? modules/ecommerce/shippingtest.module
Index: modules/ecommerce/product/product.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ecommerce/product/product.module,v
retrieving revision 1.109
diff -u -r1.109 product.module
--- modules/ecommerce/product/product.module	12 May 2006 07:35:11 -0000	1.109
+++ modules/ecommerce/product/product.module	12 May 2006 17:12:53 -0000
@@ -224,21 +224,6 @@
       }
     }
 
-    // Handle shipping.
-    // Don't test for if it *is* 'per_product', test for if it *supports* per_product
-    if (function_exists(variable_get('shipping_method', 'none').'_shippingapi')) {
-    // we can't use module_invoke, because one module could define multiple types
-      $f = variable_get('shipping_method', 'none').'_shippingapi';
-      $per_product = $f($edit, 'per_product');
-    }
-    if ($per_product && in_array('is_shippable', (array)module_invoke($product->ptype, 'productapi', $product, 'attributes', 'is_shippable'))) {
-      if ($shipping = module_invoke(variable_get('shipping_method', 'none'), 'shippingapi', $product, 'per_product_load')) {
-        foreach ($shipping as $key => $value) {
-          $product->$key = $value;
-        }
-      }
-    }
-
     $products[$node->vid] = $product;
   }
 
@@ -296,6 +281,16 @@
     );
   }
   else {
+
+    foreach(product_get_ptypes() as $type => $description) {
+      $items[] = array(
+        'path' => 'admin/settings/content-types/product/' . $type,
+        'title' => $description,
+        'callback' => 'product_types_configure',
+        'access' => user_access('administer products'),
+        'type' => MENU_CALLBACK
+      );
+    }
     if (arg(0) == 'node' && is_numeric(arg(1)) && user_access('administer products')) {
       // Only add the product-tab for non-product pages:
       if (db_result(db_query(db_rewrite_sql("SELECT COUNT(n.nid) FROM {node} n WHERE n.nid = %d AND n.type != 'product'"), arg(1))) > 0) {
@@ -339,10 +334,41 @@
  * Implementation of hook_form_alter()
  */
 function product_form_alter($form_id, &$form) {
-  if (isset($form['type']) && $form_id == $form['type']['#value'] .'_node_form') {
-    foreach (array('ptype') as $key) {
-      $form[$key] = array('#type' => 'value', '#value' => $form['#node']->$key);
+  if (isset($form['type'])) {
+    if ($form_id == $form['type']['#value'] .'_node_form') {
+      foreach (array('ptype') as $key) {
+        $form[$key] = array('#type' => 'value', '#value' => $form['#node']->$key);
+      }
+    }
+    else if ($form_id == $form['type']['#value'] .'_node_settings') {
+      $form['product_types'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Configure product types'),
+        '#collapsible' => TRUE,
+        '#weight' => -10,
+        '#children' => product_types_configure()
+      );
+    }
+  }
+}
+
+/**
+ * Menu callback; presents each product type configuration page.
+ */
+function product_types_configure() {
+  if (arg(4)) {
+    $form = array();
+    return system_settings_form('product_type_settings', $form);
+  }
+  else {
+    $header = array(t('Type'), t('Operations'));
+
+    $rows = array();
+    foreach (product_get_ptypes() as $type => $name) {
+      $rows[] = array($name, l(t('configure'), 'admin/settings/content-types/product/'. $type));
     }
+
+    return theme('table', $header, $rows);
   }
 }
 
@@ -741,10 +767,6 @@
     }
   }
 
-  if ($edit->per_product_shipping) {
-    module_invoke(variable_get('shipping_method', 'none'), 'shippingapi', $edit, 'per_product_validate');
-  }
-
   if (!$errors['ptype']) {
     $f = $edit->ptype. '_productapi';
     if (function_exists($f)) {
@@ -769,10 +791,6 @@
     $node->is_recurring = ($node->price_interval) ? 1 : 0;
     $fields = product_fields();
 
-    /*
-    TODO: ADD SHIPPING API CALLBACKS
-    */
-
     /* Be very sure that we have a product entry to update! */
     if (db_result(db_query('SELECT COUNT(vid) FROM {ec_product} WHERE vid = %d', $node->vid))) {
       foreach ($node as $key => $value) {
@@ -784,9 +802,6 @@
       $v[] = $node->vid;
       db_query('UPDATE {ec_product} SET '. implode(', ', $q) ." WHERE vid = %d", $v);
       module_invoke($node->ptype, 'productapi', $node, 'update');
-      if ($node->per_product_shipping) {
-        module_invoke(variable_get('shipping_method', 'none'), 'shippingapi', $node, 'per_product_update');
-      }
     }
     else {
       foreach ($node as $key => $value) {
@@ -799,9 +814,6 @@
 
       db_query('INSERT INTO {ec_product} ('. implode(', ', $k) .') VALUES('. implode(', ', $s) .')', $v);
       module_invoke($node->ptype, 'productapi', $node, 'insert');
-      if ($node->per_product_shipping) {
-        module_invoke(variable_get('shipping_method', 'none'), 'shippingapi', $node, 'per_product_insert');
-      }
     }
   }
 }
Index: modules/ecommerce/shipping/shipping.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ecommerce/shipping/shipping.install,v
retrieving revision 1.3
diff -u -r1.3 shipping.install
--- modules/ecommerce/shipping/shipping.install	9 May 2006 12:23:37 -0000	1.3
+++ modules/ecommerce/shipping/shipping.install	12 May 2006 14:35:07 -0000
@@ -31,11 +31,6 @@
       db_query("INSERT INTO {ec_subtotal_shipping} VALUES ('11.00-50.00', '0.00');");
       db_query("INSERT INTO {ec_subtotal_shipping} VALUES ('50.00-10000', '0.00');");
 
-      db_query("CREATE TABLE {ec_per_product_shipping} (
-        nid int(10) unsigned NOT NULL default '0',
-        shipping_fee decimal(10,2) unsigned NOT NULL default '0.00',
-        PRIMARY KEY  (nid)
-      ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
       break;
     case 'pgsql':
       db_query("CREATE TABLE {ec_shipping_shipping} (
@@ -61,11 +56,6 @@
       db_query("INSERT INTO {ec_subtotal_shipping} VALUES ('11.00-50.00', '0.00');");
       db_query("INSERT INTO {ec_subtotal_shipping} VALUES ('50.00-10000', '0.00');");
 
-      db_query("CREATE TABLE {ec_per_product_shipping} (
-        nid integer NOT NULL default '0',
-        shipping_fee decimal(10,2) NOT NULL default '0.00',
-        PRIMARY KEY  (nid)
-      )");
       break;
   }
 }
Index: modules/ecommerce/shipping/shipping.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ecommerce/shipping/shipping.module,v
retrieving revision 1.41
diff -u -r1.41 shipping.module
--- modules/ecommerce/shipping/shipping.module	12 May 2006 07:35:11 -0000	1.41
+++ modules/ecommerce/shipping/shipping.module	12 May 2006 18:08:06 -0000
@@ -11,11 +11,9 @@
 function shipping_help($section = 'admin/help#shipping') {
   switch ($section) {
     case 'admin/modules#description':
-      return t('Enable a shipping module API for ecommerce.');
-    case 'admin/store/shipping':
-      return t("First, choose a method to calculate shipping costs, then configure the shipping details for the method selected.");
+      return t('Enable a shipping module API for ecommerce. You must also install and enable at least one shipping module to use the API.');
     case 'admin/settings/shipping':
-      return t('Shipping calculation methods are <a href="%shipping_calc_url">here</a>.', array('%shipping_calc_url' => url('admin/store/shipping')));
+      return t('Set shipping options for each product type at the <a href="%product_settings">product settings page</a>.', array('%product_settings' => url('admin/settings/content-types/product')));
     case t('Shipping email'):
       return t("Hello %first_name,\n\nWe have shipped the following item(s) from Order #%txnid, received  %order_date.\n\nItems(s) Shipped:\n%items\n%shipping_to\nQuestions about your order? Please contact us at %email.\n\nThanks for shopping at %site.  We hope to hear from you again real soon!\n\n%uri");
   }
@@ -24,22 +22,6 @@
 }
 
 /**
- * Implementation of hook_menu()
- */
-function shipping_menu($may_cache) {
-  $items = array();
-  if ($may_cache) {
-    $items[] = array('path' => 'admin/store/settings/shipping', 
-                     'title' => t('shipping'), 'callback' => 'shipping_admin', 
-                     'access' => user_access('administer store'));
-    $items[] = array('path' => 'admin/store/shipping', 
-                     'title' => t('shipping'), 'callback' => 'shipping_admin', 
-                     'access' => user_access('administer store'));
-  }
-  return $items;
-}
-
-/**
  * Implementation of hook_settings()
  */
 function shipping_settings() {
@@ -61,37 +43,74 @@
   return $form;
 }
 
+/**
+ * Implementation of hook_form_alter()
+ */
+function shipping_form_alter($form_id, &$form) {
+  // On each product type's settings page, e.g., admin/settings/content-types/product/tangible,
+  // offer shipping methods for the type.
+  if ($form_id == 'product_type_settings') {
+    $ptype = arg(4);
+    $form['shipping_methods'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Shipping methods'),
+      '#description' => t('Select the shipping methods you wish to make available for this product type.'),
+      '#weight' => -10
+    );
+    $methods = shipping_get_methods();
+    $settings = variable_get($ptype . '_methods', array());
+    $form['shipping_methods'][$ptype . '_methods'] = array(
+      '#tree' => TRUE
+    );
+    foreach ($methods as $type => $method) {
+      $options = array();
+      foreach (element_children($method) as $key) {
+        $options[$key] = $method[$key]['#title'];
+      }
+      // Read title from method.
+      $form['shipping_methods'][$ptype . '_methods'][$type] = array(
+        '#title' => $methods[$type]['#title'],
+        '#type' => 'checkboxes',
+        '#value' => $settings[$type] ? array_filter($settings[$type]) : array(),
+        '#options' => $options
+      );
+      // Read in the optional method description.
+      if ($methods[$type]['#description']) {
+        $form['shipping_methods'][$ptype . '_methods'][$type]['#description'] = $methods[$type]['#description'];
+      };
+    }
+  }
+}
+
 /********************************************************************
  * Module Functions
  ********************************************************************/
 
 /**
- * Controller. This callback is invoked via menu() when "admin/store/shipping*" is hit.
+ * Return shipping methods from all enabled shipping modules.
  */
-function shipping_admin($action = '') {
-
-  $edit = $_POST['edit'];
-  $op = $_POST["op"];
+function shipping_get_methods() {
+  return module_invoke_all('shipping_methods');
+}
 
-  switch ($op ? $op : $action) {
-    case t('Save configuration'):
-      variable_set("shipping_method", $edit["shipping_method"]);
-      drupal_set_message(t('shipping options have been saved'));
-      $output = shipping_admin_overview();
-      break;
+/**
+ * Return shipping methods settings for a product type.
+ */
+function shipping_get_ptype_methods() {
+  $settings = variable_get($ptype . '_methods', array());
+  // We filter the values because checkboxes saves unneeded zeros.
+  foreach ($settings as $type => $setting) {
+    $settings[$type] = array_filter($setting);
+  }
+  return $settings;
+}
 
-    case t('Save shipping details'):
-    
-      if (shipping_details_validate($edit)) {
-       
-        shipping_details_save($edit);
-        drupal_goto('admin/store/shipping');
-      }
-      else {
-        $output = shipping_admin_overview($edit);
-      }
-      break;
+/**
+ * Callback to send email.
+ */
+function shipping_email($action) {
 
+  switch ($action) {
     case 'send':
       drupal_set_title(t('Shipping notification'));
       $output = shipping_preview_email(arg(4), 1);
@@ -108,80 +127,11 @@
         drupal_set_message(t('Unable to send email.'), 'error');
       }
       break;
-
-    default:
-      $output = shipping_admin_overview();
   }
 
   return $output;
 }
 
-/**
- * Displays the default configuration screen for managing shipping information.
- *
- * @return string HTML
- */
-function shipping_admin_overview($edit = null) {
-  /* Grab shipping methods from other modules */
-  $method = shipping_invoke_shippingapi($edit, 'method select');
-  $radio['per_product'] = t('Shipping costs are calculated on a <strong>per product</strong> basis.');
-  foreach ($method as $key => $desc) {
-    $radio[$key] = $desc;
-  }
-  $radio['subtotal'] = t('Shipping costs are calculated based on the <strong>total cost of items</strong> in the cart.');
-  $radio["none"] = t("Do not calculate shipping costs.");
-  
-  $form['methods'] = array(
-    '#type' => 'fieldset',
-    '#title' => t("Shipping calculation methods"),
-  );
-
-  $form['methods']["shipping_method"] = array(
-    '#type' => 'radios',
-    '#title' => t('Choose one'),
-    '#default_value' => variable_get("shipping_method", "none"),
-    '#options' => $radio,
-  );
-  $form[] = array(
-    '#type' => 'submit',
-    '#value' => t("Save configuration"),
-  );
-  
-
-  $output = drupal_get_form('shipping_method', $form);
-
-  unset ($form);
-  /* goodie goodie, now let's display the form specifc to the shipping method chosen. */
-  $shipping_instance_settings = '';
-  
-  if (variable_get("shipping_method", "none") != "none") {
-    $form['details'] = array(
-      //'#type' => 'fieldset',  // This fieldset is no rendering properly. It gets shown after the table. to fix this we would need to use the #theme property
-      '#title' => t("Shipping details"),
-      '#tree' => TRUE
-      //'#theme' => 'shipping_details' // This needs to be used in order to render the table within the fieldset, however it's not working properly and needs some more work
-    );
-    $fields = module_invoke(variable_get("shipping_method", ""), "shippingapi", $edit, 'form');
-    if ($fields) {
-      if (variable_get("shipping_method", "") == "subtotal") { 
-        $output .= "<p>". t("Enter the subtotals a customer should have for a given shipping cost to be applied.  This can be a single price (e.g. 1.00, 2.99, 5.34) or a range (e.g. 1.00-3.99, 4.00-10.26). Then, enter the cost of shipping for that subtotal (e.g. .99, 5.00). If conflicting shipping rules exist, the last rule that matches will always be executed. Only hyphens, dots and numbers are allowed.") ."</p>";
-      }
-      else {
-        $output .= "<p>". t("Enter the number of items a customer should have for a given shipping cost to be applied.  This can be a single digit (e.g. 1, 2, 5) or a range (e.g. 1-3, 4-10, 5-100). Then, enter the cost of shipping for that quantity (e.g. .99, 5.00). If conflicting shipping rules exist, the last rule that matches will always be executed. Only hyphens, dots and numbers are allowed.") ."</p>";
-      }
-      $form['details'] = array_merge($form['details'], $fields);
-       
-      $form[] = array(
-        '#type' => 'submit',
-        '#value' => t("Save shipping details"),
-      );
-      $output .= drupal_get_form('shipping_details', $form);
-      //$output .= form_render($form); // This is used instead of previous line in order to use the #theme property
-    }
-  }
-  return $output;
-}
-
 function shipping_preview_email($txnid, $preview = null) {
 
   $t = store_transaction_load($txnid);
@@ -294,7 +244,7 @@
   );
 
 
-  $output .= drupal_get_form('your_form_id', $form);
+  $output .= drupal_get_form('shipping_preview_email', $form);
   return $output;
 }
 
@@ -310,352 +260,5 @@
   return $mail_sent;
 }
 
-/**
- * Run the validation routines
- */
-function shipping_details_validate(&$edit) {
-  /* We use this instead of module_invoke to avoid passing $edit by reference. */
-  $f = variable_get("shipping_method", ""). "_shippingapi";
-  if (function_exists($f)) {
-    $f($edit, 'validate');
-  }
-
-  return ((form_get_errors()) ? false : true);
-}
-
-/**
- * Save the shipping information.
- *
- * This function doesn't save any information itself. Instead it calls other
- * method save functions.
- *
- * @return string shipping_admin_overview()
- */
-function shipping_details_save($edit) {
-  module_invoke(variable_get("shipping_method", ""), "shippingapi", $edit, "save");
-  drupal_set_message('Shipping information updated.');
-}
 
-/**
- * Calculcate the shipping cost
- *
- * Invoke the methods pf the current shipping scheme to calculate shipping cost.
- *
- * @param array $item A sequential array of all items in a user's cart
- *
- * @return float The actual cost of shipping
- */
-function shipping_calculate_cost($item) {
-  return module_invoke(variable_get("shipping_method", ""), "shippingapi", $item, "calculate");
-}
 
-/**
- * The controller for the plugin API hooks. It iterates through the enabled
- * plugins and calls their *_shippingapi hook if one exists, passing it the
- * action (via $op) to execute.
- *
- * @param object $items
- * @param string $op The action to execute (e.g., validate, insert, update, delete)
- * @param string $arg Optional argument to pass along. Currently being used to
- *                    pass an array of errors during form display
- *
- * @return array Collection of output from the all *_shippingapi calls.
- */
-function shipping_invoke_shippingapi(&$items, $op, $arg = 0) {
-
-  $return = array();
-  foreach (module_list() as $name) {
-    $function = $name ."_shippingapi";
-    if (function_exists($function)) {
-      $result = $function($items, $op, $arg);
-      if (isset($result)) {
-        $return = array_merge($return, $result);
-      }
-    }
-  }
-  return $return;
-}
-
-/********************************************************************
- * Default Shipping Method Functions
- *
- *  - I wanted to have a default shipping calculation method, and this
- *    seemed like the best place to put it.
- ********************************************************************/
-
-/**
- * The Controller to create a new shipping interface.
- */
-function shipping_shippingapi(&$items, $op) {
-
-  switch ($op) {
-    case 'method select': /*      module name => desc    */
-      return array('shipping' => t('Shipping costs are calculated based on the <strong>total quantity of items</strong> in the cart.'));
-
-    case 'calculate':
-      return shipping_calculate($items);
-
-    case 'form':
-      return shipping_form($items);
-
-    case 'validate':
-      shipping_validate($items);
-    break;
-
-    case 'save':
-    
-      return shipping_save($items);
-  }
-}
-
-function shipping_calculate($items) {
-
-  $type = variable_get("shipping_method", "");
-  $pivot_element = 0;
-  $cost = 0;
-
-  if ($type == "subtotal") {
-    foreach ($items as $item) {
-      if (product_is_shippable($item->nid)) {
-        $pivot_element += $item->qty * $item->price;
-      }
-    }
-  }
-  else {
-    foreach ($items as $item) {
-      if (product_is_shippable($item->nid)) {
-        $pivot_element += $item->qty;
-      }
-    }
-  }
-
-  $function = $type. "_load";
-  $ship = $function();
-  $numset = count($ship['ship_item_slot']);
-  for ($i = 0; $i < $numset; $i++) {
-    $item       = $ship['ship_item_slot'][$i];
-    $price      = $ship['ship_price_slot'][$i];
-
-    /* Check for range match */
-    if (strstr($item, '-')) {
-      list($low, $high) = explode('-', $item);
-      if ($pivot_element >= $low and $pivot_element <= $high) {
-        $cost = $price;
-      }
-    }
-    /* Check for exact item quantity match */
-    elseif ($item == $pivot_element) {
-      $cost = $price;
-    }
-  }
-
-  return $cost;
-}
-
-function shipping_validate(&$edit) {
-  $errors = array();
-
-  if (variable_get("shipping_method", "") == "subtotal") {
-    $row_1_error = t("One of the subtotal columns contain an invalid format.");
-  }
-  else {
-    $row_1_error = t("One of the item quantities columns contain an invalid format.");
-  }
-
-  $numset = count($edit['ship_item_slot']);
-  for ($i = 0; $i < $numset; $i++) {
-
-    $item   = $edit['ship_item_slot'][$i];
-    $price  = $edit['ship_price_slot'][$i];
-
-    if ($item != '' && $price != '') {
-      if (!preg_match("/^[0-9.]+([-]?[0-9.]+)*$/", $item)) {
-        $errors['ship_item_slot'] = $row_1_error;
-      }
-
-      /* Remove the currency symbol at the beginning of the price if it exists */
-      if (substr($price, 0, 1) == variable_get('payment_symbol', '$')) {
-        $price = substr($price, count(variable_get('payment_symbol', '$')));
-        $edit['ship_price_slot'][$i] = $price;
-      }
-      $price = str_replace(',', '', $price);
-      if (!is_numeric($price)) {
-        $errors['ship_price_slot'] = t("Please enter a numeric value for the shipping cost.");
-      }
-    }
-    elseif (($item == '' && $price != '') || ($item != '' && $price == '')) {
-      $errors['ship_blank_field'] = t("You need to enter a value for both columns of a row and not just one of the fields.");
-    }
-  }
-
-  foreach ($errors as $name => $message) {
-    form_set_error($name, $message);
-  }
-  return count($errors) == 0;
-}
-
-function shipping_form($edit = null) {
-
-  if (!$edit) {
-    $edit = shipping_load();
-  }
-
-  $type = variable_get("shipping_method", "");
-  if ($type == "subtotal") { 
-    $sentance_pre = t("A subtotal of ");
-    //$help = "<p>". t("Enter the subtotals a customer should have for a given shipping cost to be applied.  This can be a single price (e.g. 1.00, 2.99, 5.34) or a range (e.g. 1.00-3.99, 4.00-10.26). Then, enter the cost of shipping for that subtotal (e.g. .99, 5.00). If conflicting shipping rules exist, the last rule that matches will always be executed. Only hyphens, dots and numbers are allowed.") ."</p>";
-  }
-  else {
-    $column_name = t("Item quantity");
-    $sentance_pre = t("A quantity of ");
-    $sentance_post = t("items");
-    //$help = "<p>". t("Enter the number of items a customer should have for a given shipping cost to be applied.  This can be a single digit (e.g. 1, 2, 5) or a range (e.g. 1-3, 4-10, 5-100). Then, enter the cost of shipping for that quantity (e.g. .99, 5.00). If conflicting shipping rules exist, the last rule that matches will always be executed. Only hyphens, dots and numbers are allowed.") ."</p>";
-  }
-
-  $header = array($column_name, t("Shipping cost"));
-  $fields = 10;
-
-  for ($i = 0; $i < $fields; $i++) {
-   
-   $form['ship_item_slot'][$i] = array(
-    '#type' => 'textfield',
-    '#value' => $edit['ship_item_slot'][$i],
-    '#size' => 35,
-    '#maxlength' => 128,
-    '#required' => false,
-    '#prefix' => $sentance_pre,
-    '#suffix' => $sentance_post
-   );
-   $form['ship_price_slot'][$i] = array(
-    '#type' => 'textfield',
-    '#value' => $edit['ship_price_slot'][$i],
-    '#size' => 35,
-    '#maxlength' => 128,
-    '#required' => false,
-    '#prefix' => t('cost'),
-    '#suffix' => t("in shipping.")
-   );
-  }
-  return $form;
-}
-
-function theme_shipping_details(&$form) {
-  for ($i = 0; $i <= 9; $i++) {
-      $row = array();
-      $row[] = form_render($form['details']['ship_item_slot'][$i]);
-      $row[] = form_render($form['details']['ship_price_slot'][$i]);
-      $rows[] = $row;
-  }
-  
-  $type = variable_get("shipping_method", "");
-  if ($type == "subtotal") {
-    $column_name = t("Subtotal");
-  }
-  else {
-    $column_name = t("Item quantity");
-  }
-  $header = array($column_name, t("Shipping cost"));
-  $output = theme('table', $header, $rows);
-  $output .= form_render($form);
-  return $output;
-}
-
-function shipping_save($edit) {
-
-  $type = variable_get("shipping_method", ""). "_shipping";
-  $numset = count($edit['details']['ship_item_slot']);
-  /* As a safeguard, don't delete the old shipping values unless we're sure we
-     got at least one update. */
-  if ($numset) {
-    db_query("DELETE FROM {ec_$type}");
-  }
-
-  for ($i = 0; $i < $numset; $i++) {
-    $item       = $edit['details']['ship_item_slot'][$i];
-    $price      = $edit['details']['ship_price_slot'][$i];
-    if ($item && $price) {
-      db_query("INSERT INTO {ec_$type} (item_slot, price_slot) VALUES ('%s', '%s')", $item, $price);
-    }
-  }
-
-  drupal_set_message(t("the shipping options have been saved"));
-}
-
-function shipping_load() {
-
-  $type = variable_get("shipping_method", ""). "_shipping";
-  $result = db_query("SELECT * FROM {ec_$type}");
-
-  while ($data = db_fetch_array($result)) {
-    $output['ship_item_slot'][] = $data['item_slot'];
-    $output['ship_price_slot'][] = $data['price_slot'];
-  }
-
-  return $output;
-}
-
-/**
- * Some young whipper snapper voodoo. I have extended the shipping module with
- * two plugins in this shipping API module.  They are both so very similar that
- * i didn't overlap code.  Kids, don't try this at home. Technically only one
- * shipping api should be in each module
- */
-function subtotal_shippingapi(&$items, $op, $arg = '') {
-  return shipping_shippingapi($items, $op, $arg);
-}
-
-function subtotal_load() {
-  return shipping_load();
-}
-
-function per_product_shippingapi(&$items, $op) {
-
-  switch ($op) {
-    case 'calculate':
-      return per_product_calculate($items);
-    case 'per_product' :
-      return TRUE;
-    case 'per_product_load':
-      return db_fetch_object(db_query('SELECT * FROM {ec_per_product_shipping} WHERE nid = %d', $items->nid));
-
-    case 'per_product_form':
-      $form['shipping_fee'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Shipping charge'),
-        '#default_value' => $items->shipping_fee,
-        '#size' => 25,
-        '#maxlength' => 50,
-        '#description' => t('Enter any shipping or handling charges for this product here.'),
-      );
-      return $form;
-
-    case 'per_product_validate':
-      if ($items->shipping_fee != NULL && !is_numeric($items->shipping_fee)) {
-        form_set_error('shipping_fee', t('You must enter a numeric value for the shipping fee.'));
-      }
-      return form_get_errors();
-
-    case 'per_product_update':
-    case 'per_product_insert':
-      return per_product_save($items);
-  }
-}
-
-function per_product_save($node) {
-  if ($node->per_product_shipping) {
-    db_query('DELETE FROM {ec_per_product_shipping} WHERE nid = %d', $node->nid);
-    db_query('INSERT INTO {ec_per_product_shipping} (nid, shipping_fee) VALUES (%d, %f)', $node->nid, $node->shipping_fee);
-  }
-}
-
-/**
- * An array of items is passed in.
- */
-function per_product_calculate($items) {
-  $shipping = 0;
-  foreach ($items as $nid => $i) {
-    $shipping += $i->qty * $i->shipping_fee;
-  }
-  return $shipping;
-}
-?>
Index: modules/ecommerce/store/store.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ecommerce/store/store.install,v
retrieving revision 1.18
diff -u -r1.18 store.install
--- modules/ecommerce/store/store.install	12 May 2006 07:35:11 -0000	1.18
+++ modules/ecommerce/store/store.install	12 May 2006 17:14:02 -0000
@@ -499,3 +499,15 @@
     return $ret;
   }
 }
+
+function store_update_22() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("DROP TABLE {ec_per_product_shipping}");
+      break;
+    case 'pgsql':
+      break;
+  }
+  return $ret;
+}
