<?php
/**
* Currency converter to and from currency subunits utility.
*
* @package Stripe\StripeTaxForWooCommerce\Utils
*/
namespace Stripe\StripeTaxForWooCommerce\Utils;
defined( 'ABSPATH' ) || exit;
/**
* Currency converter to and from currency subunits utility.
*/
abstract class Amount_Utility {
// See https://docs.stripe.com/currencies#presentment-currencies.
public const CURRENCY_SUBDIVISION_MULTIPLIER = array(
'' => 2,
'BIF' => 0,
'CLP' => 0,
'DJF' => 0,
'GNF' => 0,
'JPY' => 0,
'KMF' => 0,
'KRW' => 0,
'MGA' => 0,
'PYG' => 0,
'RWF' => 0,
'UGX' => 0,
'VND' => 0,
'VUV' => 0,
'XAF' => 0,
'XOF' => 0,
'XPF' => 0,
);
/**
* Currency number of decimals
*
* @var int $num_decimals Currency number of decimals
*/
protected static $num_decimals;
/**
* Currency number of decimals as multiplier
*
* @var int $decimals_multiplier Currency number of decimals as multiplier
*/
protected static $decimals_multiplier;
/**
* Initialise internal number of decimals based on currency (Stripe minor units)
*
* @param string $currency The currency.
*/
protected static function init_internals( $currency = '' ) {
$currency = strtoupper( (string) $currency );
if ( isset( static::CURRENCY_SUBDIVISION_MULTIPLIER[ $currency ] ) ) {
static::$num_decimals = static::CURRENCY_SUBDIVISION_MULTIPLIER[ $currency ];
} else {
// Fallback mos currencies use 2 decimals.
static::$num_decimals = static::CURRENCY_SUBDIVISION_MULTIPLIER[''];
}
static::$decimals_multiplier = pow( 10, static::$num_decimals );
}
/**
* Rounds an amount
*
* @param float $amount The amount.
*/
public static function round( $amount ) {
// Ensure we default (2 decimals) even if nothing called init yet.
if ( ! isset( static::$num_decimals ) || ! isset( static::$decimals_multiplier ) ) {
static::init_internals( '' );
}
$amount_as_string = number_format( $amount, static::$num_decimals, '.', '' );
return (float) $amount_as_string;
}
/**
* Converts an amount from cents
*
* @param float|int $amount The amount in minor units.
* @param string $currency The currency.
*
* @return float Amount in major units.
*/
public static function from_cents( $amount, $currency ) {
// Initialise decimals based on currency, not WC settings.
static::init_internals( $currency );
// For zero-decimal currencies (JPY, etc.), minor == major.
if ( 0 === static::$num_decimals ) {
return (float) $amount;
}
$amount_as_string = number_format( $amount, 0, '', '' );
$amount_num_decimals = strlen( $amount_as_string );
if ( $amount_num_decimals <= static::$num_decimals ) {
$integer_part = '0';
for ( $i = $amount_num_decimals; $i < static::$num_decimals; $i++ ) {
$amount_as_string = '0' . $amount_as_string;
}
$decimal_part = $amount_as_string;
} else {
$integer_part = substr( $amount_as_string, 0, -static::$num_decimals );
$decimal_part = substr( $amount_as_string, -static::$num_decimals );
}
$units = (float) ( $integer_part . '.' . $decimal_part );
return $units;
}
/**
* Converts an amount to cents
*
* @param float $amount The amount.
* @param string $currency The currency.
*
* @return int Amount in minor units.
*/
public static function to_cents( $amount, $currency ) {
// Always initialise with the correct currency, independent of WC decimals.
static::init_internals( $currency );
return (int) round( $amount * static::$decimals_multiplier );
}
}