Skip to content

Commit

Permalink
Add national party schedule_a endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
pkfec committed Apr 18, 2024
1 parent b1e00e7 commit d89d129
Show file tree
Hide file tree
Showing 10 changed files with 603 additions and 0 deletions.
17 changes: 17 additions & 0 deletions tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,3 +651,20 @@ class Meta:
class TotalsInauguralDonationsFactory(BaseFactory):
class Meta:
model = models.InauguralDonations


class NationalParty_ScheduleAFactory(BaseFactory):
class Meta:
model = models.NationalParty_ScheduleA

sub_id = factory.Sequence(lambda n: n)
report_year = 2024
two_year_transaction_period = 2024

@factory.post_generation
def update_fulltext(obj, create, extracted, **kwargs):
obj.contributor_name_text = sa.func.to_tsvector(obj.contributor_name)
obj.contributor_employer_text = sa.func.to_tsvector(obj.contributor_employer)
obj.contributor_occupation_text = sa.func.to_tsvector(
obj.contributor_occupation
)
251 changes: 251 additions & 0 deletions tests/test_national_party.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import datetime

from tests import factories
from tests.common import ApiBaseTest
from webservices.rest import api
from webservices.schemas import NationalPartyScheduleASchema
from webservices.resources.national_party import NationalParty_ScheduleAView


class TestNationalParty(ApiBaseTest):
kwargs = {'two_year_transaction_period': 2024}

def test_fields(self):

params = [
(factories.NationalParty_ScheduleAFactory, NationalParty_ScheduleAView, NationalPartyScheduleASchema)
]
for factory, resource, schema in params:
factory()
results = self._results(api.url_for(resource, **self.kwargs))
self.assertEqual(len(results), 1)
self.assertEqual(results[0].keys(), schema().fields.keys())

def test_multiple_two_year_transaction_period(self):
"""
testing schedule_a api can take multiple cycles now
"""
receipts = [ # noqa
factories.NationalParty_ScheduleAFactory(
report_year=2014,
contribution_receipt_date=datetime.date(2014, 1, 1),
two_year_transaction_period=2014,
committee_id='C00000001',
),
factories.NationalParty_ScheduleAFactory(
report_year=2016,
contribution_receipt_date=datetime.date(2016, 1, 1),
two_year_transaction_period=2016,
committee_id='C00000001',
),
factories.NationalParty_ScheduleAFactory(
report_year=2018,
contribution_receipt_date=datetime.date(2018, 1, 1),
two_year_transaction_period=2018,
committee_id='C00000001',
),
]
response = self._response(
api.url_for(
NationalParty_ScheduleAView,
two_year_transaction_period=[2016, 2018],
committee_id='C00000001',
)
)
self.assertEqual(len(response['results']), 2)

def test_multiple_cmte_id_and_two_year_transaction_period(self):
"""
testing schedule_a api can take multiple cycles now
"""
receipts = [ # noqa
factories.NationalParty_ScheduleAFactory(
report_year=2014,
contribution_receipt_date=datetime.date(2014, 1, 1),
two_year_transaction_period=2014,
committee_id='C00000001',
),
factories.NationalParty_ScheduleAFactory(
report_year=2016,
contribution_receipt_date=datetime.date(2016, 1, 1),
two_year_transaction_period=2016,
committee_id='C00000001',
),
factories.NationalParty_ScheduleAFactory(
report_year=2018,
contribution_receipt_date=datetime.date(2018, 1, 1),
two_year_transaction_period=2018,
committee_id='C00000001',
),
factories.NationalParty_ScheduleAFactory(
report_year=2014,
contribution_receipt_date=datetime.date(2014, 1, 1),
two_year_transaction_period=2014,
committee_id='C00000002',
),
factories.NationalParty_ScheduleAFactory(
report_year=2016,
contribution_receipt_date=datetime.date(2016, 1, 1),
two_year_transaction_period=2016,
committee_id='C00000002',
),
factories.NationalParty_ScheduleAFactory(
report_year=2018,
contribution_receipt_date=datetime.date(2018, 1, 1),
two_year_transaction_period=2018,
committee_id='C00000002',
),
factories.NationalParty_ScheduleAFactory(
report_year=2014,
contribution_receipt_date=datetime.date(2014, 1, 1),
two_year_transaction_period=2014,
committee_id='C00000003',
),
factories.NationalParty_ScheduleAFactory(
report_year=2016,
contribution_receipt_date=datetime.date(2016, 1, 1),
two_year_transaction_period=2016,
committee_id='C00000003',
),
factories.NationalParty_ScheduleAFactory(
report_year=2018,
contribution_receipt_date=datetime.date(2018, 1, 1),
two_year_transaction_period=2018,
committee_id='C00000003',
),
]
response = self._response(
api.url_for(
NationalParty_ScheduleAView,
two_year_transaction_period=[2016, 2018],
committee_id=['C00000001', 'C00000002'],
)
)
self.assertEqual(len(response['results']), 4)
response = self._response(
api.url_for(
NationalParty_ScheduleAView,
committee_id='C00000001',
)
)
self.assertEqual(len(response['results']), 3)

