summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/operations/pay-merchant.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/operations/pay-merchant.ts')
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts172
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,
+ };
}
}