webservices/args.py

Summary

Maintainability
F
3 days
Test Coverage
import functools

from marshmallow.compat import text_type

import sqlalchemy as sa

from webargs import ValidationError, fields, validate

from webservices import docs
from webservices.common.models import db
from webservices.config import SQL_CONFIG

def _validate_natural(value):
    if value < 0:
        raise ValidationError('Must be a natural number')

Natural = functools.partial(fields.Int, validate=_validate_natural)

per_page = Natural(
    missing=20,
    description='The number of results returned per page. Defaults to 20.',
)

class Currency(fields.Decimal):

    def __init__(self, places=2, **kwargs):
        super().__init__(places=places, **kwargs)

    def _validated(self, value):
        if isinstance(value, text_type):
            value = value.lstrip('$').replace(',', '')
        return super()._validated(value)


class IStr(fields.Str):

    def _deserialize(self, value, attr, data):
        return super()._deserialize(value, attr, data).upper()

class District(fields.Str):

    def _validate(self, value):
        super()._validate(value)
        try:
            value = int(value)
        except (TypeError, ValueError):
            raise ValidationError('District must be a number')
        if value < 0:
            raise ValidationError('District must be a natural number')

    def _deserialize(self, value, attr, data):
        return '{0:0>2}'.format(value)

election_full = fields.Bool(missing=False, description='Aggregate values over full election period')

paging = {
    'page': Natural(missing=1, description='For paginating through results, starting at page 1'),
    'per_page': per_page,
}


class OptionValidator(object):
    """Ensure that value is one of acceptable options.

    :param list values: Valid options.
    """
    def __init__(self, values):
        self.values = values

    def __call__(self, value):
        if value.lstrip('-') not in self.values:
            raise ValidationError(
                'Cannot sort on value "{0}"'.format(value),
                status_code=422
            )


class IndexValidator(OptionValidator):
    """Ensure that value is an indexed column on the specified model.

    :param Base model: SQLALchemy model.
    :param list exclude: Optional list of columns to exclude.
    """
    def __init__(self, model, extra=None, exclude=None, schema=None):
        self.model = model
        self.extra = extra or []
        self.exclude = exclude or []
        self.database_schema = schema

    @property
    def values(self):
        inspector = sa.inspect(db.engine)
        column_map = {
            column.key: label
            for label, column in self.model.__mapper__.columns.items()
        }
        return [
            column_map[column['column_names'][0]]
            for column in inspector.get_indexes(self.model.__tablename__, self.database_schema)
            if not self._is_excluded(column_map.get(column['column_names'][0]))
        ] + self.extra

    def _is_excluded(self, value):
        return not value or value in self.exclude


class IndicesValidator(IndexValidator):

    def __call__(self, value):
        for sort_column in value:
            if sort_column.lstrip('-') not in self.values:
                raise ValidationError(
                    'Cannot sort on value "{0}"'.format(value),
                    status_code=422
                )

def make_sort_args(default=None, validator=None, default_hide_null=False, default_reverse_nulls=True,
        default_nulls_only=False):
    return {
        'sort': fields.Str(
            missing=default,
            validate=validator,
            description='Provide a field to sort by. Use - for descending order.',
        ),
        'sort_hide_null': fields.Bool(
            missing=default_hide_null,
            description='Hide null values on sorted column(s).'
        ),
        'sort_null_only': fields.Bool(
            missing=default_nulls_only,
            description='Toggle that filters out all rows having sort column that is non-null'
        )
    }


def make_multi_sort_args(default=None, validator=None, default_hide_null=False, default_reverse_nulls=True,
        default_nulls_only=False):
    args = make_sort_args(default, validator, default_hide_null, default_reverse_nulls, default_nulls_only)
    args['sort'] = fields.List(fields.Str, missing=default, validate=validator, required=False, allow_none=True,
        description='Provide a field to sort by. Use - for descending order.',)
    return args

def make_seek_args(field=fields.Int, description=None):
    return {
        'per_page': per_page,
        'last_index': field(
            missing=None,
            description=description or 'Index of last result from previous page',
        ),
    }

names = {
    'q': fields.List(fields.Str, required=True, description='Name (candidate or committee) to search for'),
}

