I am using Commerce 2 with the Stripe payment gateway.

I have products with prices in yen. For example, 3,000 yen.

Inside Commerce, the price is shown as 3,000 yen. However, when I test ordering the product using Stripe, the charge to the credit card is 300,000 yen, 100x the correct price!

If I set the price in Commerce to 30 yen, then 3,000 yen is billed to the card.

Yen is a non-decimal currency, but it seems that somewhere in the process the yen price is getting treated like a decimal currency, increasing it by a factor of 100.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

ptmkenny created an issue. See original summary.

bojanz’s picture

Project: Commerce Core » Commerce Stripe
Version: 8.x-2.0 » 8.x-1.x-dev
Component: Payment » Code
Priority: Normal » Critical

This is a Stripe module bug. For some reason the gateway does this:

  /**
   * Formats the charge amount for stripe.
   *
   * @param integer $amount
   *   The amount being charged.
   *
   * @return integer
   *   The Stripe formatted amount.
   */
  protected function formatNumber($amount) {
    $amount = $amount * 100;
    $amount = number_format($amount, 0, '.', '');
    return $amount;
  }
ptmkenny’s picture

Ok, so the code presupposes all currencies have two decimal places.

On the currencies configuration screen, you can set the number of fraction digits per currency, so the module needs to take this into account.

bojanz’s picture

Yeah.

$currency_storage = $this->entityTypeManager->getStorage('commerce_currency');
$currency = $currency_storage->load($amount->getCurrencyCode());
$fraction_digits = $currency->getFractionDigits();
if ($fraction_digits > 0) {
  $amount = $amount->multiply($fraction_digits);
}
return round($amount->getNumber(), 0);

This feels like something that should be easier (perhaps with a PaymentGatewayBase helper?). In any case, let's fix Stripe first.

ptmkenny’s picture

Status: Active » Needs review
FileSize
1.77 KB

Patch based on code by bojanz. I had to make some changes because in formatNumber, $amount is an int not an object. Tested with yen and dollars, appears to be working OK for both.

ptmkenny’s picture

Second patch, left some debugging code in the first, sorry.

ptmkenny’s picture

One more patch, this time fixing a stray space.

ptmkenny’s picture

I updated the patch to get the currency based on the $payment object; this way, it will still be easy to call formatNumber() because you won't need to get the $currencycode first (which is what the previous patch required).

bojanz’s picture

Status: Needs review » Needs work

We should be passing the entire Price object and getting both the number and currency code from there. No need to look at the payment.

bojanz’s picture

Status: Needs work » Needs review
FileSize
3.13 KB

Can you confirm that this works?

bojanz’s picture

FileSize
2.28 KB

Added the helper to Commerce 2.2.
Update Commerce, and then test the attached patch.

ptmkenny’s picture

Status: Needs review » Reviewed & tested by the community

@bojanz I tested the patch in #11 with Commerce 2.2 by purchasing products in JPY and then again in USD; in both cases, the currency amounts were correct. Thank you!

  • bojanz committed 057ee4f on 8.x-1.x authored by ptmkenny
    Issue #2913605 by ptmkenny, bojanz: Yen currency is processed...
bojanz’s picture

Status: Reviewed & tested by the community » Fixed

Committed. Thank you for your work.

Status: Fixed » Closed (fixed)

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