Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide forecasted grants while UI is being developed to support forecasted grants #3456

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions packages/server/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ API_DOMAIN=http://localhost:8080

ENABLE_GRANTS_SCRAPER=true
SHARE_TERMINOLOGY_ENABLED=true
SHOW_FORECASTED_GRANTS=true
GRANTS_SCRAPER_DATE_RANGE=7
GRANTS_SCRAPER_DELAY=1000
NODE_OPTIONS=--max_old_space_size=1024
Expand Down
53 changes: 53 additions & 0 deletions packages/server/__tests__/db/db.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,16 @@ describe('db', () => {
const result = await db.getSingleGrantDetails({ grantId, tenantId: fixtures.users.staffUser.tenant_id });
expect(result).to.be.null;
});
it('shows forecasted grants', async () => {
const grantId = '444819';
const result = await db.getSingleGrantDetails({ grantId, tenantId: fixtures.users.staffUser.tenant_id, showForecastedGrants: true });
expect(result.grant_id).to.eq('444819');
});
it('hides forecasted grants', async () => {
const grantId = '444819';
const result = await db.getSingleGrantDetails({ grantId, tenantId: fixtures.users.staffUser.tenant_id, showForecastedGrants: false });
expect(result).to.be.null;
});
});

context('getGrantsAssignedAgency', () => {
Expand All @@ -386,6 +396,49 @@ describe('db', () => {
});
});

context('getGrant', () => {
it('gets forecasted grant', async () => {
const result = await db.getGrant({ grantId: fixtures.grants.forecastedGrant.grant_id, showForecastedGrants: true });
expect(result.grant_id).to.equal(fixtures.grants.forecastedGrant.grant_id);
});

it('hides forecasted grant', async () => {
const result = await db.getGrant({ grantId: fixtures.grants.forecastedGrant.grant_id, showForecastedGrants: false });
console.log('marissasss');
console.log(result);
expect(result).to.be.null;
});
});

context('getGrantsNew', () => {
it('gets forecasted grants', async () => {
const result = await db.getGrantsNew(
{},
{ currentPage: 1, perPage: 10, isLengthAware: true },
{ orderBy: 'open_date', orderDesc: 'true' },
fixtures.tenants.SBA.id,
fixtures.agencies.accountancy.id,
false,
true,
);
const forecastedGrant = result.data.filter((grant) => grant.opportunity_status === 'forecasted');
expect(forecastedGrant.length).to.equal(1);
});
it('hides forecasted grants', async () => {
const result = await db.getGrantsNew(
{ bill: 'Infrastructure Investment and Jobs Act' },
{ currentPage: 1, perPage: 10, isLengthAware: true },
{ orderBy: 'open_date', orderDesc: 'true' },
fixtures.tenants.SBA.id,
fixtures.agencies.accountancy.id,
false,
false,
);
const forecastedGrant = result.data.filter((grant) => grant.opportunity_status === 'forecasted');
expect(forecastedGrant.length).to.equal(0);
});
});

