From 03b12d2b27e9d4038e2b02b303a0401160ebc632 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 20 Jan 2023 15:44:53 -0300 Subject: fix wrong fee calculation --- .../src/wallet/Transaction.tsx | 453 ++++++++++----------- 1 file changed, 212 insertions(+), 241 deletions(-) (limited to 'packages/taler-wallet-webextension/src/wallet/Transaction.tsx') diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx index c9e7bbe85..94d853d9a 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -28,17 +28,13 @@ import { stringifyPaytoUri, TalerProtocolTimestamp, Transaction, - TransactionDeposit, - TransactionRefresh, - TransactionRefund, - TransactionTip, TransactionType, TranslatedString, WithdrawalType, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { styled } from "@linaria/react"; -import { differenceInSeconds, isAfter, isFuture, isPast } from "date-fns"; +import { differenceInSeconds, isPast } from "date-fns"; import { ComponentChildren, Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import emptyImg from "../../static/img/empty.png"; @@ -68,6 +64,7 @@ import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; import { SafeHandler } from "../mui/handlers.js"; import { Pages } from "../NavigationBar.js"; +import { assertUnreachable } from "../utils/index.js"; interface Props { tid: string; @@ -392,9 +389,10 @@ export function TransactionView({ const { i18n } = useTranslationContext(); const { safely } = useAlertContext(); + const raw = Amounts.parseOrThrow(transaction.amountRaw); + const effective = Amounts.parseOrThrow(transaction.amountEffective); + if (transaction.type === TransactionType.Withdrawal) { - const total = Amounts.parseOrThrow(transaction.amountEffective); - const chosen = Amounts.parseOrThrow(transaction.amountRaw); return ( {transaction.exchangeBaseUrl} @@ -417,7 +415,7 @@ export function TransactionView({ .type === WithdrawalType.ManualTransfer ? ( } /> @@ -517,15 +512,9 @@ export function TransactionView({ ? undefined : Amounts.parseOrThrow(transaction.refundPending); - const price = { - raw: Amounts.parseOrThrow(transaction.amountRaw), - effective: Amounts.parseOrThrow(transaction.amountEffective), - }; - const refund = { - raw: Amounts.parseOrThrow(transaction.totalRefundRaw), - effective: Amounts.parseOrThrow(transaction.totalRefundEffective), - }; - const total = Amounts.sub(price.effective, refund.effective).amount; + const effectiveRefund = Amounts.parseOrThrow( + transaction.totalRefundEffective, + ); return (
@@ -632,8 +621,8 @@ export function TransactionView({ title={i18n.str`Details`} text={ @@ -645,7 +634,6 @@ export function TransactionView({ } if (transaction.type === TransactionType.Deposit) { - const total = Amounts.parseOrThrow(transaction.amountRaw); const payto = parsePaytoUri(transaction.targetPaytoUri); const wireTime = AbsoluteTime.fromTimestamp( @@ -663,7 +651,7 @@ export function TransactionView({
{!payto ? transaction.targetPaytoUri : } @@ -671,7 +659,11 @@ export function TransactionView({ {payto && } } + text={ + + } kind="neutral" /> {!shouldBeWired ? ( @@ -712,11 +704,6 @@ export function TransactionView({ } if (transaction.type === TransactionType.Refresh) { - const total = Amounts.sub( - Amounts.parseOrThrow(transaction.amountRaw), - Amounts.parseOrThrow(transaction.amountEffective), - ).amount; - return ( {transaction.exchangeBaseUrl}
} + text={ + + } /> ); } if (transaction.type === TransactionType.Tip) { - const total = Amounts.parseOrThrow(transaction.amountEffective); - return ( {transaction.merchantBaseUrl} @@ -767,14 +756,15 @@ export function TransactionView({ /> */} } + text={ + + } /> ); } if (transaction.type === TransactionType.Refund) { - const total = Amounts.parseOrThrow(transaction.amountEffective); return ( {transaction.info.summary} @@ -817,48 +807,17 @@ export function TransactionView({ /> } + text={ + + } /> ); } - function ShowQrWithCopy({ text }: { text: string }): VNode { - const [showing, setShowing] = useState(false); - async function copy(): Promise { - navigator.clipboard.writeText(text); - } - async function toggle(): Promise { - setShowing((s) => !s); - } - if (showing) { - return ( -
- - - -
- ); - } - return ( -
-
{text.substring(0, 64)}...
- - -
- ); - } - if (transaction.type === TransactionType.PeerPullCredit) { - const total = Amounts.parseOrThrow(transaction.amountEffective); return ( Invoice @@ -900,10 +859,7 @@ export function TransactionView({ title={i18n.str`Details`} text={ } /> @@ -912,7 +868,6 @@ export function TransactionView({ } if (transaction.type === TransactionType.PeerPullDebit) { - const total = Amounts.parseOrThrow(transaction.amountEffective); return ( Invoice @@ -946,16 +901,14 @@ export function TransactionView({ title={i18n.str`Details`} text={ } /> ); } + if (transaction.type === TransactionType.PeerPushDebit) { const total = Amounts.parseOrThrow(transaction.amountEffective); return ( @@ -998,10 +951,7 @@ export function TransactionView({ title={i18n.str`Details`} text={ } /> @@ -1010,7 +960,6 @@ export function TransactionView({ } if (transaction.type === TransactionType.PeerPushCredit) { - const total = Amounts.parseOrThrow(transaction.amountEffective); return ( Transfer @@ -1044,17 +993,14 @@ export function TransactionView({ title={i18n.str`Details`} text={ } /> ); } - return
; + assertUnreachable(transaction); } export function MerchantDetails({ @@ -1231,19 +1177,37 @@ export function ExchangeDetails({ exchange }: { exchange: string }): VNode { } export interface AmountWithFee { - effective: AmountJson; - raw: AmountJson; + value: AmountJson; + fee: AmountJson; + total: AmountJson; + maxFrac: number; } -export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode { - const { i18n } = useTranslationContext(); - - const fee = Amounts.sub(amount.raw, amount.effective).amount; - - const maxFrac = [amount.raw, amount.effective, fee] +export function getAmountWithFee( + effective: AmountJson, + raw: AmountJson, + direction: "credit" | "debit", +): AmountWithFee { + const fee = + direction === "credit" + ? Amounts.sub(raw, effective).amount + : Amounts.sub(effective, raw).amount; + + const maxFrac = [effective, raw, fee] .map((a) => Amounts.maxFractionalDigits(a)) .reduce((c, p) => Math.max(c, p), 0); + return { + total: effective, + value: raw, + fee, + maxFrac, + }; +} + +export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode { + const { i18n } = useTranslationContext(); + return ( @@ -1251,17 +1215,17 @@ export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode { Invoice - + - {Amounts.isNonZero(fee) && ( + {Amounts.isNonZero(amount.fee) && ( - Transaction fees + Fees - + )} @@ -1275,7 +1239,7 @@ export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode { Total - + @@ -1285,12 +1249,6 @@ export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode { export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode { const { i18n } = useTranslationContext(); - const fee = Amounts.sub(amount.effective, amount.raw).amount; - - const maxFrac = [amount.raw, amount.effective, fee] - .map((a) => Amounts.maxFractionalDigits(a)) - .reduce((c, p) => Math.max(c, p), 0); - return ( @@ -1298,17 +1256,17 @@ export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode { Transfer - + - {Amounts.isNonZero(fee) && ( + {Amounts.isNonZero(amount.fee) && ( - Transaction fees + Fees - + )} @@ -1322,7 +1280,7 @@ export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode { Total - + @@ -1332,12 +1290,12 @@ export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode { export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode { const { i18n } = useTranslationContext(); - const fee = Amounts.sub(amount.raw, amount.effective).amount; - - const maxFrac = [amount.raw, amount.effective, fee] + const maxFrac = [amount.fee, amount.fee] .map((a) => Amounts.maxFractionalDigits(a)) .reduce((c, p) => Math.max(c, p), 0); + const total = Amounts.add(amount.value, amount.fee).amount; + return ( @@ -1345,17 +1303,17 @@ export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode { Withdraw - + - {Amounts.isNonZero(fee) && ( + {Amounts.isNonZero(amount.fee) && ( - Transaction fees + Fees - + )} @@ -1369,7 +1327,7 @@ export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode { Total - + @@ -1378,24 +1336,18 @@ export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode { export function PurchaseDetails({ price, - refund, + effectiveRefund, info, proposalId, }: { price: AmountWithFee; - refund?: AmountWithFee; + effectiveRefund?: AmountJson; info: OrderShortInfo; proposalId: string; }): VNode { const { i18n } = useTranslationContext(); - const partialFee = Amounts.sub(price.effective, price.raw).amount; - - const refundFee = !refund - ? Amounts.zeroOfCurrency(price.effective.currency) - : Amounts.sub(refund.raw, refund.effective).amount; - - const fee = Amounts.sum([partialFee, refundFee]).amount; + const total = Amounts.add(price.value, price.fee).amount; const hasProducts = info.products && info.products.length > 0; @@ -1406,10 +1358,6 @@ export function PurchaseDetails({ return; }; - const total = !refund - ? price.effective - : Amounts.sub(price.effective, refund.effective).amount; - return ( @@ -1417,43 +1365,73 @@ export function PurchaseDetails({ Price - + - - {refund && Amounts.isNonZero(refund.raw) && ( - - - Refunded - - - - - - )} - {Amounts.isNonZero(fee) && ( + {Amounts.isNonZero(price.fee) && ( Transaction fees - + )} - - -
- - - - - Total - - - - - + {effectiveRefund && Amounts.isNonZero(effectiveRefund) ? ( + + + +
+ + + + + Subtotal + + + + + + + + Refunded + + + + + + + +
+ + + + + Total + + + + + +
+ ) : ( + + + +
+ + + + + Total + + + + + +
+ )} {hasProducts && ( @@ -1508,39 +1486,27 @@ export function PurchaseDetails({ ); } -function RefundDetails({ - transaction, -}: { - transaction: TransactionRefund; -}): VNode { +function RefundDetails({ amount }: { amount: AmountWithFee }): VNode { const { i18n } = useTranslationContext(); - const r = Amounts.parseOrThrow(transaction.amountRaw); - const e = Amounts.parseOrThrow(transaction.amountEffective); - const fee = Amounts.sub(r, e).amount; - - const maxFrac = [r, e, fee] - .map((a) => Amounts.maxFractionalDigits(a)) - .reduce((c, p) => Math.max(c, p), 0); - return ( - Amount + Refund - + - {Amounts.isNonZero(fee) && ( + {Amounts.isNonZero(amount.fee) && ( - Transaction fees + Fees - + )} @@ -1554,45 +1520,34 @@ function RefundDetails({ Total - + ); } -function DepositDetails({ - transaction, -}: { - transaction: TransactionDeposit; -}): VNode { +function DepositDetails({ amount }: { amount: AmountWithFee }): VNode { const { i18n } = useTranslationContext(); - const r = Amounts.parseOrThrow(transaction.amountRaw); - const e = Amounts.parseOrThrow(transaction.amountEffective); - const fee = Amounts.sub(e, r).amount; - - const maxFrac = [r, e, fee] - .map((a) => Amounts.maxFractionalDigits(a)) - .reduce((c, p) => Math.max(c, p), 0); return ( - Amount + Deposit - + - {Amounts.isNonZero(fee) && ( + {Amounts.isNonZero(amount.fee) && ( - Transaction fees + Fees - + )} @@ -1606,43 +1561,32 @@ function DepositDetails({ Total transfer - + ); } -function RefreshDetails({ - transaction, -}: { - transaction: TransactionRefresh; -}): VNode { - const { i18n } = useTranslationContext(); - - const r = Amounts.parseOrThrow(transaction.amountRaw); - const e = Amounts.parseOrThrow(transaction.amountEffective); - const fee = Amounts.sub(r, e).amount; - const maxFrac = [r, e, fee] - .map((a) => Amounts.maxFractionalDigits(a)) - .reduce((c, p) => Math.max(c, p), 0); +function RefreshDetails({ amount }: { amount: AmountWithFee }): VNode { + const { i18n } = useTranslationContext(); return ( - Amount + Refresh - + - Transaction fees + Fees - + @@ -1655,42 +1599,34 @@ function RefreshDetails({ Total - + ); } -function TipDetails({ transaction }: { transaction: TransactionTip }): VNode { +function TipDetails({ amount }: { amount: AmountWithFee }): VNode { const { i18n } = useTranslationContext(); - const r = Amounts.parseOrThrow(transaction.amountRaw); - const e = Amounts.parseOrThrow(transaction.amountEffective); - const fee = Amounts.sub(r, e).amount; - - const maxFrac = [r, e, fee] - .map((a) => Amounts.maxFractionalDigits(a)) - .reduce((c, p) => Math.max(c, p), 0); - return ( - Amount + Tip - + - {Amounts.isNonZero(fee) && ( + {Amounts.isNonZero(amount.fee) && ( - Transaction fees + Fees - + )} @@ -1704,7 +1640,7 @@ function TipDetails({ transaction }: { transaction: TransactionTip }): VNode { Total - + @@ -1778,3 +1714,38 @@ function NicePayto({ payto }: { payto: PaytoUri }): VNode { } return {stringifyPaytoUri(payto)}; } + +function ShowQrWithCopy({ text }: { text: string }): VNode { + const [showing, setShowing] = useState(false); + const { i18n } = useTranslationContext(); + async function copy(): Promise { + navigator.clipboard.writeText(text); + } + async function toggle(): Promise { + setShowing((s) => !s); + } + if (showing) { + return ( +
+ + + +
+ ); + } + return ( +
+
{text.substring(0, 64)}...
+ + +
+ ); +} -- cgit v1.2.3