query = {
    'q': fields.Str(required=False, description='Text to search legal documents for.'),
    'from_hit': fields.Int(required=False, description='Get results starting from this index.'),
    'hits_returned': fields.Int(required=False, description='Number of results to return (max 10).'),
    'type': fields.Str(required=False, description='Document type to refine search by'),
    'ao_no': fields.List(IStr, required=False, description='Force advisory opinion number'),
    'ao_name': fields.List(IStr, required=False, description='Force advisory opinion name'),
    'ao_min_issue_date': fields.Date(description="Earliest issue date of advisory opinion"),
    'ao_max_issue_date': fields.Date(description="Latest issue date of advisory opinion"),
    'ao_min_request_date': fields.Date(description="Earliest request date of advisory opinion"),
    'ao_max_request_date': fields.Date(description="Latest request date of advisory opinion"),
    'ao_category': fields.List(IStr(validate=validate.OneOf(['F', 'V', 'D', 'R', 'W', 'C', 'S'])),
                                    description="Category of the document"),
    'ao_is_pending': fields.Bool(description="AO is pending"),
    'ao_status': fields.Str(description="Status of AO (pending, withdrawn, or final)"),
    'ao_requestor': fields.Str(description="The requestor of the advisory opinion"),
    'ao_requestor_type': fields.List(fields.Integer(validate=validate.OneOf(range(1, 17))),
                                            description="Code of the advisory opinion requestor type."),
    'ao_regulatory_citation': fields.List(IStr, required=False, description="Search for regulatory citations"),
    'ao_statutory_citation': fields.List(IStr, required=False, description="Search for statutory citations"),
    'ao_citation_require_all': fields.Bool(
        description="Require all citations to be in document (default behavior is any)"),
    'ao_entity_name': fields.List(IStr, required=False, description='Search by name of commenter or representative'),
    'mur_no': fields.List(IStr, required=False, description='Filter MURs by case number'),
    'mur_respondents': fields.Str(IStr, required=False, description='Filter MURs by respondents'),
    'mur_dispositions': fields.List(IStr, required=False, description='Filter MURs by dispositions'),
    'mur_election_cycles': fields.Int(IStr, required=False, description='Filter MURs by election cycles'),
    'mur_document_category': fields.List(IStr, required=False,
        description='Filter MURs by category of associated documents'),
    'mur_min_open_date': fields.Date(required=False, description='Filter MURs by earliest date opened'),
    'mur_max_open_date': fields.Date(required=False, description='Filter MURs by latest date opened'),
    'mur_min_close_date': fields.Date(required=False,
        description='Filter MURs by earliest date closed'),
    'mur_max_close_date': fields.Date(required=False,
        description='Filter MURs by latest date closed'),
}

candidate_detail = {
    'cycle': fields.List(fields.Int, description=docs.CANDIDATE_CYCLE),
    'election_year': fields.List(fields.Int, description=docs.ELECTION_YEAR),
    'office': fields.List(fields.Str(validate=validate.OneOf(['', 'H', 'S', 'P'])), description=docs.OFFICE),
    'state': fields.List(IStr, description=docs.STATE),
    'party': fields.List(IStr, description=docs.PARTY),
    'year': fields.Str(attribute='year', description=docs.YEAR),
    'district': fields.List(District, description=docs.DISTRICT),
    'candidate_status': fields.List(
        IStr(validate=validate.OneOf(['', 'C', 'F', 'N', 'P'])),
        description=docs.CANDIDATE_STATUS,
    ),
    'incumbent_challenge': fields.List(
        IStr(validate=validate.OneOf(['', 'I', 'C', 'O'])),
        description=docs.INCUMBENT_CHALLENGE,
    ),
    'federal_funds_flag': fields.Bool(description=docs.FEDERAL_FUNDS_FLAG),
    'has_raised_funds': fields.Bool(description=docs.HAS_RAISED_FUNDS),
    'name': fields.List(fields.Str, description='Name (candidate or committee) to search for. Alias for \'q\'.'),
}

candidate_list = {
    'q': fields.List(fields.Str, description=docs.CANDIDATE_NAME),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'min_first_file_date': fields.Date(description='Selects all candidates whose first filing was received by the FEC after this date'),
    'max_first_file_date': fields.Date(description='Selects all candidates whose first filing was received by the FEC before this date'),
}