context('getGrants with various filters', () => {
/*
filters: {
Expand Down
42 changes: 42 additions & 0 deletions packages/server/__tests__/db/seeds/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,48 @@ const agencyEligibilityCodes = {
};

const grants = {
forecastedGrant: {
status: 'inbox',
grant_id: '444819',
grant_number: '29-468',
agency_code: 'NSF',
award_ceiling: '6500',
cost_sharing: 'No',
title: 'Forecasted Grant',
cfda_list: '47.050',
open_date: '2100-06-21',
close_date: '2200-11-03',
notes: 'auto-inserted by script',
search_terms: '[in title/desc]+',
reviewer_name: 'none',
opportunity_category: 'Discretionary',
description: 'Grant that is forecasted',
eligibility_codes: '25',
opportunity_status: 'forecasted',
raw_body_json: {
opportunity: {
id: '444819',
number: '29-468',
title: 'Forecasted Grant',
description: 'Grant that is forecasted',
category: { name: 'Discretionary' },
milestones: { post_date: '2100-06-21', close: { date: '2200-11-03' } },
},
agency: { code: 'NSF' },
cost_sharing_or_matching_requirement: false,
cfda_numbers: ['47.050'],
eligible_applicants: [{ code: '25' }],
funding_activity: { categories: [{ code: 'ISS', name: 'Income Security and Social Services' }] },
award: { ceiling: '6500' },
bill: 'Infrastructure Investment and Jobs Act (IIJA)',
funding_instrument_types: [{ code: 'CA' }, { code: 'G' }, { code: 'PC' }],
},
funding_instrument_codes: 'CA G PC',
bill: 'Infrastructure Investment and Jobs Act (IIJA)',
funding_activity_category_codes: 'ISS',
created_at: '2024-08-11 11:30:38.89828-07',
updated_at: '2024-08-11 12:30:39.531-07',
},
earFellowship: {
status: 'inbox',
grant_id: '335255',
Expand Down
33 changes: 26 additions & 7 deletions packages/server/src/db/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ function addCsvData(qb) {
tenantId: number
agencyId: number
*/
async function getGrantsNew(filters, paginationParams, orderingParams, tenantId, agencyId, toCsv) {
async function getGrantsNew(filters, paginationParams, orderingParams, tenantId, agencyId, toCsv, showForecastedGrants = false) {
const errors = validateSearchFilters(filters);
if (errors.length > 0) {
throw new Error(`Invalid filters: ${errors.join(', ')}`);
Expand Down Expand Up @@ -751,13 +751,19 @@ async function getGrantsNew(filters, paginationParams, orderingParams, tenantId,
CASE
WHEN grants.archive_date <= now() THEN 'archived'
WHEN grants.close_date <= now() THEN 'closed'
WHEN grants.open_date > now() THEN 'forecasted'
ELSE 'posted'
END as opportunity_status
`))
.select(knex.raw(`
NULLIF(grants.award_ceiling, 0) as award_ceiling
`))
.modify((qb) => grantsQuery(qb, filters, agencyId, orderingParams, paginationParams))
.modify((qb) => {
if (!showForecastedGrants) {
qb.whereNot({ opportunity_status: 'forecasted' });
}
})
.select(knex.raw(`
count(*) OVER() AS full_count
`))
Expand Down Expand Up @@ -841,7 +847,7 @@ async function enhanceGrantData(tenantId, data) {
}

async function getGrants({
currentPage, perPage, tenantId, filters, orderBy, searchTerm, orderDesc,
currentPage, perPage, tenantId, filters, orderBy, searchTerm, orderDesc, showForecastedGrants,
} = {}) {
const data = await knex(TABLES.grants)
.modify((queryBuilder) => {
Expand All @@ -852,6 +858,9 @@ async function getGrants({
.orWhere(`${TABLES.grants}.title`, '~*', searchTerm),
);
}
if (!showForecastedGrants) {
queryBuilder.andWhereNot(`${TABLES.grants}.opportunity_status`, 'forecasted');
}
if (filters) {
if (filters.interestedByUser || filters.positiveInterest || filters.result || filters.rejected || filters.interestedByAgency) {
queryBuilder.join(TABLES.grants_interested, `${TABLES.grants}.grant_id`, `${TABLES.grants_interested}.grant_id`)
Expand Down Expand Up @@ -1002,17 +1011,27 @@ async function getGrants({
return { data: dataWithAgency, pagination };
}

async function getGrant({ grantId }) {
async function getGrant({ grantId, showForecastedGrants }) {
const results = await knex.table(TABLES.grants)
.select('*')
.where({ grant_id: grantId });
return results[0];
.where({ grant_id: grantId })
.modify((queryBuilder) => {
if (!showForecastedGrants) {
queryBuilder.whereNot({ opportunity_status: 'forecasted' });
}
});
return results.length ? results[0] : null;
}

async function getSingleGrantDetails({ grantId, tenantId }) {
async function getSingleGrantDetails({ grantId, tenantId, showForecastedGrants }) {
const results = await knex.table(TABLES.grants)
.select('*')
.where({ grant_id: grantId });
.where({ grant_id: grantId })
.modify((queryBuilder) => {
if (!showForecastedGrants) {
queryBuilder.whereNot({ opportunity_status: 'forecasted' });
}
});
const enhancedResults = await enhanceGrantData(tenantId, results);
return enhancedResults.length ? enhancedResults[0] : null;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/server/src/lib/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ async function sendGrantAssignedEmails({ grantId, agencyIds, userId }) {
i. Send email
*/
try {
const grant = await db.getGrant({ grantId });
const grant = await db.getGrant({ grantId, showForecastedGrants: process.env.SHOW_FORECASTED_GRANTS === 'true' });
const grantDetail = await buildGrantDetail(grant, notificationType.grantAssignment);
const agencies = await db.getAgenciesByIds(agencyIds);
await asyncBatch(
Expand Down Expand Up @@ -517,6 +517,7 @@ async function getAndSendGrantForSavedSearch({
{},
userSavedSearch.tenantId,
false,
process.env.SHOW_FORECASTED_GRANTS === 'true',
);

return sendGrantDigestEmail({
Expand Down
6 changes: 5 additions & 1 deletion packages/server/src/routes/grants.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ router.get('/', requireUser, async (req, res) => {
},
orderBy: req.query.orderBy,
orderDesc: req.query.orderDesc,
showForecastedGrants: process.env.SHOW_FORECASTED_GRANTS === 'true',
});
res.json(grants);
});
Expand Down Expand Up @@ -92,6 +93,7 @@ router.get('/next', requireUser, async (req, res) => {
user.tenant_id,
user.agency_id,
false,
process.env.SHOW_FORECASTED_GRANTS === 'true',
);

return res.json(grants);
Expand All @@ -101,7 +103,7 @@ router.get('/next', requireUser, async (req, res) => {
router.get('/:grantId/grantDetails', requireUser, async (req, res) => {
const { grantId } = req.params;
const { user } = req.session;
const response = await db.getSingleGrantDetails({ grantId, tenantId: user.tenant_id });
const response = await db.getSingleGrantDetails({ grantId, tenantId: user.tenant_id, showForecastedGrants: process.env.SHOW_FORECASTED_GRANTS === 'true' });
res.json(response);
});

Expand All @@ -128,6 +130,7 @@ router.get('/exportCSVNew', requireUser, async (req, res) => {
user.tenant_id,
user.agency_id,
true,
process.env.SHOW_FORECASTED_GRANTS === 'true',
);

// Generate CSV
Expand Down Expand Up @@ -214,6 +217,7 @@ router.get('/exportCSV', requireUser, async (req, res) => {
opportunityStatuses: parseCollectionQueryParam(req, 'opportunityStatuses'),
opportunityCategories: parseCollectionQueryParam(req, 'opportunityCategories'),
},
showForecastedGrants: process.env.SHOW_FORECASTED_GRANTS === 'true',
});

// Generate CSV
Expand Down
1 change: 1 addition & 0 deletions terraform/prod.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ api_log_retention_in_days = 30
api_container_environment = {
NEW_GRANT_DETAILS_PAGE_ENABLED = true
SHARE_TERMINOLOGY_ENABLED = true
SHOW_FORECASTED_GRANTS = false
}

// Postgres
Expand Down
5 changes: 3 additions & 2 deletions terraform/staging.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ api_enable_saved_search_grants_digest = true
api_enable_grant_digest_scheduled_task = true
api_log_retention_in_days = 14
api_container_environment = {
NEW_GRANT_DETAILS_PAGE_ENABLED = true,
SHARE_TERMINOLOGY_ENABLED = true,
NEW_GRANT_DETAILS_PAGE_ENABLED = true
SHARE_TERMINOLOGY_ENABLED = true
SHOW_FORECASTED_GRANTS = true
}

// Postgres
Expand Down
Loading