With a Commerce Kickstart RC4 and Commerce Multicurrency 7.x-1.x-dev. The shopping cart (Commerce Order) block is not converting the Total when switching between currencies with the Currency Menu Selector block. Until I go to the /cart page, then the block displays the correct currency. Note that I can convert the currency and the cart block displays the total in the correct currency on the /cart page. Does it sound like I am missing a rule? or is it a problem with the shopping cart block in Kickstart?

Comments

makangus’s picture

It seems like the following line 92 in commerce_line_item_handler_area_line_item_summary.inc of the line item module, is returning $line_items in the wrong currency.
$line_items = commerce_line_item_load_multiple($line_item_ids);

makangus’s picture

Aha, so the problem is with "Commerce Line Item: Line item summary", if I switched it to "Commerce Order: Order total" in Views it works fine.

sbonde’s picture

Issue summary: View changes

I have the exact same problem but switching to "Commerce Order: Order total", didn't help.

I have the following currencies: DKK, EUR and GBP.
The Cart items show the correct currency but the total doesn't. Sometimes it wont even change and other times it gets stuck on the chosen currency. Most of the times EUR and can't seem to change to GBP no matter what I do.
I have modified the "Set the currency price" rule and added the price rules for the different fields in actions so that I can have manual conversion from the currency fields added to the products.

I have also tried adding a empty cache rule that triggers on the event of currency change but nothing seems to help.

I am currently using 7.x-1.3 but have also tried 7.x-1.x-dev without any luck.

Hope somebody out there might be able to help me solve this problem.

sbonde’s picture

StatusFileSize
new80.08 KB

Multi Currency Rule screenshot

msankhala’s picture

Were you able to resolve this issue?

sbonde’s picture

Yes with multiple shipping rules for each currency in each language, and a redirect to cart page, if the customer changes language on the checkout page, since I had to send the customer through the sipping page to calculate the correct shipping price.
It was quite a hassle to get it working but finally I manged. :-)
Let me know if you need screenshots or rules export or something.

das-peter’s picture

Screen shorts / rules exports would be appreciated.
We could create documentation pages.
The questions around this module are often of the same kind. So more examples would be nice to help others getting started.

sbonde’s picture

It will take me some time to gather all rules export, screnshots modules etc. But will upload as soon as possible.

msankhala’s picture

Thanks @SBonde for your suggestion. I'll try the solution you suggested. But redirecting to user to cart page whenever he change the Currency is not a good option. I think there is something wrong with commerce_line_item_handler_area_line_item_summary.inc as @makangus mentioned.

sbonde’s picture

@msankhala you are welcome.

The rule I setup to redirect to cart only if the language is changed on the checkout page and not whenever the language is changed. Since it is highly unlikely that anybody changes the language on that page, but it was the only way to force the user to go through shipping again and for my custom shipping rules to be calculated correctly.

I have also setup a rule that change currency when the language is changed.
So if chosen English currency converts to Euro and if chosen Danish the currency is changed to DKK (Danish kroner).

kunago’s picture

@msankhala: I have a fast fix that could work for you. It surely is not the Drupal way but it works nice.
Find in the file commerce_line_item_handler_area_line_item_summary.inc line no. 98, it should be this one:
$currency = commerce_currency_load($total['currency_code']);
Insert this code just below:

if (module_exists('commerce_multicurrency') && $total['currency_code'] != commerce_multicurrency_get_user_currency_code()) {
  $currency = commerce_currency_load(commerce_multicurrency_get_user_currency_code());
  $total['amount'] = commerce_multicurrency_conversion($total['amount'], $total['currency_code'], $currency['code']);
  $total['currency_code'] = $currency['code'];
}

Dirty, but does it's job.

kunago’s picture

@msankhala: In case you wish not to mess with a module directly, there is a way to tweak the template file commerce-line-item-summary.tpl.php. You can do some rewrites in the version you upload to your theme. I am currently using this method and it works perfect.

msankhala’s picture

