Skip to content

Commit

Permalink
opex: first pass at gathering LEA statistics for the pro-se committee
Browse files Browse the repository at this point in the history
  • Loading branch information
jimlerza committed Jan 11, 2025
1 parent 0ec140d commit 4c5f225
Showing 1 changed file with 191 additions and 0 deletions.
191 changes: 191 additions & 0 deletions scripts/reports/lea-stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#!/usr/bin/env -S npx ts-node --transpile-only

import {
type ScriptConfig,
parseArgsAndEnvVars,
} from '../helpers/parseArgsAndEnvVars';
import {
type ServerApplicationContext,
createApplicationContext,
} from '@web-api/applicationContext';
import { generateCsv } from '../helpers/generate-csv';
import { getCaseByDocketNumber } from '@web-api/persistence/dynamo/cases/getCaseByDocketNumber';
import { searchAll } from '@web-api/persistence/elasticsearch/searchClient';
import PQueue from 'p-queue';

const scriptConfig: ScriptConfig = {
description:
'lea-stats - Generates statistics related to Limited Entry of Appearance documents.',
environment: {
env: 'ENV',
region: 'REGION',
},
parameters: {
fiscal: {
short: 'f',
type: 'boolean',
},
year: {
position: 0,
required: true,
transform: 'number',
type: 'string',
},
},
requireActiveAwsSession: true,
};

const OUTPUT_DIR = `${process.env.HOME}/Documents`;
const caseCache: { [k: string]: RawCase } = {};
const concurrency = 50;

const getLEAsFiledInYear = async ({
applicationContext,
fiscal,
year,
}: {
applicationContext: ServerApplicationContext;
fiscal: boolean;
year: number;
}): Promise<RawDocketEntry[]> => {
const { results } = await searchAll({
applicationContext,
searchParameters: {
body: {
query: {
bool: {
must: [
{
term: {
'entityName.S': 'DocketEntry',
},
},
{
term: {
'eventCode.S': 'LEA',
},
},
{
range: {
'receivedAt.S': {
gte: fiscal
? `${year - 1}-10-01T05:00:00Z`
: `${year}-01-01T04:00:00Z`,
lt: fiscal
? `${year}-10-01T05:00:00Z`
: `${year + 1}-01-01T04:00:00Z`,
},
},
},
],
},
},
sort: [{ 'receivedAt.S': 'asc' }],
},
index: 'efcms-docket-entry',
},
});
return results;
};

const getCaseEntity = async ({
applicationContext,
docketNumber,
}: {
applicationContext: ServerApplicationContext;
docketNumber: string;
}): Promise<RawCase> => {
if (!(docketNumber in caseCache)) {
caseCache[docketNumber] = await getCaseByDocketNumber({
applicationContext,
docketNumber,
includeConsolidatedCases: false,
});
}
return caseCache[docketNumber];
};

const getNocFiledAfterLeaInCase = ({
docketNumber,
leaReceivedAt,
}: {
docketNumber: string;
leaReceivedAt: string;
}): RawDocketEntry | undefined => {
if (!(docketNumber in caseCache)) {
return;
}
const subsequentNOCs = caseCache[docketNumber].docketEntries.filter(de => {
return de.eventCode === 'NOC' && de.receivedAt > leaReceivedAt;
});
if (!subsequentNOCs) {
return;
}
return subsequentNOCs[0];
};

// eslint-disable-next-line @typescript-eslint/no-floating-promises
(async () => {
const { fiscal, year } = parseArgsAndEnvVars(scriptConfig) as {
fiscal: boolean;
year: number;
};
const applicationContext = createApplicationContext({});

const leas = await getLEAsFiledInYear({ applicationContext, fiscal, year });
console.log(
`Found ${leas.length} Limited Entry of Appearance documents filed in ` +
`in ${fiscal ? 'fiscal' : 'calendar'} year ${year}.`,
);
const docketNumbers = [...new Set(leas.map(de => de.docketNumber))];
const queue = new PQueue({ concurrency });
const funcs = docketNumbers.map(
(docketNumber: string) => async () =>
await getCaseEntity({ applicationContext, docketNumber }),
);
await queue.addAll(funcs);

const procedureTypeAggs: { [k: string]: number } = {};
for (const caseEntity of Object.values(caseCache)) {
if (!(caseEntity.procedureType in procedureTypeAggs)) {
procedureTypeAggs[caseEntity.procedureType] = 0;
}
procedureTypeAggs[caseEntity.procedureType]++;
}
const stats = {
procedureTypeAggs,
totalLeas: leas.length,
totalSubsequentNocs: 0,
};
const rows: {}[] = [];
for (const lea of leas) {
const subsequentNoc = getNocFiledAfterLeaInCase({
docketNumber: lea.docketNumber,
leaReceivedAt: lea.receivedAt,
});
if (subsequentNoc) {
stats.totalSubsequentNocs++;
}
rows.push({
docketNumber: lea.docketNumber,
leaFiledDate: lea.receivedAt.split('T')[0],
leaIndex: lea.index,
nocFiledDate: subsequentNoc?.receivedAt.split('T')[0] ?? '',
nocIndex: subsequentNoc?.index ?? '',
procedureType: caseCache[lea.docketNumber].procedureType,
});
}

const columns = [
{ header: 'Docket Number', key: 'docketNumber' },
{ header: 'Procedure Type', key: 'procedureType' },
{ header: 'LEA Index', key: 'leaIndex' },
{ header: 'LEA Filed', key: 'leaFiledDate' },
{ header: 'Subsequent NOC Index', key: 'nocIndex' },
{ header: 'Subsequent NOC Filed', key: 'nocFiledDate' },
];
const filename = `${OUTPUT_DIR}/leas-filed-in${fiscal ? '-fiscal-year' : ''}-${year}.csv`;
generateCsv({ columns, filename, rows });
console.log(`Generated ${filename}`);
console.log('\nStatistics:', stats);
})();

0 comments on commit 4c5f225

Please sign in to comment.