I am hoping to work on a way to use feeds to import the price, min, max from a csv.

I think this should be done with hook_feeds_processor_targets_alter().

Comments

Status:Active» Needs work

I have something worked out, but you need to set a separator for multiprice support into a single field with unlimited values, for the case below is pipe separated values, for importing a sample of data like this "2,56|1|19";"2,33|20|-1" where the first number is the price amount, then the min qty, next the max qty being -1 considered by price table as unlimited.

Code example:

<?php
/**
* Implements hook_feeds_processor_targets_alter().
*/
function mymodule_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
  foreach (
field_info_instances($entity_type, $bundle_name) as $name => $instance) {
   
$info = field_info_field($name);
    if (
$info['type'] == 'commerce_price_table') {
     
$targets[$name] = array(
       
'name' => $instance['label'],
       
'callback' => 'mymodule_feeds_set_target_price_table',
       
'description' => t('The table price for @name field.', array('@name' => $instance['label'])),
       
'real_target' => $name,
      );
    }
}
/**
* Callback for mapping. Here is where the actual mapping happens.
*
* When the callback is invoked, $target contains the name of the field the
* user has decided to map to and $value contains the value of the feed item
* element the user has picked as a source.
*/
function mymodule_feeds_set_target_price_table($source, $entity, $target, $value, $mapping) {
  if (empty(
$value)) {
    return;
  }
 
// Handle non-multiple value fields.
 
if (!is_array($value)) {
   
$value = array($value);
  }
 
// Iterate over all values.
 
$info = field_info_field($target);
 
$field = isset($entity->$target) ? $entity->$target : array();
 
$i = isset($field[LANGUAGE_NONE]) ? count($field[LANGUAGE_NONE]) : 0;
  foreach (
$value as $v) {
    if (!
is_array($v) && !is_object($v)) {
      list(
$amount, $min_qty, $max_qty) = explode('|', $v);
     
// Conversion from comma to decimal point.
     
$amount = str_replace(',', '.', $amount);
     
// always put the default currency
     
$currency_code = commerce_default_currency();
     
$field[LANGUAGE_NONE][$i]['currency_code'] = $currency_code;
     
$field[LANGUAGE_NONE][$i]['amount'] = $amount;
     
$field[LANGUAGE_NONE][$i]['min_qty'] = $min_qty;
     
$field[LANGUAGE_NONE][$i]['max_qty'] = $max_qty;
    }
    if (
$info['cardinality'] == 1) {
      break;
    }
   
$i++;
  }
 
$entity->{$target} = $field;
}
?>

Here is the code i put at the end of the module file and it does what i need,
The feeds tamper module will take care of multivalue for my needs

/**
* @file
* Integration with the Feeds module.
*/
/**
* Implements hook_feeds_node_processor_targets_alter().
*/
function commerce_price_table_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
    $info = field_info_field($name);
    if ($info['type'] == 'commerce_price_table') {
      foreach ($info['columns'] as $sub_field => $schema_info) {
        $name_label = $instance['label'] . ': ' . drupal_ucfirst(str_replace('_', ' ', $sub_field));
        $targets[$name . ':' . $sub_field] = array(
          'name' => $name_label,
          'callback' => 'commerce_price_table_set_target',
          'real_target' => $info['field_name'],
          'description' => $schema_info['description'],
        );
      }
    }
  }
}
/**
* Callback for hook_feeds_processor_targets_alter().
*
* @param $source
*   Field mapper source settings.
* @param $entity
*   An entity object, for instance a node object.
* @param $target
*   A string identifying the target on the node.
* @param $value
*   The value to populate the target with.
*/
function commerce_price_table_set_target($source, $entity, $target, $value) {
  list($field_name, $sub_field) = explode(':', $target, 2);
  // Handle non-multiple value fields.
  if (!is_array($value)) {
    $value = array($value);
  }
  $field = isset($entity->$field_name) ? $entity->$field_name : array();
  foreach ($value as $i => $v) {
    $field['und'][$i][$sub_field] = $v;
  }
  $entity->$field_name = $field;
}

@pcambra @thill_ Which patch has been successful? And what file are you patching it to?

Note that since #1322714: Odd Pricing Table Issue landed the

<?php
$field
[LANGUAGE_NONE][$i]['amount'] = $amount;
?>

part in #1 needs to be
<?php
$field
[LANGUAGE_NONE][$i]['amount'] = commerce_currency_decimal_to_amount($amount, $currency_code);
?>

otherwise you'll get very wrong amounts displayed afterwards (0.16 instead of 16.30, for example).

Status:Needs work» Needs review

This works as advertised! I had to use feeds tamper for it to work as thill pointed out.

Status:Needs review» Active

FYI - I needed to add a closing curly bracket in hook_feeds_processor_targets_alter() to keep it from breaking the site. Will update after I test an import

Working Code