def test_schedule_a_two_year_transaction_period_limits_results_per_cycle(self):
receipts = [ # noqa
factories.NationalParty_ScheduleAFactory(
report_year=2014,
contribution_receipt_date=datetime.date(2014, 1, 1),
two_year_transaction_period=2014,
),
factories.NationalParty_ScheduleAFactory(
report_year=2012,
contribution_receipt_date=datetime.date(2012, 1, 1),
two_year_transaction_period=2012,
),
]
response = self._response(
api.url_for(NationalParty_ScheduleAView, two_year_transaction_period=2014)
)
self.assertEqual(len(response['results']), 1)

def test_sorting_bad_column(self):
response = self.app.get(api.url_for(NationalParty_ScheduleAView, sort='bad_column'))
self.assertEqual(response.status_code, 422)
self.assertIn(b'Cannot sort on value', response.data)

def test_filterby_contributor_state(self):
[
factories.NationalParty_ScheduleAFactory(contributor_state='NY'),
factories.NationalParty_ScheduleAFactory(contributor_state='CA'),
]
results = self._results(
api.url_for(NationalParty_ScheduleAView, contributor_state='CA', **self.kwargs)
)
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['contributor_state'], 'CA')

def test_filterby_zip(self):
[
factories.NationalParty_ScheduleAFactory(contributor_zip=96789),
factories.NationalParty_ScheduleAFactory(contributor_zip=9678912),
factories.NationalParty_ScheduleAFactory(contributor_zip=967891234),
factories.NationalParty_ScheduleAFactory(contributor_zip='M4C 1M7'),
]
results = self._results(
api.url_for(NationalParty_ScheduleAView, contributor_zip=96789, **self.kwargs)
)
self.assertEqual(len(results), 3)

results = self._results(
api.url_for(NationalParty_ScheduleAView, contributor_zip='M4C 1M55', **self.kwargs)
)
self.assertEqual(len(results), 1)

contributor_zips = ['M4C 1M5555', 96789]
results = self._results(
api.url_for(NationalParty_ScheduleAView, contributor_zip=contributor_zips, **self.kwargs)
)
self.assertEqual(len(results), 4)

def test_invalid_zip(self):
response = self.app.get(
api.url_for(NationalParty_ScheduleAView, contributor_zip='96%')
)
self.assertEqual(response.status_code, 422)

def test_committee_contributor_type_filter(self):
[
factories.NationalParty_ScheduleAFactory(committee_contributor_type='S'),
factories.NationalParty_ScheduleAFactory(committee_contributor_type='S'),
factories.NationalParty_ScheduleAFactory(committee_contributor_type='P'),
]
results = self._results(
api.url_for(NationalParty_ScheduleAView, committee_contributor_type='S', **self.kwargs)
)
self.assertEqual(len(results), 2)

def test_committee_contributor_designation_type_filter(self):
[
factories.NationalParty_ScheduleAFactory(committee_contributor_designation='J'),
factories.NationalParty_ScheduleAFactory(committee_contributor_designation='U'),
factories.NationalParty_ScheduleAFactory(committee_contributor_designation='J'),
]
results = self._results(
api.url_for(NationalParty_ScheduleAView, committee_contributor_designation='J', **self.kwargs)
)
self.assertEqual(len(results), 2)

def test_filter_multi_start_with(self):
[
factories.NationalParty_ScheduleAFactory(contributor_zip='1296789')
]
results = self._results(
api.url_for(NationalParty_ScheduleAView, contributor_zip='96789')
)
self.assertEqual(len(results), 0)

def test_filter_case_insensitive(self):
[
factories.NationalParty_ScheduleAFactory(contributor_city='NEW YORK'),
factories.NationalParty_ScheduleAFactory(contributor_city='DES MOINES'),
]
results = self._results(
api.url_for(NationalParty_ScheduleAView, contributor_city='new york', **self.kwargs)
)
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['contributor_city'], 'NEW YORK')

