show refund info in purchase
notify refund pending with accept button on the purchase details better payto box
This commit is contained in:
parent
ced08c502f
commit
029340469a
@ -244,6 +244,11 @@ export interface TransactionPayment extends TransactionCommon {
|
|||||||
* Amount pending to be picked up
|
* Amount pending to be picked up
|
||||||
*/
|
*/
|
||||||
refundPending: AmountString | undefined;
|
refundPending: AmountString | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to applied refunds
|
||||||
|
*/
|
||||||
|
refunds: RefundInfoShort[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderShortInfo {
|
export interface OrderShortInfo {
|
||||||
@ -305,6 +310,13 @@ export interface OrderShortInfo {
|
|||||||
fulfillmentMessage_i18n?: InternationalizedString;
|
fulfillmentMessage_i18n?: InternationalizedString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RefundInfoShort {
|
||||||
|
transactionId: string,
|
||||||
|
timestamp: TalerProtocolTimestamp,
|
||||||
|
amountEffective: AmountString,
|
||||||
|
amountRaw: AmountString,
|
||||||
|
}
|
||||||
|
|
||||||
export interface TransactionRefund extends TransactionCommon {
|
export interface TransactionRefund extends TransactionCommon {
|
||||||
type: TransactionType.Refund;
|
type: TransactionType.Refund;
|
||||||
|
|
||||||
|
@ -799,6 +799,15 @@ export const codecForApplyRefundRequest = (): Codec<ApplyRefundRequest> =>
|
|||||||
.property("talerRefundUri", codecForString())
|
.property("talerRefundUri", codecForString())
|
||||||
.build("ApplyRefundRequest");
|
.build("ApplyRefundRequest");
|
||||||
|
|
||||||
|
export interface ApplyRefundFromPurchaseIdRequest {
|
||||||
|
purchaseId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const codecForApplyRefundFromPurchaseIdRequest = (): Codec<ApplyRefundFromPurchaseIdRequest> =>
|
||||||
|
buildCodecForObject<ApplyRefundFromPurchaseIdRequest>()
|
||||||
|
.property("purchaseId", codecForString())
|
||||||
|
.build("ApplyRefundFromPurchaseIdRequest");
|
||||||
|
|
||||||
export interface GetWithdrawalDetailsForUriRequest {
|
export interface GetWithdrawalDetailsForUriRequest {
|
||||||
talerWithdrawUri: string;
|
talerWithdrawUri: string;
|
||||||
restrictAge?: number;
|
restrictAge?: number;
|
||||||
|
@ -573,7 +573,7 @@ export async function applyRefund(
|
|||||||
throw Error("invalid refund URI");
|
throw Error("invalid refund URI");
|
||||||
}
|
}
|
||||||
|
|
||||||
let purchase = await ws.db
|
const purchase = await ws.db
|
||||||
.mktx((x) => ({
|
.mktx((x) => ({
|
||||||
purchases: x.purchases,
|
purchases: x.purchases,
|
||||||
}))
|
}))
|
||||||
@ -590,7 +590,15 @@ export async function applyRefund(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const proposalId = purchase.proposalId;
|
return applyRefundFromPurchaseId(ws, purchase.proposalId)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function applyRefundFromPurchaseId(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
proposalId: string,
|
||||||
|
): Promise<ApplyRefundResponse> {
|
||||||
|
|
||||||
|
logger.trace("applying refund for purchase", proposalId);
|
||||||
|
|
||||||
logger.info("processing purchase for refund");
|
logger.info("processing purchase for refund");
|
||||||
const success = await ws.db
|
const success = await ws.db
|
||||||
@ -620,7 +628,7 @@ export async function applyRefund(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
purchase = await ws.db
|
const purchase = await ws.db
|
||||||
.mktx((x) => ({
|
.mktx((x) => ({
|
||||||
purchases: x.purchases,
|
purchases: x.purchases,
|
||||||
}))
|
}))
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
Logger,
|
Logger,
|
||||||
OrderShortInfo,
|
OrderShortInfo,
|
||||||
PaymentStatus,
|
PaymentStatus,
|
||||||
|
RefundInfoShort,
|
||||||
Transaction,
|
Transaction,
|
||||||
TransactionsRequest,
|
TransactionsRequest,
|
||||||
TransactionsResponse,
|
TransactionsResponse,
|
||||||
@ -306,6 +307,7 @@ export async function getTransactions(
|
|||||||
|
|
||||||
let totalRefundRaw = Amounts.getZero(contractData.amount.currency);
|
let totalRefundRaw = Amounts.getZero(contractData.amount.currency);
|
||||||
let totalRefundEffective = Amounts.getZero(contractData.amount.currency);
|
let totalRefundEffective = Amounts.getZero(contractData.amount.currency);
|
||||||
|
const refunds: RefundInfoShort[] = []
|
||||||
|
|
||||||
for (const groupKey of refundGroupKeys.values()) {
|
for (const groupKey of refundGroupKeys.values()) {
|
||||||
const refundTombstoneId = makeEventId(
|
const refundTombstoneId = makeEventId(
|
||||||
@ -345,6 +347,13 @@ export async function getTransactions(
|
|||||||
refund.totalRefreshCostBound,
|
refund.totalRefreshCostBound,
|
||||||
).amount,
|
).amount,
|
||||||
).amount;
|
).amount;
|
||||||
|
|
||||||
|
refunds.push({
|
||||||
|
transactionId: refundTransactionId,
|
||||||
|
timestamp: r0.obtainedTime,
|
||||||
|
amountEffective: Amounts.stringify(amountEffective),
|
||||||
|
amountRaw: Amounts.stringify(amountRaw),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!r0) {
|
if (!r0) {
|
||||||
@ -353,7 +362,6 @@ export async function getTransactions(
|
|||||||
|
|
||||||
totalRefundRaw = Amounts.add(totalRefundRaw, amountRaw).amount;
|
totalRefundRaw = Amounts.add(totalRefundRaw, amountRaw).amount;
|
||||||
totalRefundEffective = Amounts.add(totalRefundEffective, amountEffective).amount;
|
totalRefundEffective = Amounts.add(totalRefundEffective, amountEffective).amount;
|
||||||
|
|
||||||
transactions.push({
|
transactions.push({
|
||||||
type: TransactionType.Refund,
|
type: TransactionType.Refund,
|
||||||
info,
|
info,
|
||||||
@ -382,10 +390,11 @@ export async function getTransactions(
|
|||||||
pending:
|
pending:
|
||||||
!pr.timestampFirstSuccessfulPay &&
|
!pr.timestampFirstSuccessfulPay &&
|
||||||
pr.abortStatus === AbortStatus.None,
|
pr.abortStatus === AbortStatus.None,
|
||||||
|
refunds,
|
||||||
timestamp: pr.timestampAccept,
|
timestamp: pr.timestampAccept,
|
||||||
transactionId: paymentTransactionId,
|
transactionId: paymentTransactionId,
|
||||||
proposalId: pr.proposalId,
|
proposalId: pr.proposalId,
|
||||||
info: info,
|
info,
|
||||||
frozen: pr.payFrozen ?? false,
|
frozen: pr.payFrozen ?? false,
|
||||||
...(err ? { error: err } : {}),
|
...(err ? { error: err } : {}),
|
||||||
});
|
});
|
||||||
|
@ -33,6 +33,7 @@ import {
|
|||||||
codecForAcceptTipRequest,
|
codecForAcceptTipRequest,
|
||||||
codecForAddExchangeRequest,
|
codecForAddExchangeRequest,
|
||||||
codecForAny,
|
codecForAny,
|
||||||
|
codecForApplyRefundFromPurchaseIdRequest,
|
||||||
codecForApplyRefundRequest,
|
codecForApplyRefundRequest,
|
||||||
codecForConfirmPayRequest,
|
codecForConfirmPayRequest,
|
||||||
codecForCreateDepositGroupRequest,
|
codecForCreateDepositGroupRequest,
|
||||||
@ -145,6 +146,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
abortFailedPayWithRefund,
|
abortFailedPayWithRefund,
|
||||||
applyRefund,
|
applyRefund,
|
||||||
|
applyRefundFromPurchaseId,
|
||||||
prepareRefund,
|
prepareRefund,
|
||||||
processPurchaseQueryRefund
|
processPurchaseQueryRefund
|
||||||
} from "./operations/refund.js";
|
} from "./operations/refund.js";
|
||||||
@ -839,6 +841,10 @@ async function dispatchRequestInternal(
|
|||||||
const req = codecForApplyRefundRequest().decode(payload);
|
const req = codecForApplyRefundRequest().decode(payload);
|
||||||
return await applyRefund(ws, req.talerRefundUri);
|
return await applyRefund(ws, req.talerRefundUri);
|
||||||
}
|
}
|
||||||
|
case "applyRefundFromPurchaseId": {
|
||||||
|
const req = codecForApplyRefundFromPurchaseIdRequest().decode(payload);
|
||||||
|
return await applyRefundFromPurchaseId(ws, req.purchaseId);
|
||||||
|
}
|
||||||
case "acceptBankIntegratedWithdrawal": {
|
case "acceptBankIntegratedWithdrawal": {
|
||||||
const req =
|
const req =
|
||||||
codecForAcceptBankIntegratedWithdrawalRequest().decode(payload);
|
codecForAcceptBankIntegratedWithdrawalRequest().decode(payload);
|
||||||
|
@ -92,6 +92,7 @@ const CollasibleBox = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
import arrowDown from "../svg/chevron-down.svg";
|
import arrowDown from "../svg/chevron-down.svg";
|
||||||
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
|
|
||||||
export function PartCollapsible({ text, title, big, showSign }: Props): VNode {
|
export function PartCollapsible({ text, title, big, showSign }: Props): VNode {
|
||||||
const Text = big ? ExtraLargeText : LargeText;
|
const Text = big ? ExtraLargeText : LargeText;
|
||||||
@ -137,27 +138,37 @@ interface PropsPayto {
|
|||||||
}
|
}
|
||||||
export function PartPayto({ payto, kind, big }: PropsPayto): VNode {
|
export function PartPayto({ payto, kind, big }: PropsPayto): VNode {
|
||||||
const Text = big ? ExtraLargeText : LargeText;
|
const Text = big ? ExtraLargeText : LargeText;
|
||||||
let text: string | undefined = undefined;
|
let text: VNode | undefined = undefined;
|
||||||
let title = "";
|
let title = "";
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
if (payto.isKnown) {
|
if (payto.isKnown) {
|
||||||
if (payto.targetType === "x-taler-bank") {
|
if (payto.targetType === "x-taler-bank") {
|
||||||
text = payto.account;
|
text = <Fragment>{payto.account}</Fragment>;
|
||||||
title = "Bank account";
|
title = i18n.str`Bank account`;
|
||||||
} else if (payto.targetType === "bitcoin") {
|
} else if (payto.targetType === "bitcoin") {
|
||||||
text = payto.targetPath;
|
text =
|
||||||
title = "Bitcoin addr";
|
payto.segwitAddrs && payto.segwitAddrs.length > 0 ? (
|
||||||
|
<ul>
|
||||||
|
<li>{payto.targetPath}</li>
|
||||||
|
<li>{payto.segwitAddrs[0]}</li>
|
||||||
|
<li>{payto.segwitAddrs[1]}</li>
|
||||||
|
</ul>
|
||||||
|
) : (
|
||||||
|
<Fragment>{payto.targetPath}</Fragment>
|
||||||
|
);
|
||||||
|
title = i18n.str`Bitcoin address`;
|
||||||
} else if (payto.targetType === "iban") {
|
} else if (payto.targetType === "iban") {
|
||||||
text = payto.targetPath;
|
text = <Fragment>{payto.targetPath}</Fragment>;
|
||||||
title = "IBAN";
|
title = i18n.str`IBAN`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!text) {
|
if (!text) {
|
||||||
text = stringifyPaytoUri(payto);
|
text = <Fragment>{stringifyPaytoUri(payto)}</Fragment>;
|
||||||
title = "Payto URI";
|
title = "Payto URI";
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{ margin: "1em" }}>
|
<div style={{ margin: "1em" }}>
|
||||||
<SmallLightText style={{ margin: ".5em" }}>{title}</SmallLightText>
|
<SmallBoldText>{title}</SmallBoldText>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
|
@ -207,7 +207,7 @@ function TransactionAmount(props: TransactionAmountProps): VNode {
|
|||||||
>
|
>
|
||||||
<ExtraLargeText>
|
<ExtraLargeText>
|
||||||
{sign}
|
{sign}
|
||||||
{Amounts.stringifyValue(props.amount)}
|
{Amounts.stringifyValue(props.amount, 2)}
|
||||||
</ExtraLargeText>
|
</ExtraLargeText>
|
||||||
{props.pending && (
|
{props.pending && (
|
||||||
<div>
|
<div>
|
||||||
|
@ -78,6 +78,7 @@ const exampleData = {
|
|||||||
summary: "the summary",
|
summary: "the summary",
|
||||||
fulfillmentMessage: "",
|
fulfillmentMessage: "",
|
||||||
},
|
},
|
||||||
|
refunds: [],
|
||||||
refundPending: undefined,
|
refundPending: undefined,
|
||||||
totalRefundEffective: "USD:0",
|
totalRefundEffective: "USD:0",
|
||||||
totalRefundRaw: "USD:0",
|
totalRefundRaw: "USD:0",
|
||||||
|
@ -193,7 +193,7 @@ export function HistoryView({
|
|||||||
margin: 8,
|
margin: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Amounts.stringifyValue(currencyAmount)}
|
{Amounts.stringifyValue(currencyAmount, 2)}
|
||||||
</CenteredBoldText>
|
</CenteredBoldText>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -45,7 +45,7 @@ export const TalerBank = createExample(TestedComponent, {
|
|||||||
export const IBAN = createExample(TestedComponent, {
|
export const IBAN = createExample(TestedComponent, {
|
||||||
reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
|
reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
|
||||||
paytoURI: parsePaytoUri(
|
paytoURI: parsePaytoUri(
|
||||||
"payto://iban/ASDQWEASDZXCASDQWE?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
|
"payto://iban/ES8877998399652238?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
|
||||||
),
|
),
|
||||||
amount: {
|
amount: {
|
||||||
currency: "USD",
|
currency: "USD",
|
||||||
|
@ -93,6 +93,7 @@ const exampleData = {
|
|||||||
// address_lines: [""],
|
// address_lines: [""],
|
||||||
// },
|
// },
|
||||||
},
|
},
|
||||||
|
refunds: [],
|
||||||
refundPending: undefined,
|
refundPending: undefined,
|
||||||
totalRefundEffective: "KUDOS:0",
|
totalRefundEffective: "KUDOS:0",
|
||||||
totalRefundRaw: "KUDOS:0",
|
totalRefundRaw: "KUDOS:0",
|
||||||
@ -199,7 +200,7 @@ export const WithdrawPendingManual = createExample(TestedComponent, () => ({
|
|||||||
...exampleData.withdraw,
|
...exampleData.withdraw,
|
||||||
withdrawalDetails: {
|
withdrawalDetails: {
|
||||||
type: WithdrawalType.ManualTransfer,
|
type: WithdrawalType.ManualTransfer,
|
||||||
exchangePaytoUris: ["payto://iban/asdasdasd"],
|
exchangePaytoUris: ["payto://iban/ES8877998399652238"],
|
||||||
reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
|
reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
|
||||||
} as WithdrawalDetails,
|
} as WithdrawalDetails,
|
||||||
pending: true,
|
pending: true,
|
||||||
@ -254,6 +255,14 @@ export const PaymentWithRefund = createExample(TestedComponent, {
|
|||||||
amountRaw: "KUDOS:12",
|
amountRaw: "KUDOS:12",
|
||||||
totalRefundEffective: "KUDOS:1",
|
totalRefundEffective: "KUDOS:1",
|
||||||
totalRefundRaw: "KUDOS:1",
|
totalRefundRaw: "KUDOS:1",
|
||||||
|
refunds: [
|
||||||
|
{
|
||||||
|
transactionId: "1123123",
|
||||||
|
amountRaw: "KUDOS:1",
|
||||||
|
amountEffective: "KUDOS:1",
|
||||||
|
timestamp: TalerProtocolTimestamp.fromSeconds(1546546544),
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -410,6 +419,25 @@ export const PaymentWithLongSummary = createExample(TestedComponent, {
|
|||||||
export const Deposit = createExample(TestedComponent, {
|
export const Deposit = createExample(TestedComponent, {
|
||||||
transaction: exampleData.deposit,
|
transaction: exampleData.deposit,
|
||||||
});
|
});
|
||||||
|
export const DepositTalerBank = createExample(TestedComponent, {
|
||||||
|
transaction: {
|
||||||
|
...exampleData.deposit,
|
||||||
|
targetPaytoUri: "payto://x-taler-bank/bank.demo.taler.net/Exchange",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export const DepositBitcoin = createExample(TestedComponent, {
|
||||||
|
transaction: {
|
||||||
|
...exampleData.deposit,
|
||||||
|
targetPaytoUri:
|
||||||
|
"payto://bitcoin/bcrt1q6ps8qs6v8tkqrnru4xqqqa6rfwcx5ufpdfqht4?amount=BTC:0.1&subject=0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export const DepositIBAN = createExample(TestedComponent, {
|
||||||
|
transaction: {
|
||||||
|
...exampleData.deposit,
|
||||||
|
targetPaytoUri: "payto://iban/ES8877998399652238",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const DepositError = createExample(TestedComponent, {
|
export const DepositError = createExample(TestedComponent, {
|
||||||
transaction: {
|
transaction: {
|
||||||
|
@ -22,6 +22,8 @@ import {
|
|||||||
NotificationType,
|
NotificationType,
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
parsePayUri,
|
parsePayUri,
|
||||||
|
PaytoUri,
|
||||||
|
stringifyPaytoUri,
|
||||||
TalerProtocolTimestamp,
|
TalerProtocolTimestamp,
|
||||||
Transaction,
|
Transaction,
|
||||||
TransactionDeposit,
|
TransactionDeposit,
|
||||||
@ -50,6 +52,7 @@ import {
|
|||||||
ButtonDestructive,
|
ButtonDestructive,
|
||||||
ButtonPrimary,
|
ButtonPrimary,
|
||||||
CenteredDialog,
|
CenteredDialog,
|
||||||
|
HistoryRow,
|
||||||
InfoBox,
|
InfoBox,
|
||||||
ListOfProducts,
|
ListOfProducts,
|
||||||
Overlay,
|
Overlay,
|
||||||
@ -83,7 +86,7 @@ async function getTransaction(tid: string): Promise<Transaction> {
|
|||||||
export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
|
export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const state = useAsyncAsHook(() => getTransaction(tid));
|
const state = useAsyncAsHook(() => getTransaction(tid), [tid]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
wxApi.onUpdateNotification([NotificationType.WithdrawGroupFinished], () => {
|
wxApi.onUpdateNotification([NotificationType.WithdrawGroupFinished], () => {
|
||||||
@ -119,6 +122,7 @@ export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
|
|||||||
onRetry={() =>
|
onRetry={() =>
|
||||||
wxApi.retryTransaction(tid).then(() => goToWalletHistory(currency))
|
wxApi.retryTransaction(tid).then(() => goToWalletHistory(currency))
|
||||||
}
|
}
|
||||||
|
onRefund={(id) => wxApi.applyRefundFromPurchaseId(id)}
|
||||||
onBack={() => goToWalletHistory(currency)}
|
onBack={() => goToWalletHistory(currency)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -128,6 +132,7 @@ export interface WalletTransactionProps {
|
|||||||
transaction: Transaction;
|
transaction: Transaction;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
onRetry: () => void;
|
onRetry: () => void;
|
||||||
|
onRefund: (id: string) => void;
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +148,7 @@ export function TransactionView({
|
|||||||
transaction,
|
transaction,
|
||||||
onDelete,
|
onDelete,
|
||||||
onRetry,
|
onRetry,
|
||||||
onBack,
|
onRefund,
|
||||||
}: WalletTransactionProps): VNode {
|
}: WalletTransactionProps): VNode {
|
||||||
const [confirmBeforeForget, setConfirmBeforeForget] = useState(false);
|
const [confirmBeforeForget, setConfirmBeforeForget] = useState(false);
|
||||||
|
|
||||||
@ -334,6 +339,40 @@ export function TransactionView({
|
|||||||
)}
|
)}
|
||||||
</Header>
|
</Header>
|
||||||
<br />
|
<br />
|
||||||
|
{transaction.refunds.length > 0 ? (
|
||||||
|
<Part
|
||||||
|
title={<i18n.Translate>Refunds</i18n.Translate>}
|
||||||
|
text={
|
||||||
|
<table>
|
||||||
|
{transaction.refunds.map((r, i) => {
|
||||||
|
return (
|
||||||
|
<tr key={i}>
|
||||||
|
<td>
|
||||||
|
{<Amount value={r.amountEffective} />}{" "}
|
||||||
|
<a
|
||||||
|
href={Pages.balance_transaction.replace(
|
||||||
|
":tid",
|
||||||
|
r.transactionId,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
was refunded
|
||||||
|
</a>{" "}
|
||||||
|
on{" "}
|
||||||
|
{
|
||||||
|
<Time
|
||||||
|
timestamp={AbsoluteTime.fromTimestamp(r.timestamp)}
|
||||||
|
format="dd MMMM yyyy"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
kind="neutral"
|
||||||
|
/>
|
||||||
|
) : undefined}
|
||||||
{pendingRefund !== undefined && Amounts.isNonZero(pendingRefund) && (
|
{pendingRefund !== undefined && Amounts.isNonZero(pendingRefund) && (
|
||||||
<InfoBox>
|
<InfoBox>
|
||||||
<i18n.Translate>
|
<i18n.Translate>
|
||||||
@ -348,7 +387,7 @@ export function TransactionView({
|
|||||||
<div>
|
<div>
|
||||||
<div />
|
<div />
|
||||||
<div>
|
<div>
|
||||||
<ButtonPrimary>
|
<ButtonPrimary onClick={() => onRefund(transaction.proposalId)}>
|
||||||
<i18n.Translate>Accept</i18n.Translate>
|
<i18n.Translate>Accept</i18n.Translate>
|
||||||
</ButtonPrimary>
|
</ButtonPrimary>
|
||||||
</div>
|
</div>
|
||||||
@ -385,9 +424,9 @@ export function TransactionView({
|
|||||||
total={total}
|
total={total}
|
||||||
kind="negative"
|
kind="negative"
|
||||||
>
|
>
|
||||||
{transaction.targetPaytoUri}
|
{!payto ? transaction.targetPaytoUri : <NicePayto payto={payto} />}
|
||||||
</Header>
|
</Header>
|
||||||
{payto && <PartPayto big payto={payto} kind="neutral" />}
|
{payto && <PartPayto payto={payto} kind="neutral" />}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={<i18n.Translate>Details</i18n.Translate>}
|
||||||
text={<DepositDetails transaction={transaction} />}
|
text={<DepositDetails transaction={transaction} />}
|
||||||
@ -669,7 +708,7 @@ function PurchaseDetails({
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Refunded</td>
|
<td>Refunded</td>
|
||||||
<td>
|
<td>
|
||||||
<Amount value={transaction.totalRefundEffective} />
|
<Amount value={transaction.totalRefundRaw} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
@ -988,3 +1027,30 @@ function Header({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NicePayto({ payto }: { payto: PaytoUri }): VNode {
|
||||||
|
if (payto.isKnown) {
|
||||||
|
switch (payto.targetType) {
|
||||||
|
case "bitcoin": {
|
||||||
|
return <div>{payto.targetPath.substring(0, 20)}...</div>;
|
||||||
|
}
|
||||||
|
case "x-taler-bank": {
|
||||||
|
const url = new URL("/", `https://${payto.host}`);
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<div>{payto.account}</div>
|
||||||
|
<SmallLightText>
|
||||||
|
<a href={url.href} target="_bank" rel="noreferrer">
|
||||||
|
{url.toString()}
|
||||||
|
</a>
|
||||||
|
</SmallLightText>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "iban": {
|
||||||
|
return <div>{payto.targetPath.substring(0, 20)}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <Fragment>{stringifyPaytoUri(payto)}</Fragment>;
|
||||||
|
}
|
||||||
|
@ -311,6 +311,15 @@ export function applyRefund(
|
|||||||
return callBackend("applyRefund", { talerRefundUri });
|
return callBackend("applyRefund", { talerRefundUri });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do refund for purchase.
|
||||||
|
*/
|
||||||
|
export function applyRefundFromPurchaseId(
|
||||||
|
purchaseId: string,
|
||||||
|
): Promise<ApplyRefundResponse> {
|
||||||
|
return callBackend("applyRefundFromPurchaseId", { purchaseId });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get details about a pay operation.
|
* Get details about a pay operation.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user