diff --git a/apps/frontend/src/components/layout/impersonate.tsx b/apps/frontend/src/components/layout/impersonate.tsx
index d50f3e06..7f9bf46d 100644
--- a/apps/frontend/src/components/layout/impersonate.tsx
+++ b/apps/frontend/src/components/layout/impersonate.tsx
@@ -22,6 +22,8 @@ interface Charge {
refunded: boolean;
amount_refunded: number;
description: string | null;
+ receipt_url: string | null;
+ invoice_pdf: string | null;
}
const useCharges = () => {
@@ -124,6 +126,7 @@ const ChargesModal: FC<{ close: () => void }> = ({ close }) => {
{t('date', 'Date')} |
{t('amount', 'Amount')} |
{t('status', 'Status')} |
+ |
@@ -178,6 +181,34 @@ const ChargesModal: FC<{ close: () => void }> = ({ close }) => {
)}
+
+ {(charge.invoice_pdf || charge.receipt_url) && (
+ e.stopPropagation()}
+ className="inline-flex items-center justify-center w-[28px] h-[28px] rounded-[4px] hover:bg-tableBorder transition-colors"
+ title={charge.invoice_pdf ? t('download_invoice', 'Download Invoice') : t('view_receipt', 'View Receipt')}
+ >
+
+
+ )}
+ |
))}
diff --git a/libraries/nestjs-libraries/src/services/stripe.service.ts b/libraries/nestjs-libraries/src/services/stripe.service.ts
index 05fa74df..f21bd66c 100644
--- a/libraries/nestjs-libraries/src/services/stripe.service.ts
+++ b/libraries/nestjs-libraries/src/services/stripe.service.ts
@@ -856,7 +856,7 @@ export class StripeService {
limit: 100,
});
- return charges.data
+ const chargeList = charges.data
.filter((f) => f.status === 'succeeded')
.map((charge) => ({
id: charge.id,
@@ -867,7 +867,33 @@ export class StripeService {
refunded: charge.refunded,
amount_refunded: charge.amount_refunded,
description: charge.description,
+ receipt_url: charge.receipt_url || null,
+ invoice: (charge as any).invoice || null,
}));
+
+ const invoiceIds = chargeList
+ .map((c) => c.invoice)
+ .filter((id): id is string => !!id && typeof id === 'string');
+
+ const invoicePdfMap: Record = {};
+ for (const invoiceId of invoiceIds) {
+ try {
+ const inv = await stripe.invoices.retrieve(invoiceId);
+ if (inv.invoice_pdf) {
+ invoicePdfMap[invoiceId] = inv.invoice_pdf;
+ }
+ } catch {
+ // ignore if invoice can't be fetched
+ }
+ }
+
+ return chargeList.map((charge) => ({
+ ...charge,
+ invoice_pdf:
+ charge.invoice && invoicePdfMap[charge.invoice as string]
+ ? invoicePdfMap[charge.invoice as string]
+ : null,
+ }));
}
async refundCharges(organizationId: string, chargeIds: string[]) {