candidate_history = {
    'election_full': election_full,
}

committee = {
    'year': fields.List(fields.Int, description=docs.COMMITTEE_YEAR),
    'cycle': fields.List(fields.Int, description=docs.COMMITTEE_CYCLE),
    'designation': fields.List(
        IStr(validate=validate.OneOf(['', 'A', 'J', 'P', 'U', 'B', 'D'])),
        description=docs.DESIGNATION,
    ),
    'organization_type': fields.List(
        IStr(validate=validate.OneOf(['', 'C', 'L', 'M', 'T', 'V', 'W'])),
        description=docs.ORGANIZATION_TYPE,
    ),
    'committee_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_list = {
    'q': fields.List(fields.Str, description=docs.COMMITTEE_NAME),
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'state': fields.List(IStr, description=docs.STATE_GENERIC),
    'party': fields.List(IStr, description=docs.PARTY),
    'min_first_file_date': fields.Date(description='Selects all committees whose first filing was received by the FEC after this date'),
    'max_first_file_date': fields.Date(description='Selects all committees whose first filing was received by the FEC before this date'),
    'treasurer_name': fields.List(fields.Str, description=docs.TREASURER_NAME),
}

committee_history = {
    'election_full': election_full,
}

filings = {
    'committee_type': fields.Str(description=docs.COMMITTEE_TYPE),
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'is_amended': fields.Bool(description='Filing has been amended'),
    'most_recent': fields.Bool(description='Filing is either new or is the most-recently filed amendment'),
    'report_type': fields.List(IStr, description=docs.REPORT_TYPE),
    'request_type': fields.List(IStr, description=docs.REQUEST_TYPE),
    'document_type': fields.List(IStr, description=docs.DOC_TYPE),
    'beginning_image_number': fields.List(fields.Str, description=docs.BEGINNING_IMAGE_NUMBER),
    'report_year': fields.List(fields.Int, description=docs.REPORT_YEAR),
    'min_receipt_date': fields.Date(description='Selects all items received by FEC after this date'),
    'max_receipt_date': fields.Date(description='Selects all items received by FEC before this date'),
    'form_type': fields.List(IStr, description=docs.FORM_TYPE),
    'state': fields.List(IStr, description=docs.STATE),
    'district': fields.List(IStr, description=docs.DISTRICT),
    'office': fields.List(fields.Str(validate=validate.OneOf(['', 'H', 'S', 'P'])), description=docs.OFFICE),
    'party': fields.List(IStr, description=docs.PARTY),
    'filer_type': fields.Str(
        validate=validate.OneOf(['e-file', 'paper']),
        description=docs.MEANS_FILED,
    ),
    'file_number': fields.List(fields.Int, description=docs.FILE_NUMBER),
    'primary_general_indicator': fields.List(IStr, description='Primary, general or special election indicator'),
    'amendment_indicator': fields.List(
        IStr(validate=validate.OneOf(['', 'N', 'A', 'T', 'C' , 'M', 'S'])),
        description=docs.AMENDMENT_INDICATOR),
}

efilings = {
    'file_number': fields.List(fields.Int, description=docs.FILE_NUMBER),
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'min_receipt_date': fields.DateTime(description='Selects all items received by FEC after this date or datetime'),
    'max_receipt_date': fields.DateTime(description='Selects all items received by FEC before this date or datetime'),
}

