<?php
// $Id: coupon.module,v 1.6.2.2.2.17 2007/03/03 13:31:10 gordon Exp $

define('ECMAIL_TYPE_COUPON', 'coupon');
define('MAILVAR_COUPON', 'ec_mail_coupon');

/**
 * Implementation of hook_help()
 */
function coupon_help($section) {
  switch ($section) {
    case 'admin/modules#description':
      return t('<b>EC:</b> Allows users to enter discount coupons/gift certificates when making a purchase.');
      break;
    
    case 'node/add/product#coupon':
      return t("Creates Gift Certificates for customers to use for later purchases.");
      break;

    case 'node/add/product/coupon':
      return t('If a value of $0.00 is nominated then users will have a form which allow the entry of the value of the Gift Certificate. If an amount is nominated then this will be to value that is added.');
      break;
  }
}

/**
 * Implementation of hook_menu()
 */
function coupon_menu($may_cache) {
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/store/coupon',
      'title' => t('coupons'),
      'callback' => 'coupon_admin_list'
    );
    $items[] = array(
      'path' => 'admin/store/coupon/list',
      'title' => t('list'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/store/coupon/create',
      'title' => t('create'),
      'callback' => 'coupon_admin_create',
      'type' => MENU_LOCAL_TASK,
      'weight' => 1,
    );
    $items[] = array(
      'path' => 'admin/store/coupon/delete',
      'title' => t('Delete coupon'),
      'callback' => 'coupon_admin_delete',
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'cart/checkout/coupon/remove',
      'title' => 'remove coupon from order',
      'callback' => 'coupon_cart_remove',
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/store/settings/coupon',
      'title' => 'coupon',
      'callback' => 'coupon_ec_settings',
      'access' => user_access('administer store'),
      'type' => MENU_NORMAL_ITEM,
    );
  }
  return $items;
}

/**
 * Implementation of hook_ec_settings()
 */
function coupon_ec_settings() {
  $form = ec_mail_selection_form_for_variable('coupon_settings_form', ECMAIL_TYPE_COUPON, t('Coupon e-mail'), MAILVAR_COUPON, t('This text will be emailed to customer after they buy a coupon.'));
  return system_settings_form('coupon_ec_settings_form', $form);
}

/**
 * Implementation of hook_productapi()
 */
function coupon_productapi(&$node, $op, $subop = null) {
  switch ($op) {
    case 'wizard_select':
      return array('coupon' => t('Gift Certificate'));
      break;

    case 'attributes':
      return array('in_stock', 'no_quantity', 'no_discounts');
      break;

    case 'adjust_price':
      if (!((float)$node->price)) {
        return $node->gc_price;
      }
      break;
      
    case 'cart form':
      if (!$node->price) {
        $form['gc_price'] = array(
          '#type' => 'price',
          '#title' => t('Amount'),
          '#default_value' => module_invoke('payment', 'format', $node->gc_price),
          '#size' => 10,
          '#maxlength' => 10,
        );

        return $form;
      }
      break;

    case 'transaction':
      if ($subop == 'load') {
        $extra['data'] = array();

        $result = db_query('SELECT * FROM {ec_coupon} WHERE created_txnid = %d AND created_vid = %d', $node->txnid, $node->vid);
        while ($coupon = db_fetch_object($result)) {
          $extra['data']['Coupon Purchased'] = _coupon_format($coupon->coupon);
          $extra['coupon'][] = $coupon;
        }
        return $extra;
      }
      break;
      
    case 'on payment completion':
      $txn = store_transaction_load($node->txnid);
      $txn->coupon = array(
        'coupon' => _coupon_create(),
        'operator' => '+',
        'operand' => $node->price,
        'created' => time(),
        'created_txnid' => $node->txnid,
        'created_vid' => $node->vid,
      );
      db_query("INSERT INTO {ec_coupon} (coupon, operator, operand, created, created_txnid, created_vid) VALUES ('%s', '%s', %f, %d, %d, %d)", $txn->coupon);

      $from = variable_get("site_mail", ini_get("sendmail_from"));
      $mail = $txn->mail;
      if (!$mail && $txn->uid && $account = user_load(array('uid' => $txn->uid))) {
        $mail = $account->mail;
      }
      if ($mail && valid_email_address($mail)) {
        ec_mail_send_mid(variable_get(MAILVAR_COUPON, 0), $mail, $txn);
      }
      break;
  }
}

