webservices/common/models/filings.py
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.ext.hybrid import hybrid_property
from webservices import docs, utils
from webservices.common.models.dates import ReportType
from webservices.common.models.dates import clean_report_type
from webservices.common.models.reports import CsvMixin, FecMixin, AmendmentChainMixin, FecFileNumberMixin
from .base import db
class Filings(FecFileNumberMixin, CsvMixin, db.Model):
__tablename__ = 'ofec_filings_all_mv'
committee_id = db.Column(db.String, index=True, doc=docs.COMMITTEE_ID)
committee = utils.related_committee_history('committee_id', cycle_label='report_year')
committee_name = db.Column(db.String, doc=docs.COMMITTEE_NAME)
candidate_id = db.Column(db.String, index=True, doc=docs.CANDIDATE_ID)
candidate_name = db.Column(db.String, doc=docs.CANDIDATE_NAME)
cycle = db.Column(db.Integer, doc=docs.RECORD_CYCLE)
sub_id = db.Column(db.BigInteger, index=True, primary_key=True)
coverage_start_date = db.Column(db.Date, index=True, doc=docs.COVERAGE_START_DATE)
coverage_end_date = db.Column(db.Date, index=True, doc=docs.COVERAGE_END_DATE)
receipt_date = db.Column(db.Date, index=True, doc=docs.RECEIPT_DATE)
election_year = db.Column(db.Integer, doc=docs.ELECTION_YEAR)
form_type = db.Column(db.String, index=True, doc=docs.FORM_TYPE)
report_year = db.Column(db.Integer, index=True, doc=docs.REPORT_YEAR)
report_type = db.Column(db.String, index=True, doc=docs.REPORT_TYPE)
document_type = db.Column(db.String, index=True, doc=docs.DOC_TYPE)
document_type_full = db.Column(db.String, doc=docs.DOC_TYPE)
report_type_full = db.Column(db.String, doc=docs.REPORT_TYPE)
beginning_image_number = db.Column(db.BigInteger, index=True, doc=docs.BEGINNING_IMAGE_NUMBER)
ending_image_number = db.Column(db.BigInteger, doc=docs.ENDING_IMAGE_NUMBER)
pages = db.Column(db.Integer, doc='Number of pages in the document')
total_receipts = db.Column(db.Numeric(30, 2))
total_individual_contributions = db.Column(db.Numeric(30, 2))
net_donations = db.Column(db.Numeric(30, 2))
total_disbursements = db.Column(db.Numeric(30, 2))
total_independent_expenditures = db.Column(db.Numeric(30, 2))
total_communication_cost = db.Column(db.Numeric(30, 2))
cash_on_hand_beginning_period = db.Column(db.Numeric(30, 2), doc=docs.CASH_ON_HAND_BEGIN_PERIOD)
cash_on_hand_end_period = db.Column(db.Numeric(30, 2), doc=docs.CASH_ON_HAND_END_PERIOD)
debts_owed_by_committee = db.Column(db.Numeric(30, 2), doc=docs.DEBTS_OWED_BY_COMMITTEE)
debts_owed_to_committee = db.Column(db.Numeric(30, 2), doc=docs.DEBTS_OWED_TO_COMMITTEE)
house_personal_funds = db.Column(db.Numeric(30, 2))
senate_personal_funds = db.Column(db.Numeric(30, 2))
opposition_personal_funds = db.Column(db.Numeric(30, 2))
treasurer_name = db.Column(db.String, doc=docs.TREASURER_NAME)
file_number = db.Column(db.BigInteger)
primary_general_indicator = db.Column(db.String, index=True)
report_type_full = db.Column(db.String, doc=docs.REPORT_TYPE)
request_type = db.Column(db.String)
amendment_indicator = db.Column(db.String, index=True, doc=docs.AMENDMENT_CHAIN)
update_date = db.Column(db.Date)
pdf_url = db.Column(db.String)
fec_url = db.Column(db.String)
means_filed = db.Column(db.String, doc=docs.MEANS_FILED)
is_amended = db.Column('is_amended', db.Boolean)
most_recent = db.Column('most_recent', db.Boolean)
html_url = db.Column(db.String, doc='HTML link to the filing.')
#If f2 filing, the state of the candidate, else the state of the committee
state = db.Column(db.String, doc=docs.STATE)
office = db.Column(db.String, doc=docs.OFFICE)
# Filter filings based off candidate office or committee type H, S and P only. all other
# committee types are ignored. Because from the fron-end we only filter
# filings by candidate office only.
# mapped office_cmte_tp db column with office
office = db.Column('office_cmte_tp', db.String, index=True, doc=docs.OFFICE)
party = db.Column(db.String, doc=docs.PARTY)
cmte_tp = db.Column(db.String, doc=docs.COMMITTEE_TYPE)
amendment_chain = db.Column(ARRAY(db.Numeric))
previous_file_number = db.Column(db.BigInteger)
most_recent_file_number = db.Column(db.BigInteger)
amendment_version = db.Column(db.Integer)
@property
def document_description(self):
return utils.document_description(
self.report_year,
self.report_type_full,
self.document_type_full,
self.form_type,
)
class EfilingsAmendments(db.Model):
__tablename__ = 'efiling_amendment_chain_vw'
file_number = db.Column('repid', db.BigInteger, index=True, primary_key=True, doc=docs.FILE_NUMBER)
amendment_chain = db.Column(ARRAY(db.Numeric))
longest_chain = db.Column(ARRAY(db.Numeric))
most_recent_filing = db.Column(db.Numeric)
depth = db.Column(db.Numeric)
last = db.Column(db.Numeric)
previous_file_number = db.Column('previd', db.Numeric)
def next_in_chain(self, file_number):
if len(self.longest_chain) > 0 and self.depth <= len(self.longest_chain) - 1:
index = self.longest_chain.index(file_number)
return self.longest_chain[index + 1]
else:
return 0
class EFilings(FecFileNumberMixin, AmendmentChainMixin, CsvMixin, FecMixin, db.Model):
__table_args__ = {'schema' : 'real_efile'}
__tablename__ = 'reps'
file_number = db.Column('repid', db.BigInteger, index=True, primary_key=True, doc=docs.FILE_NUMBER)
form_type = db.Column('form', db.String, doc=docs.FORM_TYPE)
committee_id = db.Column('comid', db.String, index=True, doc=docs.COMMITTEE_ID)
committee_name = db.Column('com_name', db.String, doc=docs.COMMITTEE_NAME)
receipt_date = db.Column('timestamp', db.Date, index=True, doc=docs.RECEIPT_DATE)
load_timestamp = db.Column('create_dt', db.DateTime, doc=docs.LOAD_DATE)
coverage_start_date = db.Column('from_date', db.Date, doc=docs.COVERAGE_START_DATE)
coverage_end_date = db.Column('through_date', db.Date, doc=docs.COVERAGE_END_DATE)
beginning_image_number = db.Column('starting', db.BigInteger, doc=docs.BEGINNING_IMAGE_NUMBER)
ending_image_number = db.Column('ending', db.BigInteger, doc=docs.ENDING_IMAGE_NUMBER)
report_type = db.Column('rptcode', db.String, db.ForeignKey(ReportType.report_type), doc=docs.REPORT_TYPE)
superceded = db.Column(db.BigInteger, doc=docs.AMENDED_BY)
amends_file = db.Column('previd', db.BigInteger, doc=docs.AMENDS_FILE)
amendment_number = db.Column('rptnum', db.Integer, doc=docs.AMENDMENT_NUMBER)
report = db.relationship(ReportType)
amendment = db.relationship(
'EfilingsAmendments',
primaryjoin='''and_(
EfilingsAmendments.file_number == EFilings.file_number,
)''',
foreign_keys=file_number,
lazy='joined',
)
@property
def document_description(self):
return utils.document_description(
self.coverage_end_date.year,
clean_report_type(self.report.report_type_full),
None,
self.form_type,
)
@property
def amended_by(self):
amender_file_number = self.amendment.next_in_chain(self.file_number)
if amender_file_number > 0:
return amender_file_number
else:
return self.superceded
@property
def is_amended(self):
return self.superceded or not self.most_recent
@property
def pdf_url(self):
image_number = str(self.beginning_image_number)
return 'http://docquery.fec.gov/pdf/{0}/{1}/{1}.pdf'.format(image_number[-3:], image_number)
@property
def html_url(self):
return 'http://docquery.fec.gov/cgi-bin/forms/{0}/{1}/'.format(self.committee_id, self.file_number)
# TODO: add index on committee id and filed_date
# version -- this is the efiling version and I don't think we need this - let's document in API for now, see if there are objections