reports = {
    'year': fields.List(fields.Int, description=docs.REPORT_YEAR),
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'beginning_image_number': fields.List(fields.Str, description=docs.BEGINNING_IMAGE_NUMBER),
    'report_type': fields.List(fields.Str, description=docs.REPORT_TYPE_W_EXCLUDE),
    'is_amended': fields.Bool(description='Report has been amended'),
    'most_recent': fields.Bool(description='Report is either new or is the most-recently filed amendment'),
    'filer_type': fields.Str(
        validate=validate.OneOf(['e-file', 'paper']),
        description=docs.MEANS_FILED,
    ),
    'min_disbursements_amount': Currency(description=docs.MIN_FILTER),
    'max_disbursements_amount': Currency(description=docs.MAX_FILTER),
    'min_receipts_amount': Currency(description=docs.MIN_FILTER),
    'max_receipts_amount': Currency(description=docs.MAX_FILTER),
    'min_receipt_date': fields.DateTime(description='Selects all items received by FEC after this date or datetime'),
    'max_receipt_date': fields.DateTime(description='Selects all items received by FEC before this date or datetime'),
    'min_cash_on_hand_end_period_amount': Currency(description=docs.MIN_FILTER),
    'max_cash_on_hand_end_period_amount': Currency(description=docs.MAX_FILTER),
    'min_debts_owed_amount': Currency(description=docs.MIN_FILTER),
    'max_debts_owed_expenditures': Currency(description=docs.MAX_FILTER),
    'min_independent_expenditures': Currency(description=docs.MIN_FILTER),
    'max_independent_expenditures': Currency(description=docs.MAX_FILTER),
    'min_party_coordinated_expenditures': Currency(description=docs.MIN_FILTER),
    'max_party_coordinated_expenditures': Currency(description=docs.MAX_FILTER),
    'min_total_contributions': Currency(description=docs.MIN_FILTER),
    'max_total_contributions': Currency(description=docs.MAX_FILTER),
    'type': fields.List(fields.Str, description=docs.COMMITTEE_TYPE),
    'candidate_id': fields.Str(description=docs.CANDIDATE_ID),
    'committee_id': fields.List(fields.Str, description=docs.COMMITTEE_ID),
    'amendment_indicator': fields.List(
        IStr(validate=validate.OneOf(['', 'N', 'A', 'T', 'C' , 'M', 'S'])),
        description=docs.AMENDMENT_INDICATOR),
}

committee_reports = {
    'year': fields.List(fields.Int, description=docs.REPORT_YEAR),
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'beginning_image_number': fields.List(fields.Str, description=docs.BEGINNING_IMAGE_NUMBER),
    'report_type': fields.List(fields.Str, description=docs.REPORT_TYPE_W_EXCLUDE),
    'is_amended': fields.Bool(description='Report has been amended'),
    'min_disbursements_amount': Currency(description=docs.MIN_FILTER),
    'max_disbursements_amount': Currency(description=docs.MAX_FILTER),
    'min_receipts_amount': Currency(description=docs.MIN_FILTER),
    'max_receipts_amount': Currency(description=docs.MAX_FILTER),
    'min_cash_on_hand_end_period_amount': Currency(description=docs.MIN_FILTER),
    'max_cash_on_hand_end_period_amount': Currency(description=docs.MAX_FILTER),
    'min_debts_owed_amount': Currency(description=docs.MIN_FILTER),
    'max_debts_owed_expenditures': Currency(description=docs.MAX_FILTER),
    'min_independent_expenditures': Currency(description=docs.MIN_FILTER),
    'max_independent_expenditures': Currency(description=docs.MAX_FILTER),
    'min_party_coordinated_expenditures': Currency(description=docs.MIN_FILTER),
    'max_party_coordinated_expenditures': Currency(description=docs.MAX_FILTER),
    'min_total_contributions': Currency(description=docs.MIN_FILTER),
    'max_total_contributions': Currency(description=docs.MAX_FILTER),
    'type': fields.List(fields.Str, description=docs.COMMITTEE_TYPE),
    'candidate_id': fields.Str(description=docs.CANDIDATE_ID),
}

totals = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'type': fields.Str(description=docs.COMMITTEE_TYPE),
    'designation': fields.Str(description=docs.DESIGNATION),
}

totals_all = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'committee_type_full': fields.Str(description=docs.COMMITTEE_TYPE),
    'committee_designation_full': fields.Str(description=docs.DESIGNATION),
    'committee_id': fields.Str(description=docs.COMMITTEE_ID),
}

candidate_committee_totals = {
    'full_election': fields.Bool(description='Get totals for full election period.')
}


itemized = {
    # TODO(jmcarp) Request integer image numbers from FEC and update argument types
    'image_number': fields.List(
        fields.Str,
        description='The image number of the page where the schedule item is reported',
    ),
    'min_image_number': fields.Str(),
    'max_image_number': fields.Str(),
    'min_amount': Currency(description='Filter for all amounts greater than a value.'),
    'max_amount': Currency(description='Filter for all amounts less than a value.'),
    'min_date': fields.Date(description='Minimum date'),
    'max_date': fields.Date(description='Maximum date'),
    'line_number': fields.Str(description='Filter for form and line number using the following format: '
                                          '`FORM-LINENUMBER`.  For example an argument such as `F3X-16` would filter'
                                          ' down to all entries from form `F3X` line number `16`.')
}