function coupon_nodeapi(&$node, $op, $teaser = 0, $page = 0) {
  if ($op == 'view' && isset($node->ptype) && $node->ptype == 'coupon') {
    if (!$teaser && (!((float)$node->price))) {
      $items = cart_get_items();
  
      $form['gc'] = array(
        '#type' => 'fieldset',
        '#title' => t('Options'),
      );
      $form['gc']['gc_price'] = array(
        '#type' => 'price',
        '#title' => t('Amount'),
        '#default_value' => number_format($items[$node->nid]->gc_price, 2),
        '#size' => 10,
        '#maxlength' => 10,
        '#description' => t('How much would you like the Gift Certificate to be?'),
        '#required' => true,
      );
      $form['nid'] = array(
        '#type' => 'hidden',
        '#value' => $node->nid,
      );
      $form[] = array(
        '#type' => 'submit',
        '#value' => t('add to cart'),
      );
      $form['#method'] = 'post';
      $form['#action'] = url('cart/add/' .$node->nid, drupal_get_destination());
      $output = drupal_get_form('coupon_gc_form', $form);
      $node->body .= $output;
    }
  }
}

function coupon_gc_form_submit($form_id, $form_values) {
  if ($message = cart_add_item($form_values['nid'], NULL, array('gc_price' => $form_values['gc_price']))) {
    drupal_set_message($message);
  }
}

/**
 * Implementation of hook_checkoutapi()
 */
function coupon_checkoutapi(&$txn, $op, $arg3 = null, $arg4 = null) {
  if ($txn == 'coupon' && $op == 'review') {
    return 'coupon';
  }
  
  $output = '';
  switch ($op) {
    case 'review':
      if (is_array($txn->coupon)) {
        foreach ($txn->coupon as $key => $coupon) {
          $form['coupons'][$key] = array(
            'coupon_no' => array('#value' => _coupon_format($coupon['coupon'])),
            'discount' => array('#value' => payment_format($coupon['discount'])),
            'options' => array('#value' => l(t('remove'), "cart/checkout/coupon/remove/$key", array(), drupal_get_destination())),
          );
        }
      }
      $form['new_coupon'] = array(
        '#type' => 'textfield',
        '#title' => t('Coupon/Gift Certificate Number'),
        '#size' => 20,
        '#maxlength' => 20,
      );
      $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Add'),
      );
      return $form;
      break;

    case 'review_validate':
      $error = t('Invalid or Previously Used Coupon/Gift Certificate');

      if ($txn->new_coupon) {
        $new_coupon = str_replace('-', '', $txn->new_coupon);
        if ($txn->coupon[$new_coupon]) {
          form_set_error('new_coupon', t('Coupon/Gift Certificate has already been added to this order'));
        }
        elseif ($coupon = db_fetch_object(db_query("SELECT c.*, tc.txnid, SUM(tc.discount) as coupon_discount FROM {ec_coupon} c LEFT JOIN {ec_transaction_coupon} tc ON c.coupon = tc.coupon WHERE c.coupon = '%s' GROUP BY c.coupon, c.operator, c.operand, c.created, c.created_txnid, c.created_vid, tc.txnid", $new_coupon))) {
          if (($coupon->operator == '%' && $coupon->txnid) || ($coupon->txnid && ($coupon->operand * ($coupon->operator == '+' ? 1 : -1)) <= (float)$coupon->coupon_discount)) {
            form_set_error('new_coupon', $error);
          }
        }
        else {
          form_set_error('new_coupon', $error);
        }
      }
      break;

    case 'review_submit':
      if ($txn->new_coupon) {
        $new_coupon = str_replace('-', '', $txn->new_coupon);
        $txn->coupon[$new_coupon] = array(
          'coupon' => $new_coupon,
        );
      }
      if (is_array($txn->coupon)) {
        $total_discount = 0;
        $gross = store_transaction_calc_gross($txn);
        if (is_array($txn->misc)) {
          foreach ($txn->misc as $misc) {
            if ($misc->type == 'coupon') {
              $gross-= $misc->price;
            }
          }
        }
        
        foreach ($txn->coupon as $key => $value) {
          if ($coupon = db_fetch_object(db_query("SELECT c.*, tc.txnid, SUM(tc.discount) as coupon_discount FROM {ec_coupon} c LEFT JOIN {ec_transaction_coupon} tc ON c.coupon = tc.coupon WHERE c.coupon = '%s' GROUP BY c.coupon, c.operator, c.operand, c.created, c.created_txnid, c.created_vid, tc.txnid", str_replace('-', '', $value['coupon'])))) {
            $discount = 0;
            if ($coupon->operator == '%') {
              $points = $coupon->operand/100;
              foreach ($txn->items as $item) {
                if (function_exists('bcadd')) {
                  $discount = bcadd($discount, bcmul($item->price * $item->qty, (float)$points, 2), 2);
                }
                else {
                  $discount+= $item->price * $item->qty * $points;
                }
              }  
            }
            else {
              $discount = $coupon->operator == '+' ? $coupon->operand : $coupon->operand*-1;
              $discount_avaliable = $discount - $coupon->coupon_discount;
              if ($discount > $discount_avaliable) {
                $discount = $discount_avaliable;
              }
            }
            if ($discount+$total_discount > $gross) {
              $discount = $gross - $total_discount;
            }
            $total_discount+= $discount;
            $txn->coupon[$key]['discount'] = $discount;
          }
        }
        if ($total_discount) {
          if (($key = store_search_misc(array('type' => 'coupon'), $txn)) !== false) {
            $txn->misc[$key]->price = $total_discount*-1;
          }
          else {
            $misc = new StdClass;
            $misc->type = 'coupon';
            $misc->description = 'Discount';
            $misc->price = $total_discount*-1;
            $txn->misc[] = $misc;
          }
        }
      }
      break;
  }
}

