Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 62 additions & 46 deletions consumer-issuing/src/pages/api/get_statements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth";
import { getStripeSecretKey } from "src/utils/stripe-authentication";
import { authOptions } from "src/pages/api/auth/[...nextauth]";
import { logApiRequest } from "src/utils/api-logger";

export default async function handler(
req: NextApiRequest,
Expand All @@ -19,9 +20,9 @@ export default async function handler(
const { stripeAccount } = session;
const { accountId, platform } = stripeAccount;

// First, get all the files
const filesResponse = await fetch(
`https://api.stripe.com/v1/files?purpose=issuing_receipt&limit=100&created[gt]=1746551400`,
// Get credit statements from the credit_statements API
const statementsResponse = await fetch(
`https://api.stripe.com/v1/issuing/credit_statements`,
{
method: "GET",
headers: {
Expand All @@ -32,55 +33,70 @@ export default async function handler(
}
);

if (!filesResponse.ok) {
throw new Error("Failed to fetch statements");
if (!statementsResponse.ok) {
const errorText = await statementsResponse.text();
console.error("Credit statements API error:", {
status: statementsResponse.status,
statusText: statementsResponse.statusText,
error: errorText
});

// Log the failed API request
await logApiRequest(
session.email,
"https://api.stripe.com/v1/issuing/credit_statements",
"GET",
null,
{ error: errorText, status: statementsResponse.status }
);

// If credit statements are not available, return empty array
if (statementsResponse.status === 404 || statementsResponse.status === 403) {
console.log("Credit statements not available, returning empty array");
return res.status(200).json({ statements: [] });
}

throw new Error(`Failed to fetch credit statements: ${statementsResponse.status} ${statementsResponse.statusText}`);
}

const filesData = await filesResponse.json();

// Sort files by filename (which includes date) in ascending order
const sortedFiles = filesData.data.sort((a: any, b: any) =>
a.filename.localeCompare(b.filename)
);
const statementsData = await statementsResponse.json();

// Create file links for each file
const statementsWithLinks = await Promise.all(
sortedFiles.map(async (file: any) => {
const linkResponse = await fetch(
"https://api.stripe.com/v1/file_links",
{
method: "POST",
headers: {
"Stripe-Account": accountId,
Authorization: `Bearer ${getStripeSecretKey(platform)}`,
"Stripe-Version": "2024-04-10;issuing_credit_beta=v1;issuing_underwritten_credit_beta=v1",
"Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({
file: file.id
})
}
);
// Log the successful API request
await logApiRequest(
session.email,
"https://api.stripe.com/v1/issuing/credit_statements",
"GET",
null,
statementsData
);

if (!linkResponse.ok) {
console.error(`Failed to create link for file ${file.id}`);
return {
...file,
url: null
};
}
// Handle case where no statements are returned
if (!statementsData.data || !Array.isArray(statementsData.data)) {
console.log("No statements data found, returning empty array");
return res.status(200).json({ statements: [] });
}

const linkData = await linkResponse.json();
return {
...file,
url: linkData.url
};
// Sort statements by credit_period_ends_at in descending order (most recent first)
// and limit to 3 most recent, handling null values
const sortedStatements = statementsData.data
.sort((a: any, b: any) => {
// Put statements with null dates at the end
if (a.credit_period_ends_at === null && b.credit_period_ends_at === null) return 0;
if (a.credit_period_ends_at === null) return 1;
if (b.credit_period_ends_at === null) return -1;
return b.credit_period_ends_at - a.credit_period_ends_at;
})
);
.slice(0, 3);

// Map statements to include the statement_url directly
const statementsWithUrls = sortedStatements.map((statement: any) => ({
...statement,
url: statement.statement_url || null
}));

res.status(200).json({ statements: statementsWithLinks });
res.status(200).json({ statements: statementsWithUrls });
} catch (error) {
console.error("Error fetching statements:", error);
res.status(500).json({ message: "Error fetching statements" });
console.error("Error fetching credit statements:", error);
res.status(500).json({ message: "Error fetching credit statements" });
}
}
}
84 changes: 68 additions & 16 deletions consumer-issuing/src/sections/overview/overview-credit-limit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import { TestDataMakePayment } from "src/sections/test-data/test-data-make-payme

type Statement = {
id: string;
filename: string;
url: string;
credit_period_starts_at: number | null;
credit_period_ends_at: number | null;
url: string | null;
file?: string;
status?: string;
};

export const OverviewCreditStatement = (props: {
Expand Down Expand Up @@ -70,19 +73,68 @@ export const OverviewCreditStatement = (props: {
<Typography color="text.secondary">No statements available</Typography>
) : (
<Stack spacing={1}>
{statements.map((statement) => (
<Link
key={statement.id}
href={statement.url}
target="_blank"
rel="noopener noreferrer"
underline="hover"
color="primary"
download={false}
>
{statement.filename.replace('.pdf', '')}
</Link>
))}
{statements.map((statement) => {
// Handle null dates for pending statements
if (!statement.credit_period_starts_at || !statement.credit_period_ends_at) {
const statementName = statement.status === 'pending'
? "Current Statement (Pending)"
: "Statement (Processing)";

return statement.url ? (
<Link
key={statement.id}
href={statement.url}
target="_blank"
rel="noopener noreferrer"
underline="hover"
color="primary"
download={false}
>
{statementName}
</Link>
) : (
<Typography
key={statement.id}
color="text.secondary"
variant="body2"
>
{statementName}
</Typography>
);
}

// Format the statement period as a readable name
const endDate = new Date(statement.credit_period_ends_at * 1000);
const statementDate = endDate.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
});

const statementName = statementDate;

return statement.url ? (
<Link
key={statement.id}
href={statement.url}
target="_blank"
rel="noopener noreferrer"
underline="hover"
color="primary"
download={false}
>
{statementName}
</Link>
) : (
<Typography
key={statement.id}
color="text.secondary"
variant="body2"
>
{statementName}
</Typography>
);
})}
</Stack>
)}
</Stack>
Expand Down Expand Up @@ -113,4 +165,4 @@ export const OverviewCreditStatement = (props: {
</CardContent>
</Card>
);
};
};