|
5 | 5 | UpgradeToTeamBundleRequest, |
6 | 6 | StripePaymentIntentsResponse, |
7 | 7 | PaymentIntentSearchKind, |
| 8 | + PaymentIntentRecord, |
8 | 9 | } from "../../controllers/public/stripeController"; |
9 | 10 | import { clickhouseDb } from "../../lib/db/ClickhouseWrapper"; |
10 | 11 | import { Database } from "../../lib/db/database.types"; |
@@ -1389,11 +1390,81 @@ WHERE (${builtFilter.filter})`, |
1389 | 1390 |
|
1390 | 1391 | const paymentIntents = await this.stripe.paymentIntents.search(searchParams); |
1391 | 1392 |
|
| 1393 | + // Map Stripe PaymentIntent to our custom PaymentIntentRecord type |
| 1394 | + const mappedData: PaymentIntentRecord[] = []; |
| 1395 | + |
| 1396 | + // Process each payment intent and fetch its refunds |
| 1397 | + for (const intent of paymentIntents.data) { |
| 1398 | + let totalRefunded = 0; |
| 1399 | + let isFullyRefunded = false; |
| 1400 | + let latestRefundDate = intent.created; |
| 1401 | + let refundIds: string[] = []; |
| 1402 | + |
| 1403 | + // Fetch refunds for this payment intent |
| 1404 | + try { |
| 1405 | + const refunds = await this.stripe.refunds.list({ |
| 1406 | + payment_intent: intent.id, |
| 1407 | + limit: 100, // Get all refunds for this payment intent |
| 1408 | + }); |
| 1409 | + |
| 1410 | + if (refunds.data.length > 0) { |
| 1411 | + totalRefunded = refunds.data.reduce((sum, refund) => sum + refund.amount, 0); |
| 1412 | + isFullyRefunded = totalRefunded >= intent.amount; |
| 1413 | + refundIds = refunds.data.map(refund => refund.id); |
| 1414 | + |
| 1415 | + // Use the latest refund date for sorting if fully refunded |
| 1416 | + if (isFullyRefunded) { |
| 1417 | + latestRefundDate = Math.max(...refunds.data.map(r => r.created), intent.created); |
| 1418 | + } |
| 1419 | + } |
| 1420 | + } catch (refundError) { |
| 1421 | + console.error(`Error fetching refunds for payment intent ${intent.id}:`, refundError); |
| 1422 | + // Continue processing other payment intents even if one fails |
| 1423 | + } |
| 1424 | + |
| 1425 | + // Add consolidated record |
| 1426 | + if (isFullyRefunded) { |
| 1427 | + // Show as fully refunded transaction |
| 1428 | + mappedData.push({ |
| 1429 | + id: intent.id, // Always use payment intent ID |
| 1430 | + amount: intent.amount, |
| 1431 | + created: latestRefundDate, |
| 1432 | + status: "refunded", |
| 1433 | + isRefunded: true, |
| 1434 | + refundedAmount: totalRefunded, |
| 1435 | + refundIds: refundIds, |
| 1436 | + }); |
| 1437 | + } else if (totalRefunded > 0) { |
| 1438 | + // Show as partially refunded transaction |
| 1439 | + mappedData.push({ |
| 1440 | + id: intent.id, // Always use payment intent ID |
| 1441 | + amount: intent.amount, |
| 1442 | + created: intent.created, |
| 1443 | + status: intent.status, |
| 1444 | + isRefunded: true, |
| 1445 | + refundedAmount: totalRefunded, |
| 1446 | + refundIds: refundIds, |
| 1447 | + }); |
| 1448 | + } else { |
| 1449 | + // Show as normal transaction |
| 1450 | + mappedData.push({ |
| 1451 | + id: intent.id, // Always use payment intent ID |
| 1452 | + amount: intent.amount, |
| 1453 | + created: intent.created, |
| 1454 | + status: intent.status, |
| 1455 | + isRefunded: false, |
| 1456 | + }); |
| 1457 | + } |
| 1458 | + } |
| 1459 | + |
| 1460 | + // Sort all records by created date (newest first) |
| 1461 | + mappedData.sort((a, b) => b.created - a.created); |
| 1462 | + |
1392 | 1463 | return ok({ |
1393 | | - data: paymentIntents.data, |
| 1464 | + data: mappedData, |
1394 | 1465 | has_more: paymentIntents.has_more, |
1395 | 1466 | next_page: paymentIntents.next_page || null, |
1396 | | - count: paymentIntents.data.length, |
| 1467 | + count: mappedData.length, |
1397 | 1468 | }); |
1398 | 1469 | } catch (error: any) { |
1399 | 1470 | console.error("Error searching payment intents:", error); |
|
0 commit comments