Got this code to work (wonderfully!) with some minor adjustments and a careful setup:
1) Added the closing curly bracket per my last comment
2) Removed the lines to convert the comma to a decimal on prices (my prices ARE in decimal format)
3) Made the change in #4
My code is here:

<?php
/**
* Implements hook_feeds_processor_targets_alter().
*
* Needed for importing Price Table data
*/
function MYMODULE_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
  foreach (
field_info_instances($entity_type, $bundle_name) as $name => $instance) {
   
$info = field_info_field($name);
    if (
$info['type'] == 'commerce_price_table') {
     
$targets[$name] = array(
       
'name' => $instance['label'],
       
'callback' => 'MYMODULE_feeds_set_target_price_table',
       
'description' => t('The table price for @name field.', array('@name' => $instance['label'])),
       
'real_target' => $name,
        );
      }
    }
}
/**
* Callback for mapping. Here is where the actual mapping happens.
*
* When the callback is invoked, $target contains the name of the field the
* user has decided to map to and $value contains the value of the feed item
* element the user has picked as a source.
*
* Needed for importing Price Table data
*/
function MYMODULE_feeds_set_target_price_table($source, $entity, $target, $value, $mapping) {
  if (empty(
$value)) {
    return;
  }
 
// Handle non-multiple value fields.
 
if (!is_array($value)) {
   
$value = array($value);
  }
 
// Iterate over all values.
 
$info = field_info_field($target);
 
$field = isset($entity->$target) ? $entity->$target : array();
 
$i = isset($field[LANGUAGE_NONE]) ? count($field[LANGUAGE_NONE]) : 0;
  foreach (
$value as $v) {
    if (!
is_array($v) && !is_object($v)) {
      list(
$amount, $min_qty, $max_qty) = explode('|', $v);
     
// always put the default currency
     
$currency_code = commerce_default_currency();
     
$field[LANGUAGE_NONE][$i]['currency_code'] = $currency_code;
     
$field[LANGUAGE_NONE][$i]['amount'] = commerce_currency_decimal_to_amount($amount, $currency_code);
     
$field[LANGUAGE_NONE][$i]['min_qty'] = $min_qty;
     
$field[LANGUAGE_NONE][$i]['max_qty'] = $max_qty;
    }
    if (
$info['cardinality'] == 1) {
      break;
    }
   
$i++;
  }
 
$entity->{$target} = $field;
}
?>

Add this to an existing module, a new one, or your own "glue" module... be sure to change the MYMODULE to whatever your module is actually named. If you want to hack Commerce Price Table, you can replace MYMODULE_ with commerce_price_table_ like the example in comment #2... of course, this is inadvisable as you will just lose this code on your next update of the module

Format for data

This is actually pretty straightforward, but I will leave a note her for those that may come behind. Basically, you want to create a delimited group of values (price, min qty, max qty) that is further delimited within a single field. Confused? Its sort of like making a nested array. Basically we want a single slot in the CSV to hold information about each additional entry in the table price field... and each of those entries is in turn composed of 3 separate pieces of info.

Ok - real example. Each of the 3 items for the table entries are expected by code to be separated by a pipe (|). And assuming that you are using commas in your CSV, then we want some OTHER character to delimit within the entry.. so I will use a semicolon. If we want to end up with table prices like this:

  • $40 for 0-10 items (40.00|0|10)
  • $30 for 11-25 items (30.00|11|25)
  • $20 for 24-50 items (20.00|25|50)
  • $10 for 51+ items (10.00|51|-1)

Then we need a single CSV entry of something like this:
40.00|0|10;30.00|11|25;20.00|25|50;10.00|51|-1

So - a line in your CSV showing the title, sku, price and price table, would look something like this:
Product title,sku-12345,40.00,40.00|0|10;30.00|11|25;20.00|25|50;10.00|51|-1

Tamper settings

Now - the code above WILL take care of parsing through each entry for the 3 items (as delimited by the pipe), but it WON'T break the single field into an array. Thats what the Feeds Tamper is for. Once you create your Feeds importer settings and your mapping, just click the "Configure Feeds Tamper" on the mapping screen. Then, add a plugin for the field that pull sin the price table data. You wan to choose the "Explode" plugin and select your delimiter (in this case, a semicolon).

That should do it! If your CSV is properly formatted, then you should be able to "/import" and make it happen. You may have a slightly different setup, or be working with something other than a CSV... but this should get you started.

Perhaps this could be added as a submodule of Commer Price Table with a readme to explain how it works? I am sure there are LOTS of people using Feeds to import and update products, and if they are wanting to use this module, then this would be handy to have.

#8 - Wonderful post. Thanks!

rlnorthcutt - great post many thx, also many thx to the module creator. Ive just managed to import 3,200 qty price breaks of various types all done in about 2 hours including setting this up. It all worked first time as well!

One thing ive noticed is that when re-importing the prices dont get updated, even after setting skip hash check. I ended up truncating the field_revision_field_quantity_pricing table to clear out the data.