function theme_coupon_review_form($form) {
  if ($form['coupons']) {
    $header = array(
      array('data' => t('Coupon No.')),
      array('data' => t('Discount')),
      '',
    );
    foreach (element_children($form['coupons']) as $key) {
      $rows[] = array(
        array('data' => form_render($form['coupons'][$key]['coupon_no'])),
        array('data' => form_render($form['coupons'][$key]['discount']), 'align' => 'right'),
        array('data' => form_render($form['coupons'][$key]['options'])),
      );
    }
    $output.= theme('table', $header, $rows);
  }
  $output.= '<div class="container-inline">';
  $output.= form_render($form);
  $output.= '</div>';
  return theme('box', t('Redeem Coupon/Gift Certificates'), $output);
}

/**
 * Implementation of hook_ec_transactionapi()
 */
function coupon_ec_transactionapi(&$txn, $op, $arg3 = null, $arg4 = null) {
  switch ($op) {
    case 'load':
      $result = db_query('SELECT * FROM {ec_transaction_coupon} WHERE txnid = %d', $txn->txnid);
      while ($data = db_fetch_array($result)) {
        $extra['coupon'][] = $data;
      }
      if ($extra) {
        return $extra;
      }
      break;
    case 'insert':
    case 'update':
      if ($txn->coupon) {
        foreach ($txn->coupon as $coupon) {
          if (db_result(db_query("SELECT COUNT(*) FROM {ec_transaction_coupon} WHERE txnid = %d AND coupon = '%s'", $txn->txnid, $coupon['coupon']))) {
            db_query("UPDATE {ec_transaction_coupon} SET discount = %f WHERE txnid = %d AND coupon = '%s'", $txn->txnid, (float)$coupon['discount'], $coupon['coupon']);
          }
          else {
            db_query("INSERT INTO {ec_transaction_coupon} (txnid, coupon, discount) VALUES (%d, '%s', %f)", $txn->txnid, $coupon['coupon'], (float)$coupon['discount']);
          }
        }
      }
      break;
  }
}

/**
 * Callbacks
 */
/**
 * Remove a coupon from the cart
 */
function coupon_cart_remove($coupon = false) {
  if ($coupon !== false && ($txn = ec_checkout_get_data())) {
    if ($txn->coupon[$coupon]) {
      unset($txn->coupon[$coupon]);

      $total_discount = 0;
      foreach ($txn->coupon as $coupon) {
        $total_discount+= $coupon['discount'];
      }
      if (($misc = store_search_misc(array('type' => 'coupon'), $txn)) !== false) {
        if ($total_discount) {
          $txn->misc[$misc]->price = $total_discount*-1;
        }
        else {
          unset($txn->misc[$misc]);
        }
      }
      elseif ($total_discount) {
        $misc_item = new StdClass;
        $misc_item->type = 'coupon';
        $misc_item->description = 'Discount';
        $misc_item->price = $total_discount*-1;
        $txn->misc[] = $misc_item;
      }
      ec_checkout_hide_data($txn);
    }
  }
  drupal_goto();
}

/**
 * List Coupons
 */
