Index: uc_node_access.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_node_access/uc_node_access.install,v
retrieving revision 1.1.4.2
diff -u -p -r1.1.4.2 uc_node_access.install
--- uc_node_access.install	6 Jan 2009 19:26:19 -0000	1.1.4.2
+++ uc_node_access.install	4 Oct 2010 21:09:53 -0000
@@ -52,6 +52,12 @@ function uc_node_access_schema() {
         'length' => 255,
         'not null' => FALSE,
       ),
+      'shippable' => array(
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'primary key' => array(
       'pfid'
@@ -174,3 +180,17 @@ function uc_node_access_update_6000() {
 
   return $ret;
 }
+
+function uc_node_access_update_6001() {
+  $ret = array();
+
+  $shippable = array(
+    'type' => 'int',
+    'size' => 'tiny',
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  db_add_field($ret, 'uc_node_access_products', 'shippable', $shippable);
+
+  return $ret;
+}
Index: uc_node_access.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_node_access/uc_node_access.module,v
retrieving revision 1.1.4.4
diff -u -p -r1.1.4.4 uc_node_access.module
--- uc_node_access.module	25 Aug 2010 15:04:54 -0000	1.1.4.4
+++ uc_node_access.module	4 Oct 2010 21:09:53 -0000
@@ -63,6 +63,35 @@ function uc_node_access_cron() {
 }
 
 /**
+ * Implementation of hook_cart_item().
+ */
+function uc_node_access_cart_item($op, &$item) {
+  switch ($op) {
+    case 'can_ship':
+      $sku = empty($item->data['model']) ? $item->model : $item->data['model'];
+      $accesses = db_query("SELECT shippable, model FROM {uc_node_access_products} as nap INNER JOIN {uc_product_features} as pf ON pf.pfid = nap.pfid WHERE nid = %d", $item->nid);
+      $match = FALSE;
+      while ($access = db_fetch_object($accesses)) {
+        if (empty($access->model) || $sku == $access->model) {
+          if ($access->shippable) {
+            // If one feature is shippable, the whole item is shippable.
+            return TRUE;
+          }
+          else {
+            // This non-shippable item could be overridden by a later feature.
+            $match = TRUE;
+          }
+        }
+      }
+      if ($match) {
+        // All matching features are not shippable.
+        return FALSE;
+      }
+      break;
+  }
+}
+
+/**
  * Implementation of hook_product_feature().
  */
 function uc_node_access_product_feature() {
@@ -118,6 +147,13 @@ function uc_node_access_feature_form($fo
     '#required' => TRUE,
   );
 
+  $form['shippable'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Shippable product'),
+    '#default_value' => $access['shippable'],
+    '#description' => t('Check if this product model/SKU is also associated with a shippable product.'),
+  );
+
   $form['delay_period'] = array(
     '#type' => 'fieldset',
     '#title' => t('Access time delay'),
@@ -196,6 +232,7 @@ function uc_node_access_feature_form_sub
     'pfid' => $form_state['values']['pfid'],
     'model' => $form_state['values']['model'],
     'access_nid' => $form_state['values']['access_nid'],
+    'shippable' => $form_state['values']['shippable'],
     'access_limit' => $form_state['values']['access_limit'],
     'delay_period' => $form_state['values']['delay_period_value'] .' '. $form_state['values']['delay_period_unit'],
     'time_period' => $form_state['values']['time_period_value'] .' '. $form_state['values']['time_period_unit'],
@@ -215,6 +252,8 @@ function uc_node_access_feature_form_sub
       break;
   }
 
+  $description .= '<br />' . ($access['shippable'] ? t('Shippable: Yes') : t('Shippable: No'));
+
   if (!empty($access['model'])) {
     $description .= '<br />'. t('Applies to SKU: @sku', array('@sku' => $access['model']));
   }
@@ -265,13 +304,13 @@ function uc_node_access_feature_settings
 
 function uc_node_access_feature_save($data) {
   // First attempt to update an existing row.
-  db_query("UPDATE {uc_node_access_products} SET model = '%s', access_nid = %d, access_limit = '%s', delay_period = '%s', time_period = '%s', end_date = '%s' WHERE pfid = %d",
-    $data['model'], $data['access_nid'], $data['access_limit'], $data['delay_period'], $data['time_period'], serialize($data['end_date']), $data['pfid']);
+  db_query("UPDATE {uc_node_access_products} SET model = '%s', access_nid = %d, access_limit = '%s', delay_period = '%s', time_period = '%s', end_date = '%s', shippable = %d WHERE pfid = %d",
+    $data['model'], $data['access_nid'], $data['access_limit'], $data['delay_period'], $data['time_period'], serialize($data['end_date']), $data['shippable'], $data['pfid']);
 
   // Otherwise insert this feature as a new row.
   if (db_affected_rows() == 0) {
-    db_query("INSERT INTO {uc_node_access_products} (pfid, model, access_nid, access_limit, delay_period, time_period, end_date) VALUES (%d, '%s', %d, '%s', '%s', '%s', '%s')",
-      $data['pfid'], $data['model'], $data['access_nid'], $data['access_limit'], $data['delay_period'], $data['time_period'], serialize($data['end_date']));
+    db_query("INSERT INTO {uc_node_access_products} (pfid, model, access_nid, access_limit, delay_period, time_period, end_date, shippable) VALUES (%d, '%s', %d, '%s', '%s', '%s', '%s', %d)",
+      $data['pfid'], $data['model'], $data['access_nid'], $data['access_limit'], $data['delay_period'], $data['time_period'], serialize($data['end_date']), $data['shippable']);
   }
 }
 
