Hello all,

I am trying to get the uc_products module to work with a decimal value at the product prices, instead of a point. this to local usage of the decimal seperator. the 3 main functions to alter are:

/**
 * Implementation of hook_validate().
 *
 * Ensure that prices, weight, dimensions, and quantity are positive numbers.
 */
function uc_product_validate($node) {
  $pattern = '/^\d*(\'.drupal_get_variable('uc_currency_dec','.').'\d*)?$/';
  $price_error = t('Price must be in a valid number format. No commas and only one decimal point.');
  if (!empty($node->list_price) && !is_numeric($node->list_price) && !preg_match($pattern, $node->list_price)) {
    form_set_error('list_price', $price_error);
  }
  if (!empty($node->cost) && !is_numeric($node->cost) && !preg_match($pattern, $node->cost)) {
    form_set_error('cost', $price_error);
  }
  if (!is_numeric($node->sell_price) && !preg_match($pattern, $node->sell_price)) {
    form_set_error('sell_price', $price_error);
  }
  foreach (array('weight', 'length', 'width', 'height') as $property) {
    if (!empty($node->$property) && (!is_numeric($node->$property) || $node->$property < 0)) {
      form_set_error($property, t('@property must be a positive number. No commas and only one decimal point.', array('@property' => ucfirst($property))));
    }
  }
  if ($node->default_qty) {
    if (!is_numeric($node->default_qty)) {
      form_set_error('default_qty', t('Quantities should be numeric.'));
    }
    elseif ($node->default_qty < 0) {
      form_set_error('default_qty', t("Adding negative items to the cart doesn't make sense, so don't make it easy."));
    }
  }
}

/**
 * Implementation of hook_insert().
 */
function uc_product_insert($node) {
  if (!isset($node->unique_hash)) {
    $node->unique_hash = md5($node->vid . $node->nid . $node->model . $node->list_price . $node->cost . $node->sell_price . $node->weight . $node->weight_units . $node->dim_length . $node->dim_width . $node->dim_height . $node->length_units . $node->pkg_qty . $node->default_qty . $node->shippable . time());
  }
  db_query("INSERT INTO {uc_products} (vid, nid, model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable) VALUES (%d, %d, '%s', %f, %f, %f, %f, '%s', %f, %f, %f, '%s', %d, %d, '%s', %d, %d)",
    $node->vid, $node->nid, $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->dim_length, $node->dim_width, $node->dim_height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->unique_hash, $node->ordering, $node->shippable
  );
}

/**
 * Implementation of hook_update().
 */
function uc_product_update($node) {
  if ($node->revision) {
    db_query("INSERT INTO {uc_products} (vid, nid, model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable) VALUES (%d, %d, '%s', %f, %f, %f, %f, '%s', %f, %f, %f, '%s', %d, %d, '%s', %d, %d)",
      $node->vid, $node->nid, $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->dim_length, $node->dim_width, $node->dim_height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->unique_hash, $node->ordering, $node->shippable
    );
  }
  else {
    //drupal_set_message('<pre>'. print_r($node, TRUE) .'</pre>');drupal_set_message('<pre>'. print_r($node, TRUE) .'</pre>');
    db_query("UPDATE {uc_products} SET model = '%s', list_price = %f, cost = %f, sell_price = %f, weight = %f, weight_units = '%s', length = %f, width = %f, height = %f, length_units = '%s', pkg_qty = %d, default_qty = %d, ordering = %d, shippable = %d WHERE vid = %d",
      $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->dim_length, $node->dim_width, $node->dim_height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->ordering, $node->shippable, $node->vid);
  }
}

to the following:

/**
 * Implementation of hook_validate().
 *
 * Ensure that prices, weight, dimensions, and quantity are positive numbers.
 */