reporting_dates = {
    'min_due_date': fields.Date(description='Date the report is due'),
    'max_due_date': fields.Date(description='Date the report is due'),
    'report_year': fields.List(fields.Int, description='Year of report'),
    'report_type': fields.List(fields.Str, description=docs.REPORT_TYPE),
    'min_create_date': fields.Date(description='Date this record was added to the system'),
    'max_create_date': fields.Date(description='Date this record was added to the system'),
    'min_update_date': fields.Date(description='Date this record was last updated'),
    'max_update_date': fields.Date(description='Date this record was last updated'),
}

election_dates = {
    'election_state': fields.List(fields.Str, description='State or territory of the office sought'),
    'election_district': fields.List(fields.Str, description='House district of the office sought, if applicable.'),
    'election_party': fields.List(fields.Str, description='Party, if applicable.'),
    'office_sought': fields.List(fields.Str(validate=validate.OneOf(['H', 'S', 'P'])), description='House, Senate or presidential office'),
    'min_election_date': fields.Date(description='Date of election'),
    'max_election_date': fields.Date(description='Date of election'),
    'election_type_id': fields.List(fields.Str, description='Election type'),
    'min_update_date': fields.Date(description='Date this record was last updated'),
    'max_update_date': fields.Date(description='Date this record was last updated'),
    'min_create_date': fields.Date(description='Date this record was added to the system'),
    'max_create_date': fields.Date(description='Date this record was added to the system'),
    'election_year': fields.List(fields.Str, description='Year of election'),
    'min_primary_general_date': fields.Date(description='Date of primary or general election'),
    'max_primary_general_date': fields.Date(description='Date of primary or general election'),
}

calendar_dates = {
    'calendar_category_id': fields.List(fields.Int, description=docs.CATEGORY),
    'description': fields.List(IStr, description=docs.CAL_DESCRIPTION),
    'summary': fields.List(IStr, description=docs.SUMMARY),
    'min_start_date': fields.DateTime(description='The minimum start date and time'),
    'min_end_date': fields.DateTime(description='The minimum end date and time'),
    'max_start_date': fields.DateTime(description='The maximum start date and time'),
    'max_end_date': fields.DateTime(description='The maximum end date and time'),
    'event_id': fields.Int(description=docs.EVENT_ID),
}

schedule_a = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'contributor_id': fields.List(IStr, description=docs.CONTRIBUTOR_ID),
    'contributor_name': fields.List(fields.Str, 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_employer': fields.List(fields.Str, description=docs.CONTRIBUTOR_EMPLOYER),
    'contributor_occupation': fields.List(fields.Str, description=docs.CONTRIBUTOR_OCCUPATION),
    'last_contribution_receipt_date': fields.Date(missing=None, description='When sorting by `contribution_receipt_date`, this is populated with the `contribution_receipt_date` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'last_contribution_receipt_amount': fields.Float(missing=None, description='When sorting by `contribution_receipt_amount`, this is populated with the `contribution_receipt_amount` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'last_contributor_aggregate_ytd': fields.Float(missing=None, description='When sorting by `contributor_aggregate_ytd`, this is populated with the `contributor_aggregate_ytd` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    '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'
    ),
    'two_year_transaction_period': fields.Int(
        description=docs.TWO_YEAR_TRANSACTION_PERIOD,
        required=True,
        missing=SQL_CONFIG['CYCLE_END_YEAR_ITEMIZED']
    ),
}

schedule_a_e_file = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    #'contributor_id': fields.List(IStr, description=docs.CONTRIBUTOR_ID),
    'contributor_name': fields.List(fields.Str, description=docs.CONTRIBUTOR_NAME),
    'contributor_city': fields.List(IStr, description=docs.CONTRIBUTOR_CITY),
    'contributor_state': fields.List(IStr, description=docs.CONTRIBUTOR_STATE),
    'contributor_employer': fields.List(fields.Str, description=docs.CONTRIBUTOR_EMPLOYER),
    'contributor_occupation': fields.List(fields.Str, description=docs.CONTRIBUTOR_OCCUPATION),

}

