diff -r 9066cf106c76 -r a2390463299f commerce_price_table.install
--- a/commerce_price_table.install        Fri Dec 28 15:17:06 2012 +0100
+++ b/commerce_price_table.install        Fri Dec 28 16:57:21 2012 +0100
@@ -25,12 +25,6 @@
           'not null' => TRUE,
           'default' => 0,
         ),
-        'max_qty' => array(
-          'description' => 'The maximum quantity for this amount.',
-          'type' => 'int',
-          'not null' => TRUE,
-          'default' => 0,
-        ),
         'data' => array(
           'description' => 'A serialized array of additional price data.',
           'type' => 'text',
diff -r 9066cf106c76 -r a2390463299f commerce_price_table.module
--- a/commerce_price_table.module Fri Dec 28 15:17:06 2012 +0100
+++ b/commerce_price_table.module Fri Dec 28 16:57:21 2012 +0100
@@ -94,6 +94,13 @@
   $element['#attached']['css'][] = drupal_get_path('module', 'commerce_price_table') . '/theme/commerce_price_table.css';
 
   if ($instance['widget']['type'] == 'commerce_price_table_multiple') {
+    $element['min_qty'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Min Qty'),
+      '#description' => t('Minimum quantity for the price range.'),
+      '#default_value' => isset($items[$delta]['min_qty']) ? $items[$delta]['min_qty'] : 0,
+      '#size' => 10,
+    );
     $element['amount'] = array(
       '#type' => 'textfield',
       '#title' => $element['#title'],
@@ -106,20 +113,6 @@
       '#type' => 'value',
       '#default_value' => $default_currency['code'],
     );
-    $element['min_qty'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Min Qty'),
-      '#description' => t('Minimum quantity for the price range.'),
-      '#default_value' => isset($items[$delta]['min_qty']) ? $items[$delta]['min_qty'] : 0,
-      '#size' => 10,
-    );
-    $element['max_qty'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Max Qty'),
-      '#description' => t('Maximum quantity for the price range. Use "-1" for unlimited quantity.'),
-      '#default_value' => isset($items[$delta]['max_qty']) ? $items[$delta]['max_qty'] : 0,
-      '#size' => 10,
-    );
   }
 
   $element['data'] = array(
@@ -163,9 +156,6 @@
     if (empty($item['min_qty'])) {
       $items[$delta]['min_qty'] = 0;
     }
-    if (empty($item['max_qty'])) {
-      $items[$delta]['max_qty'] = 0;
-    }
   }
 }
 
@@ -192,6 +182,7 @@
  */
 function commerce_price_table_field_validate($entity_type, $entity, $field, $instance, $langcode, &$items, &$errors) {
   // Ensure only numeric values are entered in price fields.
+  $quantities = array();
   foreach ($items as $delta => $item) {
     if (!empty($item['amount']) && !is_numeric($item['amount'])) {
       $errors[$field['field_name']][$langcode][$delta][] = array(
@@ -200,14 +191,30 @@
       );
     }
 
-    if ($item['max_qty'] < $item['min_qty'] && $item['max_qty'] <> -1) {
+    if ($item['min_qty'] < 0) {
       $errors[$field['field_name']][$langcode][$delta][] = array(
         'error' => 'price_table_quantity',
-        'message' => t('%name: Max quantity needs to be higher than min quantity.', array('%name' => check_plain($instance['label']))),
+        'message' => t('%name: Min quantity must be positive or 0.', array('%name' => check_plain($instance['label']))),
       );
     }
 
-    // @TODO Add extra validations, as no repeating qty and always force to have quantity for 1?.
+    if ($item['amount'] != '') {
+      if (isset($quantities[(int) $item['min_qty']])) {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'price_table_quantity',
+            'message' => t('%name: Min quantity must be unique.', array('%name' => check_plain($instance['label']))),
+        );
+      } else {
+        $quantities[(int) $item['min_qty']] = 1;
+      }
+    }
+  }
+
+  if (!isset($quantities[0])) {
+    $errors[$field['field_name']][$langcode][0][] = array(
+      'error' => 'price_table_quantity',
+      'message' => t('%name: There has to be at least one entry with min quantity = 0.', array('%name' => check_plain($instance['label']))),
+    );
   }
 }
 
