Skip to content

Commit

Permalink
Added currency code to fee breakdown when currency symbol is same (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
zmaglica authored Jan 17, 2025
1 parent 30643ff commit 50584f1
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 59 deletions.
4 changes: 4 additions & 0 deletions changelog/fix-10006-add-currency-to-fee-details-in-order-note
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

Add currency code to fee breakdown when multi-currency is enabled, and currencies share the same symbol.
21 changes: 18 additions & 3 deletions client/payment-details/timeline/map-events.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { getAdminUrl } from 'wcpay/utils';
import { ShieldIcon } from 'wcpay/icons';
import { fraudOutcomeRulesetMapping, paymentFailureMapping } from './mappings';
import { formatDateTimeFromTimestamp } from 'wcpay/utils/date-time';
import { hasSameSymbol } from 'multi-currency/utils/currency';

/**
* Creates a timeline item about a payment status change
Expand Down Expand Up @@ -279,12 +280,19 @@ export const composeFeeString = ( event ) => {
);
}

const hasIdenticalSymbol = hasSameSymbol(
event.transaction_details.store_currency,
event.transaction_details.customer_currency
);

return sprintf(
'%1$s (%2$f%% + %3$s): %4$s',
'%1$s (%2$f%% + %3$s%4$s): %5$s%6$s',
baseFeeLabel,
formatFee( percentage ),
formatCurrency( fixed, fixedCurrency ),
formatCurrency( -feeAmount, feeCurrency )
hasIdenticalSymbol ? ` ${ fixedCurrency }` : '',
formatCurrency( -feeAmount, feeCurrency ),
hasIdenticalSymbol ? ` ${ feeCurrency }` : ''
);
};

Expand Down Expand Up @@ -453,7 +461,14 @@ export const feeBreakdown = ( event ) => {
} = fee;

const percentageRateFormatted = formatFee( percentageRate );
const fixedRateFormatted = formatCurrency( fixedRate, currency );
const fixedRateFormatted = `${ formatCurrency( fixedRate, currency ) }${
hasSameSymbol(
event.transaction_details.store_currency,
event.transaction_details.customer_currency
)
? ` ${ currency.toUpperCase() }`
: ''
}`;

const label = sprintf(
feeLabelMapping( fixedRate, isCapped )[ labelType ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ describe( 'Strings in captured events', () => {
decimalSeparator: '.',
precision: 2,
},
CA: {
code: 'CAD',
symbol: '$',
symbolPosition: 'left',
thousandSeparator: ',',
decimalSeparator: '.',
precision: 2,
},
JP: {
code: 'JPY',
symbol: '¥',
Expand Down
27 changes: 23 additions & 4 deletions includes/class-wc-payments-captured-event-note.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ public function generate_html_note(): string {

$html = '';
foreach ( $lines as $line ) {
$html .= self::HTML_BR . $line . PHP_EOL;
$html .= '<p>' . $line . '</p>' . PHP_EOL;
}

return '<div class="captured-event-details" style="line-height: 0.8;padding-top: 15px;">' . PHP_EOL
return '<div class="captured-event-details">' . PHP_EOL
. $html
. '</div>';
}
Expand Down Expand Up @@ -123,13 +123,16 @@ public function compose_fee_string(): string {
WC_Payments_Utils::format_currency( - $fee_amount, $fee_currency )
);
}
$is_same_symbol = $this->has_same_currency_symbol( $data['transaction_details']['store_currency'], $data['transaction_details']['customer_currency'] );

return sprintf(
'%1$s (%2$s%% + %3$s): %4$s',
'%1$s (%2$s%% + %3$s%4$s): %5$s%6$s',
$base_fee_label,
self::format_fee( $percentage ),
WC_Payments_Utils::format_currency( $fixed, $fixed_currency ),
WC_Payments_Utils::format_currency( - $fee_amount, $fee_currency )
$is_same_symbol ? ' ' . $data['transaction_details']['customer_currency'] : '',
WC_Payments_Utils::format_currency( -$fee_amount, $fee_currency ),
$is_same_symbol ? " $fee_currency" : ''
);
}

Expand Down Expand Up @@ -238,6 +241,10 @@ public function get_fee_breakdown() {
$currency
);

if ( $this->has_same_currency_symbol( $data['transaction_details']['customer_currency'], $data['transaction_details']['store_currency'] ) ) {
$fix_rate_formatted = $fix_rate_formatted . ' ' . $data['transaction_details']['store_currency'];
}

$label = sprintf(
$this->fee_label_mapping( $fixed_rate, $is_capped )[ $label_type ],
$percentage_rate_formatted,
Expand Down Expand Up @@ -442,4 +449,16 @@ private function format_explicit_currency_with_base( float $amount, string $curr

return WC_Payments_Utils::format_explicit_currency( $amount, $currency, $skip_symbol, $custom_format );
}

/**
* Compare does two currencies have the same symbol.
*
* @param string $base_currency Base currency.
* @param string $currency Currency to compare.
*
* @return bool
*/
private function has_same_currency_symbol( string $base_currency, string $currency ): bool {
return strcasecmp( $base_currency, $currency ) !== 0 && get_woocommerce_currency_symbol( $base_currency ) === get_woocommerce_currency_symbol( $currency );
}
}
26 changes: 26 additions & 0 deletions includes/multi-currency/client/utils/currency/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,29 @@ function htmlDecode( input ) {
const doc = new DOMParser().parseFromString( input, 'text/html' );
return doc.documentElement.textContent;
}

