section ? $edit->section : $_GET['section']; switch (strtoupper($section)) { case 'OVERVIEW': $form = store_transaction_overview_form($edit); break; case 'ADDRESSES': $form = store_transaction_addresses_form($edit); break; case 'ITEMS': $form = store_transaction_item_form($edit); break; default: $form = array_merge(store_transaction_overview_form($edit), store_transaction_addresses_form($edit), store_transaction_item_form($edit)); } if ($edit->uid && is_numeric($edit->uid)) { $edit->uid = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $edit->uid)); } if (!empty($edit->txnid)) { $form['txnid'] = array( '#type' => 'value', '#value' => $edit->txnid, ); $form[] = array( '#type' => 'submit', '#value' => t('Update transaction') ); $form[] = array( '#type' => 'submit', '#value' => t('Delete'), ); } else { $form[] = array( '#type' => 'submit', '#value' => t('Create new transaction'), ); } $form['section'] = array( '#type' => 'value', '#value' => $section, ); return $form; } function store_transaction_form_validate($form_id, $form_values) { store_transaction_validate($form_values); } function store_transaction_validate(&$edit) { $edit['section'] = $edit['section'] ? strtoupper($edit['section']) : 'ALL'; switch ($edit['section']) { case 'OVERVIEW': store_transaction_validate_overview($edit); break; case 'ADDRESSES': store_transaction_validate_addresses($edit); break; case 'ITEMS': store_transaction_validate_item($edit); break; default: store_transaction_validate_overview($edit); store_transaction_validate_addresses($edit); store_transaction_validate_item($edit); } store_invoke_ec_transactionapi($edit, 'validate', strtoupper($edit['section'])); return ((form_get_errors()) ? FALSE : TRUE); } function store_transaction_form_submit($form_id, $form_values) { if ($form_values['op'] == t('Delete')) { $dest = drupal_get_destination(); unset($_REQUEST['destination'], $_REQUEST['edit']['destination']); return array('admin/store/transaction/delete/'. $form_values['txnid'], $dest); } else { store_transaction_save((object)$form_values); return 'admin/store/transaction'; } } // ------------------------------------------------------------------------- // Transaction items form function store_transaction_edit_items($txnid, $nid = NULL) { if (!is_numeric($txnid) || !($t = store_transaction_load($txnid))) { return drupal_not_found(); } if (is_null($nid) || !is_numeric($nid)) { return drupal_get_form('store_transaction_add_items_form', $t); } else { $p = NULL; foreach (array_keys($t->items) as $k) { $p =& $t->items[$k]; if ($p->nid == $nid) { break; } } if (is_null($p)) { return drupal_not_found(); } return drupal_get_form('store_transaction_edit_items_form', $t, $p); } } /** * Displays the form for editing a product already attached to a transaction. * * @todo: add hooks to this form for recurring etc * * @param $t Transaction * @param $p Product * @return HTML form for editing the given product as part of the given transaction. */ function store_transaction_edit_items_form(&$t, &$p) { $form['txnid'] = array( '#type' => 'value', '#value' => $t->txnid ); $form['nid'] = array( '#type' => 'value', '#value' => $p->nid ); $form['vid'] = array( '#type' => 'value', '#value' => $p->vid ); $form['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#default_value' => $p->title, '#size' => 30, '#maxlength' => 128, ); $form['qty'] = array( '#type' => 'textfield', '#title' => t('Quantity'), '#default_value' => $p->qty, '#size' => 15, '#maxlength' => 15, ); $form['data'] = array( '#type' => 'hidden', '#value' => $p->data, ); $interval = drupal_map_assoc(range(0, 31)); $interval[0] = '--'; $unit = array(0 => t('-please choose-'), 'D' => t('Day(s)'), 'W' => t('Week(s)'), 'M' => t('Month(s)'), 'Y' => t('Year(s)')); $form[] = array('#type' => 'submit', '#value' => t('Update'), '#weight' => 2); return $form; } function store_transaction_edit_items_form_submit($form_id, &$form_values) { product_transaction_save_product((object)$form_values); // Deleting the cache store_transaction_cache($form_values['txnid'], NULL, TRUE); // Fix up Gross $t = store_transaction_load($form_values['txnid']); $t->gross = store_transaction_calc_gross($t); db_query('UPDATE {ec_transaction} SET gross = %f WHERE txnid = %d', $t->gross, $t->txnid); } function store_transaction_items($txnid) { $html = store_quicklist_header(); $header = array( array('data' => t('nid'), 'field' => 'p.nid'), array('data' => t('sku'), 'field' => 'p.sku'), array('data' => t('title'), 'field' => 'stp.title', 'sort' => 'asc'), array('data' => t('qty'), 'field' => 'stp.qty'), array('data' => t('type'), 'field' => 'p.ptype') ); if ($count = db_result(db_query('SELECT COUNT(p.nid) FROM {ec_transaction_product} as stp, {ec_product} as p WHERE stp.vid = p.vid AND stp.txnid = %d', $txnid))) { $sql = 'SELECT * FROM {ec_transaction_product} as stp, {ec_product} as p WHERE stp.vid = p.vid AND stp.txnid = %d'. tablesort_sql($header); } else { $sql = 'SELECT * FROM {ec_transaction_product} as stp WHERE stp.txnid = %d'. tablesort_sql($header); } $result = pager_query($sql, 50, 0, NULL, $txnid); $num_items = 0; while ($data = db_fetch_object($result)) { ++$num_items; $qty += $data->qty; $rows[] = array($data->nid, check_plain($data->sku), l($data->title, "node/$data->nid", array('target' => '_blank')), $data->qty, $data->ptype); } $r[] = array(array('data' => 'Unique items:', 'align' => 'right'), array('data' => "$num_items")); $r[] = array(array('data' => 'Total quantity:', 'align' => 'right'), array('data' => "$qty")); $table = theme('table', NULL, $r, array('border' => 0)); $rows[] = array(array('data' => $table, 'colspan' => 5, 'align' => 'right')); $pager = theme('pager', NULL, 50, 0); if (!empty($pager)) { $rows[] = array(array('data' => $pager, 'colspan' => 5)); } echo $html; if (!empty($rows)) { echo theme('table', $header, $rows); } else { echo '