function coupon_admin_list($created = null, $method = 0) {
  if ($method == 2) {
    header('Content-Type: ', 'application/x-csv');
    header('Content-Disposition: attachment; filename="coupons.csv"' );
  }
  else {
    $head = array(
      array('data' => t('Coupon'), 'field' => 'coupon'),
      array('data' => t('Type of Discount')),
      array('data' => t('Discount Paid'), 'field' => 'coupon_discount'),
      array('data' => t('Discount Available')),
      array('data' => t('Created'), 'field' => 'created'),
      array('data' => t('Transaction'), 'field' => 'created_txnid'),
      array(),
    );
  }
  $sql = "SELECT c.*, SUM(tc.discount) as coupon_discount FROM {ec_coupon} c LEFT JOIN {ec_transaction_coupon} tc ON c.coupon = tc.coupon";
  if ($created) {
    $sql.= " WHERE created = $created";
  }
  $sql.= " GROUP BY c.coupon, c.operator, c.operand, c.created, c.created_txnid, c.created_vid";
  if ($method) {
    $result = db_query($sql);
  }
  else {
    $result = pager_query($sql. tablesort_sql($head), 50);
  }
  while ($coupon = db_fetch_object($result)) {
    if ($method == 2) {
      printf("\"%s\",\"%s\",%d\n\r", _coupon_format($coupon->coupon), ($coupon->operator == '%' ? "{$coupon->operand}% discount" : "\${$coupon->operator}{$coupon->operand} discount"), $coupon->created);
    }
    else {
      $rows[] = array(
        array('data' => _coupon_format($coupon->coupon)),
        array('data' => ($coupon->operator == '%' ? "{$coupon->operand}% discount" : "\${$coupon->operator}{$coupon->operand} discount")),
        array('data' => payment_format($coupon->coupon_discount), 'align' => 'right'),
        array('data' => $coupon->operator != '%' ? payment_format(($coupon->operand * ($coupon->operator == '+' ? 1 : -1)) - $coupon->coupon_discount) : '', 'align' => 'right'),
        array('data' => format_date($coupon->created, 'small')),
        array('data' => user_access('administor store') ? l($coupon->created_txnid, "store/transaction/view/{$coupon->created_txnid}") : $coupon->created_txnid),
        array('data' => !$method && !$coupon->created_txnid ? l(t('Delete'), 'admin/store/coupon/delete/'. $coupon->coupon) : ''),
      );
    }
  }
  if ($method == 2) {
    exit();
  }

  if ($method == 1) {
    foreach ($head as $key => $value) {
      unset($head[$key]['field']);
    }
  }
  
  $output.= theme('table', $head, $rows);
  if ($method == 1) {
    print $output;
    exit();
  }
  $output.= theme('pager', 50);

  return $output;
}

/**
 * Create Coupons
 */
function coupon_admin_create() {
  $form['coupon_value'] = array(
    '#type' => 'textfield',
    '#title' => t('Value of Coupons'),
    '#size' => 12,
    '#maxlength' => 12,
    '#description' => t('Enter the value of the coupons to be created. eg. 10%, a set value of 5.00'),
  );
  $form['coupon_count'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of Coupons to Create'),
    '#size' => 5,
    '#maxlength' => 10,
  );
  $form['coupon_output'] = array(
    '#type' => 'radios',
    '#title' => t('Select output method'),
    '#options' => array(t('Show on Page'), t('Printable Page'), t('CSV File')),
  );
  $form[] = array(
    '#type' => 'submit',
    '#value' => t('Create Coupons'),
  );
  return drupal_get_form('coupon_admin_create', $form);
}

function coupon_admin_create_validate($form_id, $form_values) {
  if (!$form_values['coupon_value']) {
    form_set_error('coupon_value', t('Coupon Value is a required field'));
  }
  elseif ($form_values['coupon_value'] && !preg_match('/^[+]?[\d]*([.][\d]{0,2})?[%]?$/i', $form_values['coupon_value'])) {
    form_set_error('coupon_value', t('Coupon Value is not in a valid format'));
  }

  if (!$form_values['coupon_count'] || !is_numeric($form_values['coupon_count']) || $form_values['coupon_count'] < 1) {
    form_set_error('coupon_count', t('Coupon Count is a required field and must be a positive numeric'));
  }
}