Yuhu.. Thank you so much @Kunago. You made my day. I was facing this issue so long and almost invested 3 days for resolving this issue but didn't find the perfect solution. @kunago i would like to buy a beer to you.

msankhala’s picture

@kunago Yes the code you provided work well when added in commerce_line_item_handler_area_line_item_summary.inc file after line 98 but in template file commerce-line-item-summary.tpl.php which i override in my theme i can't use this code because in template $total['currency_code'] is not available. $total is available as formatted string. To make $total['currency_code'] available in template i have to modify code in commerce_line_item_handler_area_line_item_summary.inc OR reload the line_item_ids and load the commerce line item again then convert the currency with the code you provided. See the changes i made in commerce-line-item-summary.tpl.php.

if ($total):

  // Build an array of line item IDs from the View results that we will load
  // and use for calculating totals.
  $line_item_ids = array();

  foreach ($view->result as $result) {
    // Here i made the changes loaded the line_item_id directly rather then calling $this->get_value($result);
    $line_item_id = $result->commerce_line_item_field_data_commerce_line_items_line_item_;
    if ($line_item_id) {
      $line_item_ids[] = $line_item_id;
    }
  }
  $line_items = commerce_line_item_load_multiple($line_item_ids);

  // Add total information and the line item summary links.
  $quantity = commerce_line_items_quantity($line_items);
  $total = commerce_line_items_total($line_items);
  $currency = commerce_currency_load($total['currency_code']);
  //rewrite the value of $total as suggeste at https://www.drupal.org/node/1853638#comment-9367691
  if (module_exists('commerce_multicurrency')) {
    $currency = commerce_currency_load(commerce_multicurrency_get_user_currency_code());
    $total['amount'] = commerce_multicurrency_conversion($total['amount'], $total['currency_code'], $currency['code']);
    $total['currency_code'] = $currency['code'];
    $total = commerce_currency_format($total['amount'], $total['currency_code'], $view);
  }
  
  <div class="line-item-total">
    <span class="line-item-total-label"><?php print $total_label; ?></span> <span class="line-item-total-raw"><?php print $total; ?></span>
  </div>

endif;

and its working fine. Does the same way you made changes in template or there is any better way?

kunago’s picture

@msankhala: I am aware of that there is no currency code in the template file. To avoid changing anything in the module because that would be overwritten once new kickstart comes out, I am trying to detect the currency code by the currency symbol. I know it is not the best solution but since the currency code is not passed to the template, this is the best I could achieve:

if (module_exists('commerce_multicurrency')) {
  $currency_chosen = commerce_currency_load(commerce_multicurrency_get_user_currency_code());
  if (isset($currency_chosen['symbol']) && ($currency_chosen['symbol'] != substr($total, -(strlen($currency_chosen['symbol']))))) {
    $currencies = commerce_currency_get_symbol();
    foreach ($currencies AS $currency_code => $currency_symbol) {
      if(strpos($total, $currency_symbol) !== FALSE) {
        $currency_display = substr($total, strpos($total, $currency_symbol), strlen($currency_symbol));
        break;
      }
    }
    if (isset($currency_chosen['code']) && isset($currency_display)) {
      $total = commerce_currency_format(commerce_multicurrency_conversion($total_raw, $currency_display, $currency_chosen['code']), $currency_chosen['code'], $view);
    }
  }
}

If you paste this code on top of your template file, you fill get what you need, I assume.

msankhala’s picture

Thanks @kunago

msankhala’s picture

@Kunago: Unfortunately adding the code in template you provided in #15 didn't work as expected because i have three currencies enabled. EUR, GBP and USD. GBP is my default currency. GBP and USD show the currency symbol at start of total while EUR show currency symbol at and of total. I changed the if condition accordingly but that didn't also work.

Changed this:

