import { desc, eq } from 'drizzle-orm'; import type { NpOutreachDatabase, NpOutreachTransaction } from '#~/db/db.js'; import { schema } from '#~/db/db.js'; export interface MatchDetail { match: { id: string; totalScore: number; subscores: unknown; rationale: unknown; easyWin: boolean; isHero: boolean; reviewStatus: 'pending' | 'approved' | 'rejected' | 'edited'; }; org: { id: string; name: string; city: string | null; state: string; ein: string | null; nteeCode: string | null; totalRevenue: number | null; registrationNumber: string | null; missionStatement: string | null; profileConfidence: number | null; programs: unknown; knownFunders: unknown; staff: unknown; serviceGeography: string | null; profileSources: unknown; }; grant: { id: string; title: string; funder: string; funderEin: string | null; synopsis: string | null; awardFloor: number | null; awardCeiling: number | null; closeDate: Date | null; sourceUrl: string; source: string; eligibilityEntityTypes: string[] | null; geographicScope: string | null; applicationEffortEstimate: string; }; /** Part XV application info from the funder's latest parsed 990-PF * (form required, deadlines, restrictions, preselected-only flag). */ funderApplicationInfo: unknown; /** For 990-PF matches: the funder's actual giving history into the * org's state — the concrete evidence behind the precedent subscore. */ funderGivingHistory: Array<{ recipientName: string; recipientCity: string | null; amount: number | null; purpose: string | null; taxYear: number; }>; } export async function serverGetMatchDetail( db: NpOutreachDatabase | NpOutreachTransaction, matchId: string, ): Promise { const rows = await db .select({ matchId: schema.matches.id, totalScore: schema.matches.totalScore, subscores: schema.matches.subscores, rationale: schema.matches.rationale, easyWin: schema.matches.easyWin, isHero: schema.matches.isHero, reviewStatus: schema.matches.reviewStatus, orgId: schema.orgs.id, orgName: schema.orgs.name, orgCity: schema.orgs.city, orgState: schema.orgs.state, orgEin: schema.orgs.ein, orgNtee: schema.orgs.nteeCode, orgRevenue: schema.orgs.totalRevenue, orgRegNo: schema.orgs.registrationNumber, grantId: schema.grants.id, grantTitle: schema.grants.title, grantFunder: schema.grants.funder, grantFunderEin: schema.grants.funderEin, grantSynopsis: schema.grants.synopsis, grantFloor: schema.grants.awardFloor, grantCeiling: schema.grants.awardCeiling, grantClose: schema.grants.closeDate, grantSourceUrl: schema.grants.sourceUrl, grantSource: schema.grants.source, grantEligibility: schema.grants.eligibilityEntityTypes, grantGeo: schema.grants.geographicScope, grantEffort: schema.grants.applicationEffortEstimate, grantProgramAwards: schema.grants.programStateAwards, }) .from(schema.matches) .innerJoin(schema.orgs, eq(schema.matches.orgId, schema.orgs.id)) .innerJoin(schema.grants, eq(schema.matches.grantId, schema.grants.id)) .where(eq(schema.matches.id, matchId)) .limit(1); const row = rows[0]; if (row == null) return null; const profiles = await db .select({ missionStatement: schema.orgProfiles.missionStatement, confidence: schema.orgProfiles.confidence, programs: schema.orgProfiles.programs, knownFunders: schema.orgProfiles.knownFunders, staff: schema.orgProfiles.staff, serviceGeography: schema.orgProfiles.serviceGeography, sources: schema.orgProfiles.sources, }) .from(schema.orgProfiles) .where(eq(schema.orgProfiles.orgId, row.orgId)) .limit(1); let funderGivingHistory: MatchDetail['funderGivingHistory'] = []; let funderApplicationInfo: unknown = null; if (row.grantFunderEin == null && Array.isArray(row.grantProgramAwards)) { // Federal grants: USASpending program awards fill the same evidence // table (recipient/amount/year) the 990-PF history uses. funderGivingHistory = ( row.grantProgramAwards as Array<{ recipientName?: string; amount?: number | null; startDate?: string | null; }> ).map((a) => ({ recipientName: a.recipientName ?? 'Unknown recipient', recipientCity: null, amount: a.amount ?? null, purpose: null, taxYear: a.startDate != null ? Number(a.startDate.slice(0, 4)) : 0, })); } if (row.grantFunderEin != null) { const funderRow = await db .select({ applicationInfo: schema.funders.applicationInfo }) .from(schema.funders) .where(eq(schema.funders.ein, row.grantFunderEin)) .limit(1); funderApplicationInfo = funderRow[0]?.applicationInfo ?? null; const funderRows = await db .select({ recipientName: schema.funderGrants.recipientName, recipientCity: schema.funderGrants.recipientCity, recipientState: schema.funderGrants.recipientState, amount: schema.funderGrants.amount, purpose: schema.funderGrants.purpose, taxYear: schema.funderGrants.taxYear, }) .from(schema.funderGrants) .innerJoin( schema.funders, eq(schema.funderGrants.funderId, schema.funders.id), ) .where(eq(schema.funders.ein, row.grantFunderEin)) .orderBy(desc(schema.funderGrants.taxYear), desc(schema.funderGrants.amount)) .limit(200); // In-state grants first (the precedent evidence), then the rest. funderGivingHistory = [...funderRows] .sort((a, b) => { const aIn = a.recipientState === row.orgState ? 0 : 1; const bIn = b.recipientState === row.orgState ? 0 : 1; return aIn - bIn; }) .slice(0, 40) .map(({ recipientState: _s, ...rest }) => rest); } return { match: { id: row.matchId, totalScore: row.totalScore, subscores: row.subscores, rationale: row.rationale, easyWin: row.easyWin, isHero: row.isHero, reviewStatus: row.reviewStatus, }, org: { id: row.orgId, name: row.orgName, city: row.orgCity, state: row.orgState, ein: row.orgEin, nteeCode: row.orgNtee, totalRevenue: row.orgRevenue, registrationNumber: row.orgRegNo, missionStatement: profiles[0]?.missionStatement ?? null, profileConfidence: profiles[0]?.confidence ?? null, programs: profiles[0]?.programs ?? null, knownFunders: profiles[0]?.knownFunders ?? null, staff: profiles[0]?.staff ?? null, serviceGeography: profiles[0]?.serviceGeography ?? null, profileSources: profiles[0]?.sources ?? null, }, grant: { id: row.grantId, title: row.grantTitle, funder: row.grantFunder, funderEin: row.grantFunderEin, synopsis: row.grantSynopsis, awardFloor: row.grantFloor, awardCeiling: row.grantCeiling, closeDate: row.grantClose, sourceUrl: row.grantSourceUrl, source: row.grantSource, eligibilityEntityTypes: row.grantEligibility, geographicScope: row.grantGeo, applicationEffortEstimate: row.grantEffort, }, funderApplicationInfo, funderGivingHistory, }; }