function coupon_admin_create_submit($form_id, $form_values) {
  $coupon = array(
    'created' => time()
  );
  preg_match('/^([+]?)([\d]*([.][\d]{0,2})?)([%]?)$/i', $form_values['coupon_value'], $match);
  if ($match[4] == '%') {
    $coupon['operator'] = '%';
  }
  else {
    $coupon['operator'] = $match[1] == '-' ? '-' : '+';
  }
  $coupon['operand'] = (float)$match[2];

  for ($i=0; $i<$form_values['coupon_count'];$i++) {
    $coupon['coupon'] = _coupon_create();
    db_query("INSERT INTO {ec_coupon} (coupon, operator, operand, created) VALUES ('%s', '%s', %f, %d)", $coupon['coupon'], $coupon['operator'], $coupon['operand'], $coupon['created']);
  }

  return "admin/store/coupon/{$coupon['created']}/{$form_values['coupon_output']}";
}

/**
 * Delete coupons from the database
 */
function coupon_admin_delete($cid = NULL) {
  if (!$cid || (!db_result(db_query("SELECT COUNT(*) FROM {ec_coupon} WHERE coupon = '%s'", $cid)))) {
    drupal_not_found();
    exit();
  }

  if (db_result(db_query("SELECT COUNT(*) FROM {ec_transaction_coupon} WHERE coupon = '%s'", $cid))) {
    drupal_access_denied();
  }

  $form['cid'] = array(
    '#type' => 'value',
    '#value' => $cid,
  );
  return confirm_form('coupon_admin_delete', $form, t('Do you want to delete coupon %coupon', array('%coupon' => _coupon_format($cid))), 'admin/store/coupon', t('This coupon will not longer be able to be redeemed once it has been deleted.'), t('Delete'));
}

function coupon_admin_delete_submit($form_id, $form_values) {
  db_query("DELETE FROM {ec_coupon} WHERE coupon = '%s'", $form_values['cid']);
  drupal_set_message(t('Coupon %coupon has been deleted', array('%coupon' => _coupon_format($form_values['cid']))));
  return 'admin/store/coupon';
}

/**
 * private functions
 */
function _coupon_create() {
  do {
    $num = mt_rand(1000000000, 9999999999);
    $num.= sprintf('%02d', $num%97);
  }
  while (db_result(db_query("SELECT COUNT(*) FROM {ec_coupon} WHERE coupon = '%s'", $num)));
  return $num;
}

function _coupon_format($coupon) {
  return preg_replace('/(\d{4})(\d{4})(\d{4})/', '$1-$2-$3', $coupon);
}

/**
 * Implements hook_token_list() from the token module.
 */
function coupon_token_list($type = 'all') {
  if ($type == 'all' || $type == ECMAIL_TYPE_COUPON) {
    if ($type == ECMAIL_TYPE_COUPON) {
      $tokens = token_list(STORE_TOKEN_TYPE);
    } else {
      $tokens = array();
    }
    $tokens[ECMAIL_TYPE_COUPON]['gift-cert-number']   = t('Gift certificate number.');
    $tokens[ECMAIL_TYPE_COUPON]['gift-cert-discount'] = t('Gift certificate discount amount.');
  }
  
  return $tokens;
}

/**
 * Implements hook_token_values() from the token module.
 */
function coupon_token_values($type, $object = NULL) {
  $values = FALSE;
  
  if ($type == ECMAIL_TYPE_COUPON) {
    $values = store_token_values(STORE_TOKEN_TYPE, $object);
    $values['coupon-number']   = _coupon_format($txn->coupon['coupon']);
    $values['coupon-discount'] = payment_format($txn->coupon['operand']);
  }

  return $values;
}

/**
 * Implementation of hook_mail_types() from ec_mail module.
 */
function coupon_mail_types() {
  return array(
    ECMAIL_TYPE_COUPON => t('Coupon or gift certificate delivery mail'),
  );
}

/**
 * Implementation of hook_mail_reset() from ec_mail module.
 */
function coupon_mail_reset($type) {
  $mids = array();
  if ($type == ECMAIL_TYPE_COUPON) {
    $defsub = t('Gift Certificate for %site');
    $defbody = t("Dear %billing_name\n\nHere is your gift certificate.\nTo redeem this Certificate please the following number during your next purchase to get a discount of up to %discount_amount.\n\n%coupon_number");
    $mid = ec_mail_import_old_mail('Default coupon mail', ECMAIL_TYPE_COUPON, 'coupon_email_coupon_subject', $defsub, 'coupon_email_coupon_body', $defbody);
    ec_mail_variable_change(MAILVAR_COUPON, $mid, TRUE);
  }
  return $mids;
}
