diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations/pay-merchant.ts')
-rw-r--r-- | packages/taler-wallet-core/src/operations/pay-merchant.ts | 172 |
1 files changed, 98 insertions, 74 deletions
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts index 50b73acb7..f6bbe5b9f 100644 --- a/packages/taler-wallet-core/src/operations/pay-merchant.ts +++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -111,6 +111,7 @@ import { timestampPreciseToDb, timestampProtocolFromDb, timestampProtocolToDb, + WalletDbReadWriteTransactionArr, } from "../index.js"; import { EXCHANGE_COINS_LOCK, @@ -2006,8 +2007,8 @@ async function processPurchasePay( ) { // Do this in the background, as it might take some time handleInsufficientFunds(ws, proposalId, err).catch(async (e) => { - console.log("handling insufficient funds failed"); - console.log(`${e.toString()}`); + logger.error("handling insufficient funds failed"); + logger.error(`${e.toString()}`); }); // FIXME: Should we really consider this to be pending? @@ -2853,6 +2854,55 @@ export async function startQueryRefund( ws.workAvailable.trigger(); } +async function computeRefreshRequest( + ws: InternalWalletState, + tx: WalletDbReadWriteTransactionArr<["coins", "denominations"]>, + items: RefundItemRecord[], +): Promise<CoinRefreshRequest[]> { + const refreshCoins: CoinRefreshRequest[] = []; + for (const item of items) { + const coin = await tx.coins.get(item.coinPub); + if (!coin) { + throw Error("coin not found"); + } + const denomInfo = await ws.getDenomInfo( + ws, + tx, + coin.exchangeBaseUrl, + coin.denomPubHash, + ); + if (!denomInfo) { + throw Error("denom not found"); + } + if (item.status === RefundItemStatus.Done) { + const refundedAmount = Amounts.sub( + item.refundAmount, + denomInfo.feeRefund, + ).amount; + refreshCoins.push({ + amount: Amounts.stringify(refundedAmount), + coinPub: item.coinPub, + }); + } + } + return refreshCoins; +} + +/** + * Compute the refund item status based on the merchant's response. + */ +function getItemStatus(rf: MerchantCoinRefundStatus): RefundItemStatus { + if (rf.type === "success") { + return RefundItemStatus.Done; + } else { + if (rf.exchange_status >= 500 && rf.exchange_status <= 599) { + return RefundItemStatus.Pending; + } else { + return RefundItemStatus.Failed; + } + } +} + /** * Store refunds, possibly creating a new refund group. */ @@ -2875,59 +2925,19 @@ async function storeRefunds( const download = await expectProposalDownload(ws, purchase); const currency = Amounts.currencyOf(download.contractData.amount); - const getItemStatus = (rf: MerchantCoinRefundStatus) => { - if (rf.type === "success") { - return RefundItemStatus.Done; - } else { - if (rf.exchange_status >= 500 && rf.exchange_status <= 599) { - return RefundItemStatus.Pending; - } else { - return RefundItemStatus.Failed; - } - } - }; - - const result = await ws.db - .mktx((x) => [ - x.purchases, - x.refundGroups, - x.refundItems, - x.coins, - x.denominations, - x.coinAvailability, - x.refreshGroups, - ]) - .runReadWrite(async (tx) => { - const computeRefreshRequest = async (items: RefundItemRecord[]) => { - const refreshCoins: CoinRefreshRequest[] = []; - for (const item of items) { - const coin = await tx.coins.get(item.coinPub); - if (!coin) { - throw Error("coin not found"); - } - const denomInfo = await ws.getDenomInfo( - ws, - tx, - coin.exchangeBaseUrl, - coin.denomPubHash, - ); - if (!denomInfo) { - throw Error("denom not found"); - } - if (item.status === RefundItemStatus.Done) { - const refundedAmount = Amounts.sub( - item.refundAmount, - denomInfo.feeRefund, - ).amount; - refreshCoins.push({ - amount: Amounts.stringify(refundedAmount), - coinPub: item.coinPub, - }); - } - } - return refreshCoins; - }; - + const result = await ws.db.runReadWriteTx( + [ + "coins", + "denominations", + "purchases", + "refundItems", + "refundGroups", + "denominations", + "coins", + "coinAvailability", + "refreshGroups", + ], + async (tx) => { const myPurchase = await tx.purchases.get(purchase.proposalId); if (!myPurchase) { logger.warn("purchase group not found anymore"); @@ -3008,7 +3018,11 @@ async function storeRefunds( // we can compute the raw/effective amounts. if (newGroup) { const amountsRaw = newGroupRefunds.map((x) => x.refundAmount); - const refreshCoins = await computeRefreshRequest(newGroupRefunds); + const refreshCoins = await computeRefreshRequest( + ws, + tx, + newGroupRefunds, + ); const outInfo = await calculateRefreshOutput( ws, tx, @@ -3028,35 +3042,40 @@ async function storeRefunds( myPurchase.proposalId, ); - logger.info( - `refund groups for proposal ${myPurchase.proposalId}: ${j2s( - refundGroups, - )}`, - ); - for (const refundGroup of refundGroups) { - if (refundGroup.status === RefundGroupStatus.Aborted) { - continue; - } - if (refundGroup.status === RefundGroupStatus.Done) { - continue; + switch (refundGroup.status) { + case RefundGroupStatus.Aborted: + case RefundGroupStatus.Expired: + case RefundGroupStatus.Failed: + case RefundGroupStatus.Done: + continue; + case RefundGroupStatus.Pending: + break; + default: + assertUnreachable(refundGroup.status); } - const items = await tx.refundItems.indexes.byRefundGroupId.getAll( + const items = await tx.refundItems.indexes.byRefundGroupId.getAll([ refundGroup.refundGroupId, - ); + ]); let numPending = 0; + let numFailed = 0; for (const item of items) { if (item.status === RefundItemStatus.Pending) { numPending++; } + if (item.status === RefundItemStatus.Failed) { + numFailed++; + } } - logger.info(`refund items pending for refund group: ${numPending}`); if (numPending === 0) { - logger.info("refund group is done!"); // We're done for this refund group! - refundGroup.status = RefundGroupStatus.Done; + if (numFailed === 0) { + refundGroup.status = RefundGroupStatus.Done; + } else { + refundGroup.status = RefundGroupStatus.Failed; + } await tx.refundGroups.put(refundGroup); - const refreshCoins = await computeRefreshRequest(items); + const refreshCoins = await computeRefreshRequest(ws, tx, items); await createRefreshGroup( ws, tx, @@ -3085,7 +3104,8 @@ async function storeRefunds( newTxState, }, }; - }); + }, + ); if (!result) { return TaskRunResult.finished(); @@ -3120,5 +3140,9 @@ export function computeRefundTransactionState( return { major: TransactionMajorState.Pending, }; + case RefundGroupStatus.Expired: + return { + major: TransactionMajorState.Expired, + }; } } |