schedule_a_by_size = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'size': fields.List(fields.Int(validate=validate.OneOf([0, 200, 500, 1000, 2000])), description=docs.SIZE),
}

schedule_a_by_state = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'state': fields.List(IStr, description='State of contributor'),
    'hide_null': fields.Bool(missing=False, description='Exclude values with missing state'),
}

schedule_a_by_zip = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'zip': fields.List(fields.Str, description='Zip code'),
    'state': fields.List(IStr, description='State of contributor'),
}

schedule_a_by_employer = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'employer': fields.List(IStr, description=docs.EMPLOYER),
}

schedule_a_by_occupation = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'occupation': fields.List(IStr, description=docs.OCCUPATION),
}

schedule_a_by_contributor = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'contributor_id': fields.List(IStr, description=docs.CONTRIBUTOR_ID),
}

schedule_b_by_recipient = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'recipient_name': fields.List(fields.Str, description=docs.RECIPIENT_NAME),
}

schedule_b_by_recipient_id = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'recipient_id': fields.List(IStr, description=docs.RECIPIENT_ID),
}

schedule_b = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'recipient_committee_id': fields.List(IStr, description='The FEC identifier should be represented here if the contributor is registered with the FEC.'),
    'recipient_name': fields.List(fields.Str, description='Name of recipient'),
    'disbursement_description': fields.List(fields.Str, description='Description of disbursement'),
    'recipient_city': fields.List(IStr, description='City of recipient'),
    'recipient_state': fields.List(IStr, description='State of recipient'),
    'disbursement_purpose_category': fields.List(IStr, description='Disbursement purpose category'),
    'last_disbursement_date': fields.Date(missing=None, description='When sorting by `disbursement_date`, this is populated with the `disbursement_date` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'last_disbursement_amount': fields.Float(missing=None, description='When sorting by `disbursement_amount`, this is populated with the `disbursement_amount` of the last result.  However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'two_year_transaction_period': fields.Int(
        description=docs.TWO_YEAR_TRANSACTION_PERIOD,
        required=True,
        missing=SQL_CONFIG['CYCLE_END_YEAR_ITEMIZED']
    ),
}

schedule_b_efile = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    #'recipient_committee_id': fields.List(IStr, description='The FEC identifier should be represented here if the contributor is registered with the FEC.'),
    #'recipient_name': fields.List(fields.Str, description='Name of recipient'),
    'disbursement_description': fields.List(fields.Str, description='Description of disbursement'),
    'image_number': fields.List(
        fields.Str,
        description='The image number of the page where the schedule item is reported',
    ),
    'recipient_city': fields.List(IStr, description='City of recipient'),
    'recipient_state': fields.List(IStr, description='State of recipient'),
    'max_date': fields.Date(missing=None, description='When sorting by `disbursement_date`, this is populated with the `disbursement_date` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'min_date': fields.Date(missing=None, description='When sorting by `disbursement_date`, this is populated with the `disbursement_date` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'min_amount': Currency(description='Filter for all amounts less than a value.'),
    'max_amount': Currency(description='Filter for all amounts less than a value.'),
}

schedule_b_by_purpose = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'purpose': fields.List(fields.Str, description='Disbursement purpose category'),
}

schedule_c = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'candidate_name': fields.List(fields.Str, description=docs.CANDIDATE_NAME),
    'loaner_name': fields.List(fields.Str, description=docs.LOAN_SOURCE),
    'min_payment_to_date': fields.Int(description='Minimum payment to date'),
    'max_payment_to_date': fields.Int(description='Maximum payment to date'),

}

schedule_e_by_candidate = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'support_oppose': IStr(
        missing=None,
        validate=validate.OneOf(['S', 'O']),
        description='Support or opposition'
    ),
}
#These arguments will evolve with updated filtering needs
schedule_d = {
    'min_payment_period': fields.Float(),
    'max_payment_period': fields.Float(),
    'min_amount_incurred': fields.Float(),
    'max_amount_incurred': fields.Float(),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'creditor_debtor_name': fields.List(fields.Str),
    'nature_of_debt': fields.Str(),
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
}

