-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
311 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#!/usr/bin/env -S npx ts-node --transpile-only | ||
|
||
import { type RawPractitioner } from '@shared/business/entities/Practitioner'; | ||
import { | ||
type ScriptConfig, | ||
parseArgsAndEnvVars, | ||
} from '../helpers/parseArgsAndEnvVars'; | ||
import { | ||
type ServerApplicationContext, | ||
createApplicationContext, | ||
} from '@web-api/applicationContext'; | ||
import { generateCsv } from '../helpers/generate-csv'; | ||
import { pick } from 'lodash'; | ||
import { searchAll } from '@web-api/persistence/elasticsearch/searchClient'; | ||
|
||
const scriptConfig: ScriptConfig = { | ||
description: | ||
'attorneys-admitted-in-year - Generates a CSV of attorneys admitted in the given year.', | ||
environment: { | ||
elasticsearchEndpoint: 'ELASTICSEARCH_ENDPOINT', | ||
env: 'ENV', | ||
}, | ||
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 getAttorneysAdmittedInYear = async ({ | ||
applicationContext, | ||
fiscal, | ||
year, | ||
}: { | ||
applicationContext: ServerApplicationContext; | ||
fiscal: boolean; | ||
year: number; | ||
}): Promise<RawPractitioner[]> => { | ||
const { results } = await searchAll({ | ||
applicationContext, | ||
searchParameters: { | ||
body: { | ||
query: { | ||
bool: { | ||
must: [ | ||
{ | ||
term: { | ||
'practitionerType.S': 'Attorney', | ||
}, | ||
}, | ||
{ | ||
range: { | ||
'admissionsDate.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: [{ 'admissionsDate.S': 'asc' }], | ||
}, | ||
index: 'efcms-user', | ||
}, | ||
}); | ||
return results; | ||
}; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
(async () => { | ||
const applicationContext = createApplicationContext({}); | ||
const { fiscal, year } = parseArgsAndEnvVars(scriptConfig) as { | ||
fiscal: boolean; | ||
year: number; | ||
}; | ||
const attorneys: RawPractitioner[] = await getAttorneysAdmittedInYear({ | ||
applicationContext, | ||
fiscal, | ||
year, | ||
}); | ||
console.log( | ||
`Found ${attorneys.length} attorneys admitted in ${fiscal ? 'fiscal' : 'calendar'} year ${year}.`, | ||
); | ||
const columns = [ | ||
{ header: 'Bar Number', key: 'barNumber' }, | ||
{ header: 'Name', key: 'name' }, | ||
{ header: 'Practice Type', key: 'practiceType' }, | ||
{ header: 'Firm', key: 'firmName' }, | ||
{ header: 'Admissions Date', key: 'admissionsDate' }, | ||
]; | ||
const rows = attorneys.map(attorney => ({ | ||
...pick(attorney, ['barNumber', 'firmName', 'name', 'practiceType']), | ||
admissionsDate: attorney.admissionsDate.split('T')[0], | ||
})); | ||
const filename = `${OUTPUT_DIR}/attorneys-admitted-in${fiscal ? '-fiscal-year' : ''}-${year}.csv`; | ||
generateCsv({ columns, filename, rows }); | ||
console.log(`Generated ${filename}`); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
#!/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 { pick } from 'lodash'; | ||
import { searchAll } from '@web-api/persistence/elasticsearch/searchClient'; | ||
|
||
const scriptConfig: ScriptConfig = { | ||
description: | ||
'documents-filed-by-non-attorneys - Generates a CSV of documents filed by non-attorneys.', | ||
environment: { | ||
elasticsearchEndpoint: 'ELASTICSEARCH_ENDPOINT', | ||
env: 'ENV', | ||
}, | ||
parameters: { | ||
eventCode: { | ||
default: 'P', | ||
long: 'event-code', | ||
required: false, | ||
short: 'e', | ||
type: 'string', | ||
}, | ||
fiscal: { | ||
default: false, | ||
short: 'f', | ||
type: 'boolean', | ||
}, | ||
year: { | ||
default: '2024', | ||
required: false, | ||
short: 'y', | ||
transform: 'number', | ||
type: 'string', | ||
}, | ||
}, | ||
requireActiveAwsSession: true, | ||
}; | ||
|
||
const OUTPUT_DIR = `${process.env.HOME}/Documents`; | ||
|
||
const getNonAttorneys = async ({ | ||
applicationContext, | ||
}: { | ||
applicationContext: ServerApplicationContext; | ||
}): Promise<{ [k: string]: string }> => { | ||
const nonAttorneys = {}; | ||
const { results } = await searchAll({ | ||
applicationContext, | ||
searchParameters: { | ||
body: { | ||
query: { | ||
bool: { | ||
must: [ | ||
{ | ||
term: { | ||
'admissionsStatus.S': 'Active', | ||
}, | ||
}, | ||
{ | ||
term: { | ||
'practitionerType.S': 'Non-Attorney', | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
index: 'efcms-user', | ||
}, | ||
}); | ||
for (const result of results) { | ||
nonAttorneys[result.pk.replace('user|', '')] = result.name; | ||
} | ||
return nonAttorneys; | ||
}; | ||
|
||
const getDocuments = async ({ | ||
applicationContext, | ||
eventCode, | ||
fiscal, | ||
userIds, | ||
year, | ||
}: { | ||
applicationContext: ServerApplicationContext; | ||
eventCode: string; | ||
fiscal: boolean; | ||
userIds: string[]; | ||
year: number; | ||
}): Promise<RawDocketEntry[]> => { | ||
const { results } = await searchAll({ | ||
applicationContext, | ||
searchParameters: { | ||
body: { | ||
query: { | ||
bool: { | ||
must: [ | ||
{ | ||
term: { | ||
'entityName.S': 'DocketEntry', | ||
}, | ||
}, | ||
{ | ||
term: { | ||
'eventCode.S': eventCode, | ||
}, | ||
}, | ||
{ | ||
terms: { | ||
'userId.S': userIds, | ||
}, | ||
}, | ||
{ | ||
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; | ||
}; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
(async () => { | ||
const applicationContext = createApplicationContext({}); | ||
const { eventCode, fiscal, year } = parseArgsAndEnvVars(scriptConfig) as { | ||
eventCode: string; | ||
fiscal: boolean; | ||
year: number; | ||
}; | ||
console.log( | ||
`Looking for documents with event code ${eventCode} filed by non-attorneys ` + | ||
`in ${fiscal ? 'fiscal' : 'calendar'} year ${year}...`, | ||
); | ||
const nonAttorneys = await getNonAttorneys({ applicationContext }); | ||
console.log( | ||
`Found ${Object.keys(nonAttorneys).length} non-attorneys with active admissions status.`, | ||
); | ||
const documents = await getDocuments({ | ||
applicationContext, | ||
eventCode, | ||
fiscal, | ||
userIds: Object.keys(nonAttorneys), | ||
year, | ||
}); | ||
if (!documents.length) { | ||
console.log( | ||
`Found 0 documents with event code ${eventCode} filed by non-attorneys ` + | ||
`in ${fiscal ? 'fiscal' : 'calendar'} year ${year}.`, | ||
); | ||
return; | ||
} | ||
console.log( | ||
`Found ${documents.length} ${documents[0].documentType}` + | ||
`${documents.length === 1 ? '' : 's'} filed by non-attorneys ` + | ||
`in ${fiscal ? 'fiscal' : 'calendar'} year ${year}.`, | ||
); | ||
const columns = [ | ||
{ header: 'Docket Number', key: 'docketNumber' }, | ||
{ header: 'Document Title', key: 'documentTitle' }, | ||
{ header: 'Filed On', key: 'filedOn' }, | ||
{ header: 'Filed By', key: 'filedBy' }, | ||
]; | ||
const rows = documents.map(de => ({ | ||
...pick(de, ['docketNumber', 'documentTitle']), | ||
filedBy: nonAttorneys[de.userId!], | ||
filedOn: de.receivedAt.split('T')[0], | ||
})); | ||
const docType = documents[0].documentType.replace(' ', '-').toLowerCase(); | ||
const filename = `${OUTPUT_DIR}/${docType}s-filed-by-non-attorneys-in${fiscal ? '-fiscal-year' : ''}-${year}.csv`; | ||
generateCsv({ columns, filename, rows }); | ||
console.log(`Generated ${filename}`); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters