<?php
// $Id: uc_followup.module,v 1.1.2.1 2010/06/30 00:19:49 neochief Exp $

define('DEFAULT_FOLLOWUP_SEND_LIMIT', 100);
define('DEFAULT_FOLLOWUP_AUTO_SEND', TRUE);
define('DEFAULT_FOLLOWUP_BCC', '');

// constants for integration with recurring
define('FOLLOWUP_RECURRING_BEFORE_EXPIRATION', 1);
define('FOLLOWUP_RECURRING_AFTER_SUCCESSFUL_REBILL', 2);
define('FOLLOWUP_RECURRING_AFTER_UNSUCCESSFULL_CHARGE', 3);
define('FOLLOWUP_RECURRING_AFTER_EXPIRATION', 4);

/**
 * @file
 * UC Follow-up allows to automatically send e-mails to customers on different stages of ordering.
 */

/**
 * Implementation of hook_menu().
 */
function uc_followup_menu() {
  $items['admin/store/follow-up'] = array(
    'title' => 'Follow-ups',
    'page callback' => 'uc_followup_list',
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  $items['admin/store/follow-up/list'] = array(
    'title' => 'Follow-ups',
    'type' => MENU_DEFAULT_FOLLOWUP_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/store/follow-up/add'] = array(
    'title' => 'Add follow-up',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('uc_followup_form'),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/store/follow-up/edit/%uc_followup'] = array(
    'title' => 'Edit follow-up',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('uc_followup_form', 4),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  $items['admin/store/follow-up/delete/%uc_followup'] = array(
    'title' => 'Delete follow-up',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('uc_followup_delete_confirm', 4),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  $items['admin/store/follow-up/settings'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('uc_followup_settings'),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/store/orders/%uc_order/follow-up'] = array(
    'title' => 'Follow-up the customer',
    'page callback' => 'uc_followup_customer',
    'page arguments' => array(3),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  $items['admin/store/orders/%uc_order/follow-up/send/%uc_followup'] = array(
    'title' => 'Preview & send',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('uc_followup_send', 3, 6),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  $items['admin/store/orders/%uc_order/follow-up/details/%'] = array(
    'title' => 'Sent follow-up details',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('uc_followup_send', 3, '', 6),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  $items['admin/store/orders/%uc_order/follow-up/ahah_preview/%uc_followup'] = array(
    'title' => 'Preview & send',
    'page callback' => 'uc_followup_send_preview',
    'page arguments' => array(3, 6),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  $items['admin/store/orders/%uc_order/follow-up/skip/%uc_followup'] = array(
    'title' => 'Skip follow-up for this order?',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('uc_followup_skip_confirm', 3, 6),
    'access arguments' => array('administer order workflow'),
    'file' => 'uc_followup.admin.inc',
  );
  return $items;
}

function uc_followup_load($followup_id) {
  return db_fetch_array(db_query('SELECT * FROM {uc_followup} WHERE followup_id = %d', $followup_id));
}

function uc_followup_sent_details($follow_id) {
  return db_fetch_array(db_query('SELECT * FROM {uc_followup_sent} WHERE follow_id = %d', $follow_id));
}

/**
 * Implementation of hook_order_actions().
 */
function uc_followup_order_actions($order, $icon_html = FALSE) {
  drupal_add_js(drupal_get_path('module', 'uc_followup') . '/uc_followup.js');
  drupal_add_css(drupal_get_path('module', 'uc_followup') . '/uc_followup.css');
  if (user_access('administer order workflow')) {
    $result = db_query('SELECT fu.order_status, COUNT(fus.date) as "sent", COUNT(fu.followup_id) as "total", (COUNT(fu.followup_id) - COUNT(fus.date)) as "pending"  FROM {uc_followup} fu LEFT JOIN (SELECT * FROM {uc_followup_sent} WHERE order_id = %s GROUP BY followup_id ORDER BY date DESC) fus ON fu.followup_id = fus.followup_id WHERE fu.order_status = "%s" OR fus.date IS NOT NULL GROUP BY fu.order_status ORDER BY fu.status DESC', $order->order_id, $order->order_status);
    $alt = array();
    while ($data = db_fetch_array($result)) {
      $folowups[$data['order_status']] = $data;
      $state = uc_order_status_data($data['order_status'], 'title');
      $alt[$data['order_status']] = t('%status: pending(@pending) | sent(@sent)', array('%status' => $state, '@pending' => $data['pending'], '@sent' => $data['sent']));
    }
    array_unshift($alt, '<b>'. $alt[$order->order_status] .'</b>');
    unset($alt[$order->order_status]);
    $alt = '<h4>'. t('Folow-up summary') .'</h4>'. implode('<br/>', $alt);

    $actions[] = array(
      'name' => t('Contact customer'),
      'url' => 'admin/store/orders/'. $order->order_id .'/follow-up',
      'icon' => '<img src="'. url(drupal_get_path('module', 'uc_followup') .'/images/email'. ($folowups[$order->order_status]['pending'] ? ($folowups[$order->order_status]['sent'] ? '-some' : '-active') : '') .'.png') .'" class="tooltip" alt="'. $alt .'" />',
    );
  }
  return $actions;
}

/**
 * Implementation of hook_mail().
 */
function uc_followup_mail($key, &$message, $params) {
  $message['subject'] = $params['subject'];
  $message['body'] = wordwrap($params['body']);
  if (variable_get('uc_followup_bcc', DEFAULT_FOLLOWUP_BCC)) {
    $message['headers']['Bcc'] = variable_get('uc_followup_bcc', DEFAULT_FOLLOWUP_BCC);
  }
}

/**
 * Implementation of hook_cron().
 */
function uc_followup_cron() {
 if (variable_get('uc_followup_auto_send', DEFAULT_FOLLOWUP_AUTO_SEND)) {
    $follow_ups = db_query('SELECT * FROM {uc_followup} fu WHERE fu.status = 1');
    $sent_mails = 0;
    while ($follow_up = db_fetch_object($follow_ups)) {
      if ($follow_up->is_recurring) {
        $join = '';

        // Selecting conditions for recurring follow-ups.
        switch ($follow_up->is_recurring) {

          // Before expiration/rebill attempt.
          case FOLLOWUP_RECURRING_BEFORE_EXPIRATION : $where = '(fus.date IS NULL AND (ru.next_charge - %d * 3600 < '.time().')) AND (ru.remaining_intervals <> 0) '; break;

          // After successful rebill. Date greater that current date + hours
          case FOLLOWUP_RECURRING_AFTER_SUCCESSFUL_REBILL : {
            $where = '(fus.date IS NULL AND (coalesce(oac.created, ru.created) + %d * 3600 < '.time().')) AND (ru.remaining_intervals <> 0) ';
            break;
          }

          // After unsuccessfull charge, but before expiration.
          case FOLLOWUP_RECURRING_AFTER_UNSUCCESSFULL_CHARGE : {
            $where = '(fus.date IS NULL AND ((ru.next_charge - coalesce(re.time_to_extend, 0)) + %d * 3600 > '. time().')) AND (ru.remaining_intervals <> 0) AND (ru.attempts > 0) ';
            $join = ' LEFT JOIN {uc_recurring_extensions} re on ru.attempts - 1 = re.rebill_attempt ';
            break;
          }

          // After expiration.
          case FOLLOWUP_RECURRING_AFTER_EXPIRATION : $where = '(fus.date IS NULL AND (ru.next_charge + %d * 3600 < '. time().')) AND (ru.remaining_intervals = 0)'; break;
        }
        $result = db_query('
        SELECT fus.date, fus.manual, fus.email, sent_count, coalesce(oac.max_order_id, o.order_id) order_id
          FROM {uc_orders} o
          INNER JOIN {uc_recurring_users} ru on ru.order_id = o.order_id
          LEFT JOIN (select max(created) created, max(order_id) max_order_id, max(message) message FROM {uc_order_admin_comments} WHERE message like \'Order created as a recurring fee for order %\'  group by message) oac ON  (CONCAT(\'Order created as a recurring fee for order <a href="/admin/store/orders/\', ru.order_id, \'">\', ru.order_id, \'</a>.\') = oac.message)
           '. $join .'
          LEFT JOIN (
            SELECT *, COUNT(order_id) as "sent_count"
              FROM {uc_followup_sent}
              GROUP BY followup_id, order_id
              ORDER BY date DESC
          ) fus ON ((fus.order_id = coalesce(oac.max_order_id, o.order_id)))
          WHERE '.$where.'

        ', $follow_up->hours_recurring);
      }
      else {
        // If not recurring, then parser is based on order state.
        $result = db_query('
          SELECT o.order_id, fus.date, fus.manual, fus.email, sent_count
          FROM {uc_orders} o
          LEFT JOIN (
            SELECT *, COUNT(order_id) as "sent_count"
              FROM {uc_followup_sent}
              GROUP BY followup_id, order_id
              ORDER BY date DESC
            ) fus ON fus.order_id = o.order_id
          WHERE
            o.order_status = "%s" AND
            /* If date is null, then no messages was previously sent, checking if order modified date is less, than in follow-up */
            ((fus.date IS NULL AND (o.modified + %d * 3600 < .'time().')) OR
            (
              /* If need to send sequence of follow-ups, start sending notifications after (and each) "repeat_after" */
              /* but stop after "repeat_max" times (or never if it is equal to zero). */
              (%d > 0 AND (fus.date + %d * 3600 < UNIX_TIMESTAMP())) AND
              (%d = 0 OR %d < sent_count)
            ))
          GROUP BY fus.followup_id, fus.order_id
        ', $follow_up->order_status, $follow_up->hours_past, $follow_up->repeat_after, $follow_up->repeat_after,
           $follow_up->repeat_max, $follow_up->repeat_max);
      }

      while (($pending = db_fetch_array($result)) && ($sent_mails < variable_get('uc_followup_send_limit', DEFAULT_FOLLOWUP_SEND_LIMIT))) {
        $order = uc_order_load($pending['order_id']);
        $replacements = uc_followup_get_token_replacements($order);

        // Apply token replacements to from and recipient e-mail addressses.
        $pending['sender'] = token_replace_multiple($follow_up->sender, $replacements);
        $pending['subject'] = token_replace_multiple($follow_up->subject, $replacements);
        $pending['body'] = token_replace_multiple($follow_up->body, $replacements);
        $pending['email'] = token_replace_multiple('[order-email]', $replacements);

        // Send message
        if (valid_email_address($pending['email'])) {
          $sent = drupal_mail('uc_followup', '', $pending['email'], '', $pending, empty($pending['sender']) ? uc_store_email_from() : $pending['sender']);
          if ($sent['result']) {
            $pending['date'] = time();
            $pending['manual'] = FALSE;
            drupal_write_record('uc_followup_sent', $pending);
            if ($sent_mails > variable_get('uc_followup_send_limit', DEFAULT_FOLLOWUP_SEND_LIMIT)) {
              return;
            } else {
              $sent_mails++;
            };
          }
        }
      }
    }
  }
}

function uc_followup_get_token_replacements($order) {
  $account = user_load(array('uid' => $order->uid));
  $replacements = array(
    'global' => NULL,
    'order' => $order,
    'user' => $account,
  );
  return $replacements;
}