schedule_f = {
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'payee_name': fields.List(fields.Str),
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
}

communication_cost = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'support_oppose_indicator': fields.List(
        IStr(validate=validate.OneOf(['S', 'O'])),
        description='Support or opposition',
    ),
}

electioneering = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'report_year': fields.List(fields.Int, description=docs.REPORT_YEAR),
    'min_amount': Currency(description='Filter for all amounts greater than a value.'),
    'max_amount': Currency(description='Filter for all amounts less than a value.'),
    'min_date': fields.Date(description='Minimum disbursement date'),
    'max_date': fields.Date(description='Maximum disbursement date'),
    'description': fields.Str('Disbursement description'),
}

electioneering_by_candidate = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
}

elections_list = {
    'state': fields.List(IStr, description=docs.STATE),
    'district': fields.List(District, description=docs.DISTRICT),
    'cycle': fields.List(fields.Int, description=docs.CANDIDATE_CYCLE),
    'zip': fields.List(fields.Int, description=docs.ZIP_CODE),
    'office': fields.List(
        fields.Str(validate=validate.OneOf(['house', 'senate', 'president'])),
    ),
}

elections = {
    'state': IStr(description=docs.STATE),
    'district': District(description=docs.DISTRICT),
    'cycle': fields.Int(description=docs.CANDIDATE_CYCLE),
    'office': fields.Str(
        validate=validate.OneOf(['house', 'senate', 'president']),
        description=docs.OFFICE,
    ),
    'election_full': election_full,
}

schedule_a_candidate_aggregate = {
    'candidate_id': fields.List(IStr, required=True, description=docs.CANDIDATE_ID),
    'cycle': fields.List(fields.Int, required=True, description=docs.RECORD_CYCLE),
    'election_full': election_full,
}

candidate_totals = {
    'q': fields.List(fields.Str, description=docs.CANDIDATE_NAME),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'election_year': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'office': fields.List(fields.Str(validate=validate.OneOf(['', 'H', 'S', 'P'])), description='Governmental office candidate runs for: House, Senate or presidential'),
    'election_full': election_full,
    'state': fields.List(IStr, description='State of candidate'),
    'district': fields.List(District, description='District of candidate'),
    'party': fields.List(IStr, description='Three-letter party code'),
    'min_receipts': Currency(description='Minimum aggregated receipts'),
    'max_receipts': Currency(description='Maximum aggregated receipts'),
    'min_disbursements': Currency(description='Minimum aggregated disbursements'),
    'max_disbursements': Currency(description='Maximum aggregated disbursements'),
    'min_cash_on_hand_end_period': Currency(description='Minimum cash on hand'),
    'max_cash_on_hand_end_period': Currency(description='Maximum cash on hand'),
    'min_debts_owed_by_committee': Currency(description='Minimum debt'),
    'max_debts_owed_by_committee': Currency(description='Maximum debt'),
    'federal_funds_flag': fields.Bool(description=docs.FEDERAL_FUNDS_FLAG),
    'has_raised_funds': fields.Bool(description=docs.HAS_RAISED_FUNDS),
}

totals_committee_aggregate = {
    'min_receipts': Currency(description='Minimum aggregated receipts'),
    'max_receipts': Currency(description='Maximum aggregated receipts'),
    'min_disbursements': Currency(description='Minimum aggregated disbursements'),
    'max_disbursements': Currency(description='Maximum aggregated disbursements'),
}

communication_cost_by_candidate = {
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'support_oppose': IStr(
        missing=None,
        validate=validate.OneOf(['S', 'O']),
        description='Support or opposition',
    ),
}

entities = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
}

schedule_e = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'filing_form': fields.List(IStr, description='Filing form'),
    'last_expenditure_date': fields.Date(missing=None, description='When sorting by `expenditure_date`, this is populated with the `expenditure_date` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'last_expenditure_amount': fields.Float(missing=None, description='When sorting by `expenditure_amount`, this is populated with the `expenditure_amount` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'last_office_total_ytd': fields.Float(missing=None, description='When sorting by `office_total_ytd`, this is populated with the `office_total_ytd` of the last result. However, you will need to pass the index of that last result to `last_index` to get the next page.'),
    'payee_name': fields.List(fields.Str, description='Name of the entity that received the payment'),
    'support_oppose_indicator': fields.List(
        IStr(validate=validate.OneOf(['S', 'O'])),
        description='Support or opposition',
    ),
    'is_notice': fields.List(fields.Bool, description='Record filed as 24- or 48-hour notice'),
}