if (isset($currency_chosen['symbol']) && ($currency_chosen['symbol'] != substr($total, -(strlen($currency_chosen['symbol']))))) {

to this:

if (isset($currency_chosen['symbol']) && ($currency_chosen['symbol'] != substr($total, strpos($total, $currency_chosen['symbol']), strlen($currency_chosen['symbol'])))){

This also didn't work because of $total variable i receive in template. Because sometime currency symbol in $total is other then user selected currency. For example if user selected USD then i should receive $total (e.g $223.45) but i receive $total in other currency. in this case i have to recalculate $total. But that is not possible to recalculate $total until i get the $linte_items_ids in template.

kunago’s picture

@msankhala: What if you used this test "if" condition instead?

if (isset($currency_chosen['symbol']) && strpos($total, $currency_chosen['symbol']) === false) {

It should work better, even for those currencies that have the symbol at the beginning.
It basically says "if the symbol is set and it is not found in the total at all ..."

sbonde’s picture

Sorry guys I confused this issue with this one another (https://www.drupal.org/node/2294107).

Unfortunately I wasn't able to solve this, will try some of the suggestions mentioned above.

msankhala’s picture

@Kunago: Unfortunately this code didn't work after making the change you mentioned in #18. i don't know why. There may some other issue in my case. But the following code works for me. Thank you for all the help and your code show me direction how i can resolve this issue.

if (module_exists('commerce_multicurrency')) {
// Build an array of line item IDs from the View results that we will load
// and use for calculating totals.
$line_item_ids = array();

foreach ($view->result as $result) {
  // $line_item_id = $result->commerce_line_item_field_data_commerce_line_items_line_item_;
  $alias = $view->query->fields['commerce_line_item_field_data_commerce_line_items_line_item_']['alias'];
  $line_item_id = $result->{$alias};
  if ($line_item_id) {
    $line_item_ids[] = $line_item_id;
  }
}
$line_items = commerce_line_item_load_multiple($line_item_ids);

// Add total information and the line item summary links.
$quantity = commerce_line_items_quantity($line_items);
$total = commerce_line_items_total($line_items);
// $currency = commerce_currency_load($total['currency_code']);
//rewrite the value of $total as suggeste at https://www.drupal.org/node/1853638#comment-9367691

  $currency = commerce_currency_load(commerce_multicurrency_get_user_currency_code());
  $total['amount'] = commerce_multicurrency_conversion($total['amount'], $total['currency_code'], $currency['code']);
  $total['currency_code'] = $currency['code'];
  $total = commerce_currency_format($total['amount'], $total['currency_code'], $view);
}

I added this code on top of commerce-line-item-summary.tpl.php template file which i override in my theme.

bgilhome’s picture

What about adding an order refresh in commerce_multicurrency_set_user_currency_code for the current user's cart order? Patch attached. Is this the right track? Or too much overhead?

bgilhome’s picture

StatusFileSize
new1.48 KB

I've solved this by calling an order refresh for the current user's order when currency is changed, and also adding a hook_commerce_cart_line_item_refresh() to convert the line items totals to the new currency (so the order total uses the new currency - see commerce_order_calculate_total()). Patch attached.

msankhala’s picture

Status: Active » Needs review

  • das-peter committed 8e61fa2 on 7.x-1.x authored by bgilhome
    Issue #1853638 by bgilhome, sBonde: Commerce Kickstart shopping cart (...
das-peter’s picture

Status: Needs review » Fixed

@bgilhome I've had some trouble applying your patch - the path prefixes i/ w/ don't seem to be recognized properly. Further the patch had some flaws regarding coding standards - would be nice if you could check that stuff next time:

  1. +++ w/commerce_multicurrency.module
    @@ -420,11 +420,33 @@ function commerce_multicurrency_set_user_currency_code($currency_code, $overwrit
    +      commerce_cart_order_refresh($order);  // also refreshes line items via hook
    

    Line exceeds 80 characters; contains 81 characters.
    Inline comments must start with a capital letter.
    Inline comments must end in full-stops, exclamation marks, or question marks.
    Comments may not appear after statements

  2. +++ w/commerce_multicurrency.module
    @@ -420,11 +420,33 @@ function commerce_multicurrency_set_user_currency_code($currency_code, $overwrit
     /**
    + * Implements hook_commerce_cart_line_item_refresh()
    + */
    

    Doc comment short description must end with a full stop.

  3. +++ w/commerce_multicurrency.module
    @@ -420,11 +420,33 @@ function commerce_multicurrency_set_user_currency_code($currency_code, $overwrit
    +      $line_item_wrapper->commerce_total->amount->value(), ¶
    +      $line_item_wrapper->commerce_total->currency_code->value(), ¶
    

    Whitespace found at end of line

However, I think the approach is sensible, so I fixed all those nitpicks and committed the patch.
Thanks all for keep pushing this. Let's hope nothing breaks :D

tnfno’s picture

I have a problem with the latest dev version with this patch. If I have a new browser session (test with a new incognito/private window) and nothing has been added to the cart, changing currency gives the following error:

EntityMetadataWrapperException: Invalid data value given. Be sure it matches the required data type and format. in EntityDrupalWrapper->set() (line 736 of /var/www/html/nnnnnn/web/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.wrapper.inc).

If you add something to the cart and even remove it again, the problem does not show up anymore in that session.

  • das-peter committed fb8f2d3 on 7.x-1.x
    Issue #1853638 by bgilhome, sBonde: Commerce Kickstart shopping cart (...
das-peter’s picture

@tnfno I've just pushed a change that adds a check if a order's available before calling commerce_cart_order_refresh(). This could fix such an issue.

tnfno’s picture

Thank you for the fast solution. I can confirm that the error is gone on my site.

PS: You get a md5 checksum error on the update if you try to drush dl commerce_multicurrency-7.x-1.x-dev

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

rahu231086’s picture

Hello there,

Yes this issue has been resolved by committing this patch to the 7.x-1.x-dev. But it produces another very serious bug which is extremely hard to detect. It produces following error if line item refers to the disabled items.

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'commerce_line_item-32-0-0-und' for key 'PRIMARY': INSERT INTO {field_data_commerce_unit_price} (entity_type, entity_id, revision_id, bundle, delta, language, commerce_unit_price_amount, commerce_unit_price_currency_code, commerce_unit_price_data) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8); Array ( [:db_insert_placeholder_0] => commerce_line_item [:db_insert_placeholder_1] => 32 [:db_insert_placeholder_2] => 32 [:db_insert_placeholder_3] => product [:db_insert_placeholder_4] => 0 [:db_insert_placeholder_5] => und [:db_insert_placeholder_6] => 1195 [:db_insert_placeholder_7] => USD [:db_insert_placeholder_8] => a:1:{s:10:"components";a:1:{i:0;a:3:{s:4:"name";s:10:"base_price";s:5:"price";a:3:{s:6:"amount";s:4:"1195";s:13:"currency_code";s:3:"USD";s:4:"data";a:1:{s:10:"components";a:0:{}}}s:8:"included";b:1;}}} ) in field_sql_storage_field_storage_write() (line 448 of /drupal/modules/field/modules/field_sql_storage/field_sql_storage.module).

TO mitigate this you should never ever save the line item as we just need the refresh the line item not to save the line item after update as this is going to handle by the core. Since core is taking care for disabled items but your patch not if save the line item having disabled product. Then product pricing rules already empty the unit price and currency conversion does still product empty result. And unit price is required in the database schema and thus producing error. So to overcome this just remove from following

function commerce_multicurrency_commerce_cart_line_item_refresh($line_item, $order_wrapper) {
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$currency_code = commerce_multicurrency_get_user_currency_code();
if ($line_item_wrapper->commerce_total->currency_code->value() != $currency_code) {
$amount = commerce_currency_convert(
$line_item_wrapper->commerce_total->amount->value(),
$line_item_wrapper->commerce_total->currency_code->value(),
$currency_code
);
$line_item_wrapper->commerce_total->amount = $amount;
$line_item_wrapper->commerce_total->currency_code = $currency_code;
}
// $line_item_wrapper->save(); // remove this core will take care of it.
}

das-peter’s picture

@rahu231086 Please reopen a dedicated ticket for this. This ensures the issue is found.

freelylw’s picture

.