def test_filter_fulltext(self):
"""
Note: this is the only test for filter_fulltext.
If this is removed, please add a test to test_filters.py
"""
names = ['David Koch', 'George Soros']
[
factories.NationalParty_ScheduleAFactory(contributor_name=name) for name in names
]
results = self._results(
api.url_for(NationalParty_ScheduleAView, contributor_name='soros', **self.kwargs)
)
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['contributor_name'], 'George Soros')
66 changes: 66 additions & 0 deletions webservices/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -1347,3 +1347,69 @@ def make_seek_args(field=fields.Int, description=None):
'contributor_name': fields.List(IStr, description=docs.CONTRIBUTOR_NAME),
'cycle': fields.List(fields.Int(), description=docs.COMMITTEE_CYCLE)
}

# Used for endpoint `/national_party/schedule_a/`
# under tag: national party
national_party_schedule_a = {
'committee_id': fields.List(Committee_ID, description=docs.COMMITTEE_ID),
'contributor_id': fields.List(IStr, description=docs.CONTRIBUTOR_ID),
'two_year_transaction_period': fields.List(
TwoYearTransactionPeriod,
description=docs.TWO_YEAR_TRANSACTION_PERIOD,
),
'min_date': Date(description='Minimum date'),
'max_date': Date(description='Maximum date'),
'contributor_name': fields.List(Keyword, description=docs.CONTRIBUTOR_NAME),
'contributor_city': fields.List(IStr, description=docs.CONTRIBUTOR_CITY),
'contributor_state': fields.List(IStr, description=docs.CONTRIBUTOR_STATE),
'contributor_zip': fields.List(IStr, description=docs.CONTRIBUTOR_ZIP),
'contributor_occupation': fields.List(Keyword, description=docs.CONTRIBUTOR_OCCUPATION),
'contributor_employer': fields.List(Keyword, description=docs.CONTRIBUTOR_EMPLOYER),
'image_number': fields.List(IStr, description=docs.IMAGE_NUMBER),
'contributor_committee_type': fields.List(Keyword, description=docs.CONTRIBUTOR_EMPLOYER),
'contribution_receipt_date': Date(
missing=None,
description='When sorting by `contb_receipt_dt`, this is populated with the \
`contb_receipt_dt` of the last result. However, you will need to pass the index \
of that last result to `last_index` to get the next page.'
),
'contribution_receipt_amount': fields.Float(
missing=None,
description='When sorting by `contb_receipt_amt`, this is populated with the \
`contb_receipt_amt` of the last result. However, you will need to pass the index \
of that last result to `last_index` to get the next page.'
),
'line_number': fields.Str(description=docs.LINE_NUMBER),
'is_individual': fields.Bool(missing=None, description=docs.IS_INDIVIDUAL),
'contributor_type': fields.List(
fields.Str(validate=validate.OneOf(['individual', 'committee'])),
description='Filters individual or committee contributions based on line number'
),
'committee_contributor_type': fields.List(
IStr(validate=validate.OneOf([
'', 'C', 'D', 'E', 'H', 'I', 'N', 'O', 'P', 'Q',
'S', 'U', 'V', 'W', 'X', 'Y', 'Z'])),
description=docs.COMMITTEE_TYPE,
),
# 'committee_contributor_organization_type': fields.List(
# IStr(validate=validate.OneOf(['', 'C', 'L', 'M', 'T', 'V', 'W'])),
# description=docs.ORGANIZATION_TYPE,
# ),
'committee_contributor_designation': fields.List(
IStr(validate=validate.OneOf(['', 'A', 'J', 'P', 'U', 'B', 'D'])),
description=docs.DESIGNATION,
),
'min_amount': Currency(description='Filter for all amounts greater than a value.'),
'max_amount': Currency(description='Filter for all amounts less than a value.'),
'party_account_type': fields.List(
IStr(validate=validate.OneOf(['', 'CONVENTION', 'HEADQUARTERS', 'RECOUNT'])),
description='National party account type',
),
'party_account_receipt_type': fields.List(
IStr(validate=validate.OneOf([
'30', '30E', '30F', '30G', '30J', '30K', '30T',
'31', '31E', '31F', '31G', '31J', '31K', '31T',
'32', '32E', '32F', '32G', '32J', '32K', '32T'])),
description='National party account receipt type',
),
}
1 change: 1 addition & 0 deletions webservices/common/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
from .audit import * # noqa
from .operations_log import * # noqa
from .presidential import * # noqa
from .national_party import * # noqa
Loading

0 comments on commit d89d129

Please sign in to comment.