@@ -348,13 +355,6 @@
       'getter callback' => 'entity_property_verbatim_get',
       'setter callback' => 'entity_property_verbatim_set',
     ),
-    'max_qty' => array(
-      'label' => t('Max Qty'),
-      'description' => !empty($name) ? t('Max quantity value of field %name', array('%name' => $name)) : '',
-      'type' => 'integer',
-      'getter callback' => 'entity_property_verbatim_get',
-      'setter callback' => 'entity_property_verbatim_set',
-    ),
     'data' => array(
       'label' => t('Data'),
       'description' => !empty($name) ? t('Data array of field %name', array('%name' => $name)) : '',
@@ -383,12 +383,13 @@
   $element = array();
 
   if ($display['type'] == 'commerce_multiprice_default' && !empty($items)) {
+    uasort($items, 'commerce_price_table_sort_by_qty');
     $header = array(isset($display['settings']['quantity_label']) ? $display['settings']['quantity_label'] : t('Quantity'));
     $row = array(isset($display['settings']['price_label']) ? $display['settings']['price_label'] : t('Price'));
     if ($entity_type == 'commerce_product') {
       foreach ($items as $delta => $item) {
-        if (isset($item['min_qty']) && $item['max_qty'] && $item['amount']) {
-          $header[] = commerce_price_table_display_quantity_headers($item);
+        if (isset($item['min_qty']) && $item['amount']) {
+          $header[] = commerce_price_table_display_quantity_headers($item, @$items[$delta + 1]);
 
           $line_item = commerce_product_line_item_new($entity, $item['min_qty']);
           $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
@@ -420,8 +421,8 @@
     else {
       // Not a product. We're dealing with exotic stuff here.
       foreach ($items as $delta => $item) {
-        if (isset($item['min_qty']) && $item['max_qty'] && $item['amount']) {
-          $header[] = commerce_price_table_display_quantity_headers($item);
+        if (isset($item['min_qty']) && $item['amount']) {
+          $header[] = commerce_price_table_display_quantity_headers($item, @$items[$delta + 1]);
           $row[] = array('data' => commerce_currency_format($item['amount'], $item['currency_code'], $entity));
         }
       }
@@ -453,35 +454,17 @@
 /**
  * Get the price for the min qty possible in a product.
  */
-function commerce_price_table_get_amount_qty($product, $quantity = 1) {
-  $items = array();
-  $product_wrapper = entity_metadata_wrapper('commerce_product', $product);
-  $fields = commerce_info_fields('commerce_price_table', 'commerce_product');
-  foreach ($fields as $field) {
-    if (!empty($product->{$field['field_name']})) {
-      foreach ($product_wrapper->{$field['field_name']}->value() as $item) {
-        $items[] = $item;
-      }
+function commerce_price_table_get_amount_qty($product, $quantity = 1, $items) {
+  // Sort the items by quantity and return the matching one.
+  $result = false;
+  uasort($items, 'commerce_price_table_sort_by_qty');
+  foreach ($items as $item) {
+    if ($quantity >= $item['min_qty']) {
+      $result = $item;
     }
   }
 
-  // Sort the items by quantity and return the matching one.
-  uasort($items, 'commerce_price_table_sort_by_qty');
-  foreach ($items as $item) {
-    if ($quantity <= $item['max_qty'] && $quantity >= $item['min_qty']) {
-      return $item;
-    }
-  }
-
-  // Handle the unlimited qty.
-  foreach ($items as $item) {
-    if ($item['max_qty'] == -1) {
-      return $item;
-    }
-  }
-
-  // We fallback to the higher one if no match was found.
-  return end($items);
+  return $result;
 }
 
 /**
@@ -554,15 +537,19 @@
  * Helper function that takes care of the quantity displayed in the headers of 
  * the price table.
  */
-function commerce_price_table_display_quantity_headers($item) {
-  // Set the quantity text to unlimited if it's -1.
-  $max_qty = $item['max_qty'] == -1 ? t('Unlimited') : $item['max_qty'];
+function commerce_price_table_display_quantity_headers($item, $next_item) {
   // If max and min qtys are the same, only show one.
-  if ($item['min_qty'] == $max_qty) {
-    $quantity_text = $item['min_qty'];
+  $min_qty = $item['min_qty'] == 0 ? 1 : $item['min_qty'];
+  $max_qty = empty($next_item) ? -1 : $next_item['min_qty'] - 1;
+
+  if ($min_qty == $max_qty) {
+    $quantity_text = $min_qty;
+  }
+  else if ($max_qty < 0) {
+    $quantity_text = "≥ $min_qty";
   }
   else {
-    $quantity_text = $item['min_qty'] . ' - ' . $max_qty;
+    $quantity_text = $min_qty . ' - ' . $max_qty;
   }
   return $quantity_text;
 }
diff -r 9066cf106c76 -r a2390463299f commerce_price_table.rules.inc
--- a/commerce_price_table.rules.inc      Fri Dec 28 15:17:06 2012 +0100
+++ b/commerce_price_table.rules.inc      Fri Dec 28 16:57:21 2012 +0100
@@ -17,6 +17,10 @@
         'label' => t('Quantity'),
         'type' => 'decimal',
       ),
+      'price_table' => array(
+        'label' => t('Price table'),
+        'type' => 'list<commerce_price_table>',
+      ),
     ),
     'group' => t('Commerce price table'),
   );
@@ -24,13 +28,13 @@
   return $actions;
 }
 
-function commerce_price_table_set_price($line_item, $quantity) {
+function commerce_price_table_set_price($line_item, $quantity, $price_table) {
   // If the line item contains a product, we set the price according to the
   // quantity.
   if (commerce_line_items_quantity(array($line_item), commerce_product_line_item_types())) {
     $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
     $product = commerce_product_load($line_item_wrapper->commerce_product->product_id->value());
-    $item = commerce_price_table_get_amount_qty($product, $quantity);
+    $item = commerce_price_table_get_amount_qty($product, $quantity, $price_table);
     if (!empty($item)) {
       // Empty the price components to recalculate them.
       $line_item->commerce_unit_price[LANGUAGE_NONE][0]['data']['components'] = array();
diff -r 9066cf106c76 -r a2390463299f commerce_price_table.rules_defaults.inc
--- a/commerce_price_table.rules_defaults.inc     Fri Dec 28 15:17:06 2012 +0100
+++ b/commerce_price_table.rules_defaults.inc     Fri Dec 28 16:57:21 2012 +0100
@@ -20,9 +20,18 @@
 
   $rule
     ->event('commerce_product_calculate_sell_price')
+    ->condition('entity_has_field', array(
+      'entity:select' => 'commerce-line-item',
+      'field' => 'commerce_product',
+    ))
+    ->condition('entity_has_field', array(
+      'entity:select' => 'commerce-line-item:commerce-product',
+      'field' => 'field_price_table',
+    ))
     ->action('commerce_price_table_set_price', array(
       'commerce_line_item:select' => 'commerce-line-item',
       'quantity:select' => 'commerce-line-item:quantity',
+      'price_table:select' => 'commerce-line-item:commerce-product:field-price-table',
     ));
 
   $rule->weight = -10;
diff -r 9066cf106c76 -r a2390463299f tests/commerce_price_table.test
--- a/tests/commerce_price_table.test     Fri Dec 28 15:17:06 2012 +0100
+++ b/tests/commerce_price_table.test     Fri Dec 28 16:57:21 2012 +0100
@@ -123,7 +123,6 @@
     $this->assertText('Price table', t('Price table field label found in the add product form.'));
     $this->assertFieldByName($this->field_name . '[und][0][amount]', NULL, t('Price table amount is present'));
     $this->assertFieldByName($this->field_name . '[und][0][min_qty]', NULL, t('Price table min quantity is present'));
-    $this->assertFieldByName($this->field_name . '[und][0][max_qty]', NULL, t('Price table max quantity is present'));
     $this->assertFieldById('edit-field-price-table-und-add-more', t('Add another item'), t('\'Add another item\' button is present'));
   }
 
@@ -138,21 +137,18 @@
     $edit = array(
       'field_price_table[und][0][amount]' => 100,
       'field_price_table[und][0][min_qty]' => 1,
-      'field_price_table[und][0][max_qty]' => 10,
     );
     $this->drupalPostAJAX(NULL, $edit, 'field_price_table_add_more');
 
     $edit = array(
       'field_price_table[und][1][amount]' => 50,
       'field_price_table[und][1][min_qty]' => 11,
-      'field_price_table[und][1][max_qty]' => 20,
     );
     $this->drupalPostAJAX(NULL, $edit, 'field_price_table_add_more');
 
     $edit = array(
       'field_price_table[und][2][amount]' => 10,
       'field_price_table[und][2][min_qty]' => 21,
-      'field_price_table[und][2][max_qty]' => -1,
     );
     $this->drupalPostAJAX(NULL, $edit, 'field_price_table_add_more');
 
@@ -162,13 +158,10 @@
     $this->drupalGet('admin/commerce/products/1/edit');
     $this->assertFieldByName($this->field_name . '[und][0][amount]', 100, t('First amount for price table is correct.'));
     $this->assertFieldByName($this->field_name . '[und][0][min_qty]', 1, t('First min quantity for price table is correct.'));
-    $this->assertFieldByName($this->field_name . '[und][0][max_qty]', 10, t('First max quantity for price table is correct.'));
     $this->assertFieldByName($this->field_name . '[und][1][amount]', 50, t('Second amount for price table is correct.'));
     $this->assertFieldByName($this->field_name . '[und][1][min_qty]', 11, t('Second min quantity for price table is correct.'));
-    $this->assertFieldByName($this->field_name . '[und][1][max_qty]', 20, t('Second max quantity for price table is correct.'));
     $this->assertFieldByName($this->field_name . '[und][2][amount]', 10, t('Third amount for price table is correct.'));
     $this->assertFieldByName($this->field_name . '[und][2][min_qty]', 21, t('Third min quantity for price table is correct.'));
-    $this->assertFieldByName($this->field_name . '[und][2][max_qty]', -1, t('Third max quantity for price table is correct.'));
     
     // Load the product with id 1 and check the field values.
     $product = commerce_product_load(1);
@@ -176,13 +169,10 @@
     $product_wrapper = entity_metadata_wrapper('commerce_product', $product);
     $this->assertTrue($product_wrapper->{$this->field_name}->get(0)->amount->value() == 10000, t('First amount for price table is stored correctly.'));
     $this->assertTrue($product_wrapper->{$this->field_name}->get(0)->min_qty->value() == 1, t('First min quantity for price table is stored correctly.'));
-    $this->assertTrue($product_wrapper->{$this->field_name}->get(0)->max_qty->value() == 10, t('First max quantity for price table is stored correctly.'));
     $this->assertTrue($product_wrapper->{$this->field_name}->get(1)->amount->value() == 5000, t('Second amount for price table is stored correctly.'));
     $this->assertTrue($product_wrapper->{$this->field_name}->get(1)->min_qty->value() == 11, t('Second min quantity for price table is stored correctly.'));
-    $this->assertTrue($product_wrapper->{$this->field_name}->get(1)->max_qty->value() == 20, t('Second max quantity for price table is stored correctly.'));
     $this->assertTrue($product_wrapper->{$this->field_name}->get(2)->amount->value() == 1000, t('Third amount for price table is stored correctly.'));
     $this->assertTrue($product_wrapper->{$this->field_name}->get(2)->min_qty->value() == 21, t('Third min quantity for price table is stored correctly.'));
-    $this->assertTrue($product_wrapper->{$this->field_name}->get(2)->max_qty->value() == -1, t('Third max quantity for price table is stored correctly.'));
 
     // Login with customer
     $this->drupalLogin($this->store_customer);
@@ -207,21 +197,18 @@
     $edit = array(
       'field_price_table[und][0][amount]' => 100,
       'field_price_table[und][0][min_qty]' => 1,
-      'field_price_table[und][0][max_qty]' => 10,
     );
     $this->drupalPostAJAX(NULL, $edit, 'field_price_table_add_more');
 
     $edit = array(
       'field_price_table[und][1][amount]' => 50,
       'field_price_table[und][1][min_qty]' => 11,
-      'field_price_table[und][1][max_qty]' => 20,
     );
     $this->drupalPostAJAX(NULL, $edit, 'field_price_table_add_more');
 
     $edit = array(
       'field_price_table[und][2][amount]' => 10,
       'field_price_table[und][2][min_qty]' => 21,
-      'field_price_table[und][2][max_qty]' => -1,
     );
     $this->drupalPostAJAX(NULL, $edit, 'field_price_table_add_more');
 
