wallet-core: fix getTransactionById for refunds

This commit is contained in:
Florian Dold 2023-05-24 14:20:48 +02:00
parent f14c7e5f2a
commit f475f98f86
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
2 changed files with 91 additions and 23 deletions

View File

@ -203,10 +203,12 @@ export type Transaction =
| TransactionPeerPullCredit | TransactionPeerPullCredit
| TransactionPeerPullDebit | TransactionPeerPullDebit
| TransactionPeerPushCredit | TransactionPeerPushCredit
| TransactionPeerPushDebit; | TransactionPeerPushDebit
| TransactionInternalWithdrawal;
export enum TransactionType { export enum TransactionType {
Withdrawal = "withdrawal", Withdrawal = "withdrawal",
InternalWithdrawal = "internal-withdrawal",
Payment = "payment", Payment = "payment",
Refund = "refund", Refund = "refund",
Refresh = "refresh", Refresh = "refresh",
@ -271,8 +273,9 @@ interface WithdrawalDetailsForTalerBankIntegrationApi {
reserveIsReady: boolean; reserveIsReady: boolean;
} }
// This should only be used for actual withdrawals /**
// and not for tips that have their own transactions type. * A withdrawal transaction (either bank-integrated or manual).
*/
export interface TransactionWithdrawal extends TransactionCommon { export interface TransactionWithdrawal extends TransactionCommon {
type: TransactionType.Withdrawal; type: TransactionType.Withdrawal;
@ -294,6 +297,40 @@ export interface TransactionWithdrawal extends TransactionCommon {
withdrawalDetails: WithdrawalDetails; withdrawalDetails: WithdrawalDetails;
} }
/**
* Internal withdrawal operation, only reported on request.
*
* Some transactions (peer-*-credit) internally do a withdrawal,
* but only the peer-*-credit transaction is reported.
*
* The internal withdrawal transaction allows to access the details of
* the underlying withdrawal for testing/debugging.
*
* It is usually not reported, so that amounts of transactions properly
* add up, since the amountEffecive of the withdrawal is already reported
* in the peer-*-credit transaction.
*/
export interface TransactionInternalWithdrawal extends TransactionCommon {
type: TransactionType.InternalWithdrawal;
/**
* Exchange of the withdrawal.
*/
exchangeBaseUrl: string;
/**
* Amount that got subtracted from the reserve balance.
*/
amountRaw: AmountString;
/**
* Amount that actually was (or will be) added to the wallet's balance.
*/
amountEffective: AmountString;
withdrawalDetails: WithdrawalDetails;
}
export interface PeerInfoShort { export interface PeerInfoShort {
expiration: TalerProtocolTimestamp | undefined; expiration: TalerProtocolTimestamp | undefined;
summary: string | undefined; summary: string | undefined;

View File

@ -111,6 +111,7 @@ import {
computeWithdrawalTransactionStatus, computeWithdrawalTransactionStatus,
processWithdrawalGroup, processWithdrawalGroup,
} from "./withdraw.js"; } from "./withdraw.js";
import { GetReadOnlyAccess, WalletStoresV1 } from "../index.js";
const logger = new Logger("taler-wallet-core:transactions.ts"); const logger = new Logger("taler-wallet-core:transactions.ts");
@ -155,6 +156,7 @@ const txOrder: { [t in TransactionType]: number } = {
[TransactionType.Deposit]: 9, [TransactionType.Deposit]: 9,
[TransactionType.Refresh]: 10, [TransactionType.Refresh]: 10,
[TransactionType.Tip]: 11, [TransactionType.Tip]: 11,
[TransactionType.InternalWithdrawal]: 12,
}; };
export async function getTransactionById( export async function getTransactionById(
@ -271,9 +273,23 @@ export async function getTransactionById(
}); });
} }
case TransactionType.Refund: case TransactionType.Refund: {
// FIXME! return await ws.db
throw Error("not implemented"); .mktx((x) => [x.refundGroups, x.contractTerms, x.purchases])
.runReadOnly(async (tx) => {
const refundRecord = await tx.refundGroups.get(
parsedTx.refundGroupId,
);
if (!refundRecord) {
throw Error("not found");
}
const contractData = await lookupMaybeContractData(
tx,
refundRecord?.proposalId,
);
return buildTransactionForRefund(refundRecord, contractData);
});
}
case TransactionType.PeerPullDebit: { case TransactionType.PeerPullDebit: {
return await ws.db return await ws.db
.mktx((x) => [x.peerPullPaymentIncoming]) .mktx((x) => [x.peerPullPaymentIncoming])
@ -829,6 +845,33 @@ function buildTransactionForTip(
}; };
} }
async function lookupMaybeContractData(
tx: GetReadOnlyAccess<{
purchases: typeof WalletStoresV1.purchases;
contractTerms: typeof WalletStoresV1.contractTerms;
}>,
proposalId: string,
): Promise<WalletContractData | undefined> {
let contractData: WalletContractData | undefined = undefined;
const purchaseTx = await tx.purchases.get(proposalId);
if (purchaseTx && purchaseTx.download) {
const download = purchaseTx.download;
const contractTermsRecord = await tx.contractTerms.get(
download.contractTermsHash,
);
if (!contractTermsRecord) {
return;
}
contractData = extractContractData(
contractTermsRecord?.contractTermsRaw,
download.contractTermsHash,
download.contractTermsMerchantSig,
);
}
return contractData;
}
async function buildTransactionForPurchase( async function buildTransactionForPurchase(
purchaseRecord: PurchaseRecord, purchaseRecord: PurchaseRecord,
contractData: WalletContractData, contractData: WalletContractData,
@ -1061,22 +1104,10 @@ export async function getTransactions(
if (shouldSkipCurrency(transactionsRequest, currency)) { if (shouldSkipCurrency(transactionsRequest, currency)) {
return; return;
} }
let contractData: WalletContractData | undefined = undefined; const contractData = await lookupMaybeContractData(
const purchaseTx = await tx.purchases.get(refundGroup.proposalId); tx,
if (purchaseTx && purchaseTx.download) { refundGroup.proposalId,
const download = purchaseTx.download;
const contractTermsRecord = await tx.contractTerms.get(
download.contractTermsHash,
); );
if (!contractTermsRecord) {
return;
}
contractData = extractContractData(
contractTermsRecord?.contractTermsRaw,
download.contractTermsHash,
download.contractTermsMerchantSig,
);
}
transactions.push(buildTransactionForRefund(refundGroup, contractData)); transactions.push(buildTransactionForRefund(refundGroup, contractData));
}); });