function uc_product_validate($node) {
  $pattern = '/^\d*(\'.drupal_get_variable('uc_currency_dec','.').'\d*)?$/'; /*Altered  to add the variable for the decimal seperator as found in admin/store/settings/store/edit/format */
  $price_error = t('Price must be in a valid number format. No commas and only one decimal point.');
  if (!empty($node->list_price) && !is_numeric($node->list_price) && !preg_match($pattern, $node->list_price)) {
    form_set_error('list_price', $price_error);
  }
  if (!empty($node->cost) && !is_numeric($node->cost) && !preg_match($pattern, $node->cost)) {
    form_set_error('cost', $price_error);
  }
  if (!is_numeric($node->sell_price) && !preg_match($pattern, $node->sell_price)) {
    form_set_error('sell_price', $price_error);
  }
  foreach (array('weight', 'length', 'width', 'height') as $property) {
    if (!empty($node->$property) && (!is_numeric($node->$property) || $node->$property < 0)) {
      form_set_error($property, t('@property must be a positive number. No commas and only one decimal point.', array('@property' => ucfirst($property))));
    }
  }
  if ($node->default_qty) {
    if (!is_numeric($node->default_qty)) {
      form_set_error('default_qty', t('Quantities should be numeric.'));
    }
    elseif ($node->default_qty < 0) {
      form_set_error('default_qty', t("Adding negative items to the cart doesn't make sense, so don't make it easy."));
    }
  }
}

/**
 * Implementation of hook_insert().
 */
function uc_product_insert($node) {
  $node->cost = str_replace(',', '.', $node->cost); /*Added by KoffieSchaap*/
  $node->list_price = str_replace(',', '.', $node->list_price); /*Added by KoffieSchaap*/
  $node->sell_price str_replace(',', '.', $node->sell_price); /*Added by KoffieSchaap*/

  if (!isset($node->unique_hash)) {
    $node->unique_hash = md5($node->vid . $node->nid . $node->model . $node->list_price . $node->cost . $node->sell_price . $node->weight . $node->weight_units . $node->dim_length . $node->dim_width . $node->dim_height . $node->length_units . $node->pkg_qty . $node->default_qty . $node->shippable . time());
  }
  db_query("INSERT INTO {uc_products} (vid, nid, model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable) VALUES (%d, %d, '%s', %f, %f, %f, %f, '%s', %f, %f, %f, '%s', %d, %d, '%s', %d, %d)",
    $node->vid, $node->nid, $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->dim_length, $node->dim_width, $node->dim_height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->unique_hash, $node->ordering, $node->shippable
  );
}

/**
 * Implementation of hook_update().
 */
function uc_product_update($node) {
  $node->cost = str_replace(',', '.', $node->cost); /*Added by KoffieSchaap*/
  $node->list_price = str_replace(',', '.', $node->list_price); /*Added by KoffieSchaap*/
  $node->sell_price str_replace(',', '.', $node->sell_price); /*Added by KoffieSchaap*/
  if ($node->revision) {
    db_query("INSERT INTO {uc_products} (vid, nid, model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable) VALUES (%d, %d, '%s', %f, %f, %f, %f, '%s', %f, %f, %f, '%s', %d, %d, '%s', %d, %d)",
      $node->vid, $node->nid, $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->dim_length, $node->dim_width, $node->dim_height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->unique_hash, $node->ordering, $node->shippable
    );
  }
  else {
    //drupal_set_message('<pre>'. print_r($node, TRUE) .'</pre>');drupal_set_message('<pre>'. print_r($node, TRUE) .'</pre>');
    db_query("UPDATE {uc_products} SET model = '%s', list_price = %f, cost = %f, sell_price = %f, weight = %f, weight_units = '%s', length = %f, width = %f, height = %f, length_units = '%s', pkg_qty = %d, default_qty = %d, ordering = %d, shippable = %d WHERE vid = %d",
      $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->dim_length, $node->dim_width, $node->dim_height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->ordering, $node->shippable, $node->vid);
  }
}

ofcourse, this also needs to be done to reading the values into the form, which could be done by altering the "uc_store_format_price_field_value" function in uc_store.module to change the point to a comma there.

function uc_store_format_price_field_value($price) {
  $exact = rtrim(number_format($price, 6, '.', ''), '0');
  $round = number_format($price, variable_get('uc_currency_prec', 2), '.', '');

  if ($exact == rtrim($round, '0')) {
    return $round;
  }
  else {
    return $exact;
  }
}

to