/**
* Checks if two currencies share the same symbol. Don't use this function to compare the same currency.
*
* @param {string} currencyCode1 First currency code
* @param {string} currencyCode2 Second currency code
*
* @return {boolean} True if currencies share same symbol, false otherwise
*/
export const hasSameSymbol = ( currencyCode1, currencyCode2 ) => {
currencyCode1 = currencyCode1.toUpperCase();
currencyCode2 = currencyCode2.toUpperCase();
if ( currencyCode1 === currencyCode2 ) {
return false;
}
const { currencyData } = wcpaySettings;

const currency1 = find( currencyData, { code: currencyCode1 } );
const currency2 = find( currencyData, { code: currencyCode2 } );

if ( ! currency1 || ! currency2 ) {
return false;
}

return currency1.symbol === currency2.symbol;
};
99 changes: 47 additions & 52 deletions tests/fixtures/captured-payments/foreign-card.json
Original file line number Diff line number Diff line change
@@ -1,60 +1,55 @@
{
"title": "Payment with a foreign card",
"capturedEvent": {
"type": "captured",
"amount": 13000,
"amount_captured": 13000,
"fee": 676,
"fee_rates": {
"percentage": 0.049,
"fixed": 30,
"fixed_currency": "USD",
"history": [
{
"type": "base",
"percentage_rate": 0.029,
"fixed_rate": 30,
"currency": "usd"
},
{
"type": "additional",
"additional_type": "international",
"percentage_rate": 0.01,
"fixed_rate": 0,
"currency": "usd"
},
{
"type": "additional",
"additional_type": "fx",
"percentage_rate": 0.01,
"fixed_rate": 0,
"currency": "usd"
}
]
"title": "Payment with foreign card",
"capturedEvent":
{
"type": "captured",
"amount": 1800,
"amount_captured": 1800,
"fee": 109,
"fee_rates": {
"percentage": 0.044,
"fixed": 30,
"fixed_currency": "USD",
"history": [
{
"type": "base",
"additional_type": "",
"fee_id": "base-us-card-fee",
"percentage_rate": 0.029,
"fixed_rate": 30,
"currency": "usd"
},
{
"type": "additional",
"additional_type": "international",
"fee_id": "additional-us-intl-fee",
"percentage_rate": 0.015,
"fixed_rate": 0,
"currency": "usd"
}
]
},
"currency": "USD",
"datetime": 1736869781,
"deposit": null,
"transaction_id": "txn_3QhCN7R3NO9FvHYd0wKleSrw",
"transaction_details": {
"customer_currency": "USD",
"customer_amount": 1800,
"customer_amount_captured": 1800,
"customer_fee": 109,
"store_currency": "USD",
"store_amount": 1800,
"store_amount_captured": 1800,
"store_fee": 109
}
},
"currency": "CAD",
"datetime": 1651997332,
"deposit": null,
"transaction_id": "txn_3Kx5Ae2EFxam75ai0P2BCbp0",
"transaction_details": {
"customer_currency": "CAD",
"customer_amount": 13000,
"customer_amount_captured": 13000,
"customer_fee": 676,
"store_currency": "USD",
"store_amount": 10071,
"store_amount_captured": 10071,
"store_fee": 524
}
},
"expectation": {
"fxString": "1.00 CAD → 0.774692 USD: $100.71 USD",
"feeString": "Fee (4.9% + $0.30): -$5.24",
"feeString": "Fee (4.4% + $0.30): -$1.09",
"feeBreakdown": {
"base": "Base fee: 2.9% + $0.30",
"additional-international": "International card fee: 1%",
"additional-fx": "Currency conversion fee: 1%"
"additional-international": "International card fee: 1.5%"
},
"netString": "Net payout: $95.47 USD"
"netString": "Net payout: $16.91 USD"
}
}
56 changes: 56 additions & 0 deletions tests/fixtures/captured-payments/fx-same-currency-symbol.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"title": "FX Payment with a same currency symbol but different currency",
"capturedEvent":
{
"type": "captured",
"amount": 2400,
"amount_captured": 2400,
"fee": 132,
"fee_rates": {
"percentage": 0.039,
"fixed": 39,
"fixed_currency": "CAD",
"history": [
{
"type": "base",
"additional_type": "",
"fee_id": "base-us-card-fee",
"percentage_rate": 0.029,
"fixed_rate": 30,
"currency": "usd"
},
{
"type": "additional",
"additional_type": "fx",
"fee_id": "additional-us-card-fx-fee",
"percentage_rate": 0.01,
"fixed_rate": 0,
"currency": "usd"
}
]
},
"currency": "CAD",
"datetime": 1736871090,
"deposit": null,
"transaction_id": "txn_3QhCiER3NO9FvHYd2DQY4k1S",
"transaction_details": {
"customer_currency": "CAD",
"customer_amount": 2400,
"customer_amount_captured": 2400,
"customer_fee": 132,
"store_currency": "USD",
"store_amount": 1672,
"store_amount_captured": 1672,
"store_fee": 92
}
},
"expectation": {
"fxString": "1.00 CAD → 0.696667 USD: $16.72 USD",
"feeString": "Fee (3.9% + $0.39 CAD): -$0.92 USD",
"feeBreakdown": {
"base": "Base fee: 2.9% + $0.30 USD",
"additional-fx": "Currency conversion fee: 1%"
},
"netString": "Net payout: $15.80 USD"
}
}

0 comments on commit 50584f1

Please sign in to comment.