Skip to content

Commit e2307a5

Browse files
committed
fix(stripe): harden early fraud warning admin listing
1 parent 0363bd6 commit e2307a5

2 files changed

Lines changed: 15 additions & 4 deletions

File tree

apps/web/src/routers/admin/stripe-early-fraud-warnings-router.test.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('admin early fraud warnings list', () => {
105105
);
106106
});
107107

108-
it('paginates warning cases deterministically', async () => {
108+
it('paginates dated warning cases before rows without warning timestamps', async () => {
109109
await db.insert(stripe_early_fraud_warning_cases).values([
110110
{
111111
stripe_early_fraud_warning_id: 'issfr_older',
@@ -123,14 +123,25 @@ describe('admin early fraud warnings list', () => {
123123
reason: 'No canonical customer owner matched; manual review required',
124124
warning_created_at: '2026-05-27T00:00:00.000Z',
125125
},
126+
{
127+
stripe_early_fraud_warning_id: 'issfr_missing_warning_time',
128+
stripe_event_id: 'evt_missing_warning_time',
129+
owner_classification: StripeEarlyFraudWarningOwnerClassification.Unmatched,
130+
status: StripeEarlyFraudWarningCaseStatus.ReviewRequired,
131+
reason: 'Warning timestamp missing; manual review required',
132+
warning_created_at: null,
133+
},
126134
]);
127135

128136
const caller = await createCallerForUser(admin.id);
129137
const firstPage = await caller.admin.earlyFraudWarnings.list({ page: 1, limit: 1 });
130138
const secondPage = await caller.admin.earlyFraudWarnings.list({ page: 2, limit: 1 });
139+
const thirdPage = await caller.admin.earlyFraudWarnings.list({ page: 3, limit: 1 });
131140

132-
expect(firstPage.pagination).toEqual({ page: 1, limit: 1, total: 2, totalPages: 2 });
141+
expect(firstPage.pagination).toEqual({ page: 1, limit: 1, total: 3, totalPages: 3 });
133142
expect(firstPage.rows[0]?.stripeEarlyFraudWarningId).toBe('issfr_newer');
134143
expect(secondPage.rows[0]?.stripeEarlyFraudWarningId).toBe('issfr_older');
144+
expect(thirdPage.rows[0]?.stripeEarlyFraudWarningId).toBe('issfr_missing_warning_time');
145+
expect(thirdPage.rows[0]?.warningCreatedAt).toBeNull();
135146
});
136147
});

apps/web/src/routers/admin/stripe-early-fraud-warnings-router.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const EarlyFraudWarningListInputSchema = z.object({
1717
function normalizeTimestamp(value: string | null): string | null {
1818
if (!value) return null;
1919
const date = new Date(value);
20-
return Number.isNaN(date.getTime()) ? value : date.toISOString();
20+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
2121
}
2222

2323
export const adminStripeEarlyFraudWarningsRouter = createTRPCRouter({
@@ -57,7 +57,7 @@ export const adminStripeEarlyFraudWarningsRouter = createTRPCRouter({
5757
eq(organizations.id, stripe_early_fraud_warning_cases.organization_id)
5858
)
5959
.orderBy(
60-
desc(stripe_early_fraud_warning_cases.warning_created_at),
60+
sql`${stripe_early_fraud_warning_cases.warning_created_at} DESC NULLS LAST`,
6161
desc(stripe_early_fraud_warning_cases.created_at),
6262
desc(stripe_early_fraud_warning_cases.id)
6363
)

0 commit comments

Comments
 (0)