function uc_store_format_price_field_value($price) {
  $exact = rtrim(number_format($price, 6, '.', ''), '0');
  $round = str_replace('.', ',', number_format($price, variable_get('uc_currency_prec', 2), '.', ''));

  if ($exact == rtrim($round, '0')) {
    return $round;
  }
  else {
    return $exact;
  }
}

is there any potential to implement this?

Comments

koffieschaap’s picture

small typing error:

$pattern = '/^\d*(\'.drupal_get_variable('uc_currency_dec','.').'d*)?$/'; should be $pattern = '/^\d*(\\'.drupal_get_variable('uc_currency_dec','.').'d*)?$/';

longwave’s picture

Can you post your changes as a .patch file instead? This will make it easier to review and comment on.

longwave’s picture

koffieschaap’s picture

ofcourse, uc_Store_format_price_field_value could be changed to:

$exact = rtrim(number_format($price, 6, variable_get('uc_currency_dec','.'), ''), '0');
$round = number_format($price, variable_get('uc_currency_prec', 2), variable_get('uc_currency_dec','.'), '');

koffieschaap’s picture

im horrible with creating patch files, but i will try

koffieschaap’s picture

patchfile attached

koffieschaap’s picture

#1091000: uc_store_format_price_field_value() does not respect decimal marker is also needed for this, but i think a patchfile is created there. so i did not include that code in my patch.

koffieschaap’s picture

Status: Active » Needs review

Status: Needs review » Needs work
longwave’s picture

Testing failed because the patch is buggy:

+  $node->sell_price str_replace(',', '.', $node->sell_price);

Also, shouldn't that str_replace() be using uc_currency_dec instead of hard coding a comma?

koffieschaap’s picture

Status: Needs work » Needs review
StatusFileSize
new2.21 KB

as far as i know, the database values are a float value. this means we need to use the point there. if people enter the value with a point decimal seperator all is ok, but if they use a comma seperator it needs to be altered to a point.

ofcourse, if there is a better way to convert the decimal to a float than str_replace thats ok, but this works for me.

this means we do not need the uc_currence_dec variable in there, its about database storage.

sorry for the error in the patch, here is a corrected one

Status: Needs review » Needs work
longwave’s picture

Your code supports using comma as the decimal separator, but what if someone configures something other than dot or comma as the separator? That should be supported as well...

koffieschaap’s picture

not right now, but i do not think there are any other ways for seperating the decimals besides comma and point.

i was watching the testresults and i kinda dont get why it didnt pass the test, can anyone clarify?

koffieschaap’s picture

Status: Needs work » Needs review
StatusFileSize
new2.4 KB

i must be as blind as a bat, i was using drupal_get_variable instead of variable_get
i also added a line to modify for any other seperators as noted in #13, and changed the lines with drupal_get_variable

Status: Needs review » Needs work
longwave’s picture

You missed one:

+  $pattern = '/^\d*(\\'.drupal_get_variable('uc_currency_dec','.').'d*)?$/';

You should probably test these patches yourself before uploading ;)

koffieschaap’s picture

Status: Needs work » Needs review
StatusFileSize
new2.39 KB

Status: Needs review » Needs work
longwave’s picture

Status: Needs work » Needs review

I think the remaining failures are due to the fact UC 2.x requires token, but testbot does not handle dependencies properly.

longwave’s picture

Title: Product node validation decimal values » Product price editing should respect currency decimal marker
Version: 6.x-2.6 » 6.x-2.x-dev
Status: Needs review » Needs work
StatusFileSize
new4.17 KB

Attached patch fixes a couple of issues with the above regarding coding style and use of preg_quote() to escape the decimal marker, and incorporates #1091000: uc_store_format_price_field_value() does not respect decimal marker to initially format prices in the same way.

This however does not address other price fields, namely order editing and attribute price adjustments, which should be treated the same way, so marking as needs work. I think perhaps we should introduce a new 'uc_price' Form API element which can handle formatting and conversion for us.

tr’s picture

Version: 6.x-2.x-dev » 7.x-3.x-dev

Now that we have a uc_price Form API element, maybe this can be reworked for D7.

tr’s picture

Version: 7.x-3.x-dev » 8.x-4.x-dev