'. t('There are no transactions to view. You can manually add transactions, however.', array('!add_transaction' => 'admin/store/transaction/add')) .'

'; } echo ''; } // ------------------------------------------------------------------------- // Transaction delete form /** * Confirm users wants to delete transaction using confirm_form(). * @param $txnid * Transaction ID of transaction to be deleted. */ function store_transaction_confirm_delete($txnid) { $form['txnid'] = array( '#type' => 'value', '#value' => $txnid, ); return confirm_form( $form, t('Are you sure you want to delete this transaction?'), 'admin/store/transaction', t('Are you sure you want to delete transaction #%txnid? This cannot be undone.', array('%txnid' => $txnid)), t('Confirm delete'), t('Cancel')); } /** * hook_submit for store_transaction_confirm_delete(). Performs delete of * transaction using store_transaction_delete(). */ function store_transaction_confirm_delete_submit($form_id, $form_values) { store_transaction_delete($form_values['txnid']); return 'admin/store/transaction'; } /** * Delete a transaction from the database and trigger ec_transactionapi. * * @param $txnid * Transaction id of the transaction to delete. */ function store_transaction_delete($txnid) { $txn = store_transaction_load($txnid); store_invoke_ec_transactionapi($txn, 'delete'); db_query('DELETE FROM {ec_transaction} WHERE txnid = %d', $txnid); // Purge the transactions cache so that the the next load won't find this // transactions that hase been loaded. store_transaction_cache($txnid, NULL, TRUE); } function store_transaction_add_items_form(&$txn) { $items = store_transaction_item_list($txn); if (empty($items)) { $items = t('No items found for the transaction'); } $form['items'] = array( '#type' => 'item', '#title' => t('Transaction items'), '#value' => $items ); $form['txnid'] = array( '#type' => 'value', '#value' => $txn->txnid ); $form['products'] = array( '#type' => 'fieldset', '#title' => t('Products'), ); $form['products']['nids'] = array( '#type' => 'textfield', '#title' => t('Product IDs'), '#default_value' => $txn->nids, '#autocomplete_path' => 'product/autocomplete/all', '#size' => 60, '#maxlength' => 128, '#description' => t('Enter a comma separated list of product ids to add to this transaction. Here is a list of all products.', array('!product_quicklist' => url('admin/store/products/quicklist'))) ); $form['products'][] = array('#type' => 'submit', '#value' => t('Add products')); return $form; } function store_transaction_item_list(&$txn) { $rows = array(); if (!empty($txn->items)) { foreach (array_keys($txn->items) as $key) { $p =& $txn->items[$key]; $rows[] = array($p->title, l(t('edit'), "admin/store/transaction/product/edit/$txn->txnid/$p->nid", array(), drupal_get_destination())); } } if (!empty($rows)) { return theme('table', array('product', 'op'), $rows); } return ''; } function store_transaction_add_items_form_validate($form_id, &$form_values) { foreach (split(', ?', $form_values['nids']) as $nid) { if (!is_numeric($nid) || !db_result(db_query('SELECT nid FROM {ec_product} WHERE nid = %d', $nid))) { form_set_error('nids', t('Invalid list of product IDs')); break; } } } function store_transaction_add_items_form_submit($form_id, &$form_values) { $form_values['nids'] = str_replace(' ', '', $form_values['nids']); store_transaction_save_nids($form_values); } // ------------------------------------------------------------------------- // e-Commerce search hooks (see ec_common.manage.inc) /** * Implementation of hook_ec_search_init() * (called from ec_common.manage.inc) */ function store_transaction_ec_search_init(&$query) { $query->ensure_table('ec_transaction', 'st'); $query->add_select('st.txnid'); $query->add_select('st.*'); } /** * Implementation of hook_ec_search() * (Called from ec_common.manage.inc) */ function store_ec_search($search_id, &$query, &$filter, &$details) { switch ($search_id) { case 'store_transaction': switch ($filter['name']) { case 'text': $query->ensure_table('ec_transaction_product', 'stp', 'INNER', 'st.txnid = stp.txnid'); $query->ensure_table('node', 'n', 'LEFT', 'stp.vid = n.vid'); $query->ensure_table('node_revisions', 'r', 'LEFT', 'stp.vid = r.vid'); $query->add_where("(n.title LIKE '%%{$filter['data'][0]}%%' OR r.body LIKE '%%{$filter['data'][0]}%%')"); $details[] = ec_search_detail(t('Text'), $filter); break; case 'txnid': $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'st.txnid')); $details[] = ec_search_detail(t('Transaction id'), $filter); break; case 'nid': $query->ensure_table('ec_transaction_product', 'stp', 'INNER', 'st.txnid = stp.txnid'); $query->ensure_table('ec_product', 'p', 'INNER', 'stp.vid = p.vid'); $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'p.nid')); $details[] = ec_search_detail(t('Product id'), $filter); break; case 'nid_expires': $query->ensure_table('ec_transaction_product', 'stp', 'INNER', 'st.txnid = stp.txnid'); $query->ensure_table('ec_product', 'p', 'INNER', 'stp.vid = p.vid'); $mod = array(); foreach ($filter['data'] as $key => $value) { if ($key !== 'op') { $mod[$key] = format_date(strtotime($value), 'small'); } } $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'stp.expires', 'strtotime')); $details[] = ec_search_detail(t('Product expires'), $filter, $mod); break; case 'date': $mod = array(); foreach ($filter['data'] as $key => $value) { if ($key !== 'op') { $mod[$key] = format_date(strtotime($value), 'small'); } } $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'st.created', 'strtotime')); $details[] = ec_search_detail(t('Date'), $filter, $mod); break; case 'duedate': $mod = array(); foreach ($filter['data'] as $key => $value) { if ($key !== 'op') { $mod[$key] = format_date(strtotime($value), 'small'); } } $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'st.duedate', 'strtotime')); $query->add_where('AND st.duedate != 0'); $details[] = ec_search_detail(t('Date Due'), $filter, $mod); break; case 'gross': $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'st.gross')); $details[] = ec_search_detail(t('Cost'), $filter); break; case 'allocation': $mod = array(); foreach ($filter['data'] as $key => $value) { $value = ($key !== 'op') ? transaction_get_allocation($value) : $value; $mod[$key] = $value; } $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'st.allocation')); $details[] = ec_search_detail(t('Allocation'), $filter, $mod); break; case 'workflow': $mod = array(); foreach ($filter['data'] as $key => $value) { $value = ($key !== 'op') ? transaction_get_workflow($value) : $value; $mod[$key] = $value; } $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'st.workflow')); $details[] = ec_search_detail(t('Workflow'), $filter, $mod); break; case 'ptype': $mod = array_intersect_key(product_ptypes_get('names'), array_flip($filter['data'])); sort($mod); $query->ensure_table('ec_transaction_product', 'stp', 'INNER', 'st.txnid = stp.txnid'); $query->ensure_table('ec_product', 'p', 'INNER', 'stp.vid = p.vid'); $query->add_where(ec_search_operator($filter['data'], $filter['op'], 'p.ptype')); $details[] = ec_search_detail(t('Product type'), $filter, $mod); break; } break; } } /** * Implementation of hook_ec_search_format_header() * (Called from ec_common.manage.inc) */ function store_ec_search_format_header($search_id, $criteria, $query, &$header) { if ($search_id == 'store_transaction') { $header['txnid'] = array( 'data' => t('ID'), 'field' => 'st.txnid', 'sort' => 'desc', 'weight' => -10, ); $header['workflow'] = array( 'data' => t('Workflow'), 'field' => 'st.workflow', 'weight' => 2, ); $header['gross'] = array( 'data' => t('Total'), 'field' => 'st.gross', 'weight' => 3, ); $header['created'] = array( 'data' => t('Created'), 'field' => 'st.created', 'weight' => 5, ); $header['changed'] = array( 'data' => t('Changed'), 'field' => 'st.changed', 'weight' => 6, ); $header['datedue'] = array( 'data' => t('Due date'), 'field' => 'st.duedate', 'weight' => 7, ); $header['items'] = array( 'data' => t('Items ordered'), 'weight' => 98, ); } $header['op'] = array( 'data' => t('Operations'), 'weight' => 99, ); } /** * Implementation of hook_ec_search_format_row() * (Called from ec_common.manage.inc) */ function store_ec_search_format_row($search_id, $criteria, $query, $header, &$row, $data) { if (isset($data->txnid)) { $row[0]['txnid'] = array( 'data' => $data['txnid'], 'align' => 'right', ); } if (isset($header['ecid'])) { if (!isset($row[0]['ecid'])) { $row[0]['ecid'] = array('data' => array()); } if ($search_id == 'store_transaction') { if ($billing_address = db_fetch_object(db_query('SELECT * FROM {ec_transaction_address} WHERE txnid = %d AND type = "billing"', $data['txnid']))) { if ($billing_address->firstname || $billing_address->lastname) { $name = $billing_address->firstname .' '. $billing_address->lastname; $name = l($name, 'admin/store/transaction/edit/'. $data['txnid'], array(), 'section=addresses&'. drupal_get_destination()); } else { $name = $billing_address->fullname; $name = l($name, 'admin/store/transaction/edit/'. $data['txnid'], array(), 'section=addresses&'. drupal_get_destination()); } } $row[0]['ecid']['data']['address'] = array( '#value' => $name, ); $row[0]['ecid']['nowrap'] = 'nowrap'; } $actions = array( 'print_invoice' => l(t('print invoice'), "admin/store/transaction/print/{$data['txnid']}", array(), ($data->$col > 1 ? NULL : 'wf=2')), 'ship_notify' => l(t('shipping notify'), "admin/store/transaction/shipping/{$data['txnid']}", array(), 'wf=3&'. drupal_get_destination()), 'ask_customer' => l(t('ask customer'), "admin/store/transaction/ask/{$data['txnid']}", array(), 'wf=4&'. drupal_get_destination()), 'cancel_transaction' => l(t('cancel transaction'), "admin/store/transaction/cancel/{$data['txnid']}", array(), 'wf=5&'. drupal_get_destination()) ); $row[0]['workflow']['data']['wf'] = array( '#type' => 'fieldset', '#title' => transaction_get_workflow($data['workflow']), '#collapsible' => TRUE, '#collapsed' => TRUE, 'actions' => array( '#value' => theme('item_list', $actions), ), ); $row[0]['gross']['data'] = array( '#value' => format_currency($data['gross']), ); $row[0]['gross']['align'] = 'right'; $row[0]['created']['data'] = array( '#value' => format_date($data['created'], 'small'), ); $row[0]['changed']['data'] = array( '#value' => format_date($data['changed'], 'small'), ); $row[0]['datedue']['data'] = array( '#value' => $data['duedate'] ? format_date($data['duedate'], 'small') : '', ); $items = db_result(db_query('SELECT SUM(qty) FROM {ec_transaction_product} WHERE txnid = %d', $data['txnid'])); $row[0]['items']['data'] = array( '#value' => l(format_plural($items, '1 item', '@count items'), 'admin/store/transaction/product/edit/'. $data['txnid'], array('onclick' => 'window.open(this.href, \'items_ordered\', \'width=480,height=480,scrollbars=yes,status=yes\'); return FALSE')), ); $links = module_invoke_all('link', $search_id, (object)$data); $row[0]['op']['data'] = array( '#value' => theme('links', $links), ); } } // ------------------------------------------------------------------------- // eC Mail /** * Implementation of hook_mail_reset() from ec_mail module. */ function store_mail_reset($type) { $mids = array(); $mid = NULL; $var = NULL; switch ($type) { case ECMAIL_TYPE_CUSTOMER_INVOICE: $defsub = t('Your %site order'); $defbody = t("Dear %billing_name,\n\nThanks for your recent purchase from %site. This message includes important information about your order. Please take a moment to read it closely, and be sure to save a copy for future reference.\n\n********************************\nBilling and Shipping Information\n********************************\n%user_data\n********************************\nOrder Details\n********************************\n%txn_items\nQuestions about your order? Please contact us at %email\n\n********************************\nShipping Instructions\n********************************\nWe will notify you by email as soon as your order ships.\n\nThanks for shopping at %site. We hope to hear from you again real soon!\n\n%uri"); $mid = ec_mail_import_old_mail(t('Default customer invoice'), $type, 'store_email_customer_invoice_subject', $defsub, 'store_email_customer_invoice_body', $defbody); $var = MAILVAR_CUSTOMER_INVOICE; break; case ECMAIL_TYPE_PROCESSING_ERROR: $defsub = t('Purchase problem, %site'); $defbody = t("Dear Customer\n\nIt seems there was a problem while processing your order (%txnid). Please contact us at %email for further details.\n\nRegards,\n%site team\n%uri"); $mid = ec_mail_import_old_mail(t('Default processing error'), $type, 'store_email_processing_error_subject', $defsub, 'store_email_processing_error_body', $defbody); $var = MAILVAR_PROCESSING_ERROR; break; case ECMAIL_TYPE_CANCEL_TXN: $defsub = t('Your %site order has been canceled'); $defbody = t("Dear %billing_name,\n\nYour order (%txnid) has been canceled. Please contact us at %email for further details.\n\nRegards,\n%site team\n%uri"); $mid = ec_mail_import_old_mail(t('Default order cancellation notice'), $type, 'store_email_cancel_transaction_subject', $defsub, 'store_email_cancel_transaction_body', $defbody); $var = MAILVAR_CANCEL_TXN; break; case ECMAIL_TYPE_ASK_CUSTOMER: $defsub = t('Questions regarding your order from %site'); $defbody = t("Dear %billing_name,\n\nWe have some questions regarding your order from %site.\n\nRegards,\n%site team\n%uri"); $mid = ec_mail_import_old_mail(t('Default query to customer'), $type, 'store_email_ask_customer_template_subject', $defsub, 'store_email_ask_customer_template_body', $defbody); $var = MAILVAR_ASK_CUSTOMER; break; } if (!empty($var)) { ec_mail_variable_change($var, $mid, TRUE); } if (!empty($mid)) { $mids[] = $mid; } return $mids; } /** * Send an invoice email. * @param $txn * Transaction to send email based on. * @param $preview * Boolean, this toggles whether the user wants to see a preview. */ function store_send_invoice_email($txn, $preview = NULL) { if ($txn->mail && valid_email_address($txn->mail)) { $to = $txn->mail; } else { $to = ec_customer_get_email($txn->ecid); } $mid = variable_get(MAILVAR_CUSTOMER_INVOICE, 0); if (!empty($preview)) { return ec_mail_preview($mid, $to, $txn); } elseif (!empty($to) && valid_email_address($to)) { return ec_mail_send_mid($mid, $to, $txn); } else { return FALSE; } } function store_send_error_email($txnid, $preview = NULL) { $txn = store_transaction_load($txnid); if (!empty($txn->mail) && valid_email_address($txn->mail)) { $to = $txn->mail; } else { $to = ec_customer_get_email($txn->ecid); } $mid = variable_get(MAILVAR_PROCESSING_ERROR, 0); if (!empty($preview)) { return ec_mail_preview($mid, $to, $txn); } elseif (!empty($to) && valid_email_address($to)) { return ec_mail_send_mid($mid, $to, $txn); } else { return FALSE; } } /** * Ask customer question by mail workflow page. * @todo: this could be moved completely into a menu entry. */ function store_transaction_ask_customer() { return drupal_get_form('store_transaction_mail_form', arg(4), t('Ask customer a question'), MAILVAR_ASK_CUSTOMER); } /** * FIXME: Preview is not working. * Displays a mail form for the given mail variable and allows the user to preview * the mail with tokens substituted. Only use this function for mails that * populate tokens through a transaction object. * * @param $txnid * Transaction ID. * @param $pagetitle * Title to set for the page using drupal_set_title(). * @param $variable * Variable name for the value of the mail ID. * @param $force_wf * Forces the workflow to be changed if the mail is sent. Only works if $_GET['wf'] * contains a workflow value. Default is FALSE. * @param $send_optional * TRUE if the mail sending is optional. Default is FALSE. */ function store_transaction_mail_form($txnid, $pagetitle, $variable, $force_wf = FALSE, $send_optional = FALSE) { $txn = store_transaction_load($txnid); if (!empty($txn->mail) && valid_email_address($txn->mail)) { $to = $txn->mail; } else { $to = ec_customer_get_email($txn->customer); } $form = ec_mail_send_varmail_form($variable, $to, $pagetitle, $txn); $form['txnid'] = array( '#type' => 'value', '#value' => $txn->txnid, ); if (!empty($send_optional)) { unset($form['perform_send']); $form['perform_send'] = array( '#type' => 'checkbox', '#title' => t('Notify customer'), '#description' => t('Check here if you want a mail notification sent to the customer.'), '#default_value' => FALSE, ); } if (($workflow = $_GET['wf']) && transaction_valid_workflow($workflow)) { if (empty($force_wf)) { $form['change_workflow'] = array( '#type' => 'checkbox', '#title' => t('Change Workflow'), '#description' => t('Check here if you want to change the transaction workflow to %new_workflow.', array('%new_workflow' => transaction_get_workflow($workflow))), '#default_value' => TRUE, ); } else { // we're forcing the workflow, so we still need to set the change_workflow value. $form['change_workflow'] = array('#type' => 'value', '#value' => TRUE); } $form['wf'] = array('#type' => 'value', '#value' => $workflow); } return $form; } function store_transaction_mail_form_submit($form_id, &$form_values) { if (!empty($form_values['perform_send'])) { drupal_set_message(t('The mail has been accepted for delivery to the customer.')); } if (!empty($form_values['change_workflow']) && is_numeric($form_values['wf'])) { $txn = new StdClass; $txn->txnid = $form_values['txnid']; $txn->workflow = $form_values['wf']; store_transaction_save($txn); drupal_set_message(t('The transaction workflow has been updated.')); } }