schedule_e_efile = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'candidate_id': fields.List(IStr, description=docs.CANDIDATE_ID),
    'payee_name': fields.List(fields.Str, description='Name of the entity that received the payment'),
    'candidate_name': fields.List(fields.Str, description=docs.CANDIDATE_NAME),
    'image_number': fields.List(
        fields.Str,
        description='The image number of the page where the schedule item is reported',
    ),
    'support_oppose_indicator': fields.List(
        IStr(validate=validate.OneOf(['S', 'O'])),
        description='Support or opposition',
    ),
    'min_expenditure_date': fields.Date(description=docs.EXPENDITURE_MAX_DATE),
    'max_expenditure_date': fields.Date(description=docs.EXPENDITURE_MIN_DATE),
    'min_expenditure_amount': fields.Date(description=docs.EXPENDITURE_MIN_AMOUNT),
    'max_expenditure_amount': fields.Date(description=docs.EXPENDITURE_MAX_AMOUNT),
}

rad_analyst = {
    'committee_id': fields.List(IStr, description=docs.COMMITTEE_ID),
    'analyst_id': fields.List(fields.Int(), description='ID of RAD analyst'),
    'analyst_short_id': fields.List(fields.Int(), description='Short ID of RAD analyst'),
    'telephone_ext': fields.List(fields.Int(), description='Telephone extension of RAD analyst'),
    'name': fields.List(fields.Str, description='Name of RAD analyst'),
    'email': fields.List(fields.Str, description='Email of RAD analyst'),
    'title': fields.List(fields.Str, description='Title of RAD analyst'),
}

large_aggregates = {'cycle': fields.Int(required=True, description=docs.RECORD_CYCLE)}

schedule_a_by_state_recipient_totals = {
    'cycle': fields.List(fields.Int, description=docs.RECORD_CYCLE),
    'state': fields.List(IStr, description=docs.STATE_GENERIC),
    'committee_type': fields.List(
        IStr,
        description=docs.COMMITTEE_TYPE_STATE_AGGREGATE_TOTALS
    ),
}


# endpoint audit-primary-category
PrimaryCategory = {
    'primary_category_id': fields.List(fields.Str(), description=docs.PRIMARY_CATEGORY_ID),
    'primary_category_name': fields.List(fields.Str, description=docs.PRIMARY_CATEGORY_NAME),
    # 'tier': fields.List(fields.Int, description=docs.AUDIT_TIER),
}


# endpoint audit-category
Category = {
    'primary_category_id': fields.List(fields.Str(), description=docs.PRIMARY_CATEGORY_ID),
    'primary_category_name': fields.List(fields.Str, description=docs.PRIMARY_CATEGORY_NAME),
}

# endpoint audit-case
AuditCase = {
    'primary_category_id': fields.List(fields.Str(), missing='all', description=docs.PRIMARY_CATEGORY_ID),
    'sub_category_id': fields.List(fields.Str(), missing='all', description=docs.SUB_CATEGORY_ID),
    'audit_case_id': fields.List(fields.Str(), description=docs.AUDIT_CASE_ID),
    'cycle': fields.List(fields.Int(), description=docs.CYCLE),
    'committee_id': fields.List(fields.Str(), description=docs.COMMITTEE_ID),
    'committee_name': fields.List(fields.Str(), description=docs.COMMITTEE_NAME),
    'committee_type': fields.List(fields.Str(), description=docs.COMMITTEE_TYPE),
    'audit_id': fields.List(fields.Int(), description=docs.AUDIT_ID),
    'candidate_id': fields.List(fields.Str(), description=docs.CANDIDATE_ID),
    'candidate_name': fields.List(fields.Str(), description=docs.CANDIDATE_NAME),
    'min_election_cycle': fields.Int(description=docs.CYCLE),
    'max_election_cycle': fields.Int(description=docs.CYCLE),
}