Models

Base Models and Mixins

Model

class Model(**kwargs)[source]

Base model class that includes CRUD convenience methods.

All models that inherit from this model automatically have several additional attributes attached to them:

Variables:
  • created_at – Timestamp for when the model was created
  • updated_at – Timestamp for when the model was updated
  • created_by_id – Foreign key to User
  • created_by – Sqlalchemy relationship to User
  • updated_by_id – Foreign key to User
  • updated_by – Sqlalchemy relationship to User
get_or_create(session, model, create_method='', create_method_kwargs=None, **kwargs)[source]

Get a method or create it if it doesn’t exist.

For implementation details, see this post

Parameters:
  • session – SQLAlchemy database session
  • model – The model object to find or create
  • create_method – Optional custom instantiation method for model
  • create_method_kwargs – Optional instantiation kwargs for model
  • **kwargs – Any arguments needed to find or create the model
Returns:

Two-tuple of (Created/Found model, True if found False if created)

RefreshSearchViewMixin

class RefreshSearchViewMixin[source]

Mixin to trigger a search view refresh.

Concretely, any Model that subclasses this mixin will trigger a refresh of the search view after any additions, modifications, or deletions.

Any model that subclasses this mixin will have two new classmethods attached: an event_handler method, which handles what should happen when the events are fired by SQLAlchemy, and a __declare_last__ method, which allows the events to be attached to the models after all the SQLAlchemy mappers are declared. In this case, our event_handler is used to trigger a referesh on our materialized search view.

See also

For a brief discussion on using Model mixins to create event listeners, please refer to this stackoverflow thread

For detailed discussion of the implementation, please read this blog post

The search view is primarily used by Scout. For more, see:

Scout and Conductor

Contracts

class ContractBase(**kwargs)[source]

Base contract model

Variables:
  • id – Primary key unique ID
  • financial_id – Financial identifier for the contract. In Pittsburgh, this is called the “controller number” because it is assigned by the City Controller’s office
  • expiration_date – Date when the contract expires
  • description – Short description of what the contract covers
  • contract_href – Link to the actual contract document
  • followers – A many-to-many relationship with User objects for people who will receive updates about when the contract will be updated
  • is_archived – Whether the contract is archived. Archived contracts do not appear by default on Scout search
  • contract_type_id – Foreign key to ContractType
  • contract_type – Sqlalchemy relationship to ContractType
  • department_id – Foreign key to Department
  • department – Sqlalchemy relationship to Department
  • opportunity – An Opportunity created via conductor for this contract
  • is_visible – A flag as to whether or not the contract should be visible in Conductro
  • assigned_to – Foreign key to User
  • assigned – Sqlalchemy relationship to User
  • flow_id – Foreign key to Flow
  • current_flow – Sqlalchemy relationship to Flow
  • current_stage_id – Foreign key to Stage
  • current_stage – Sqlalchemy relationship to Stage
  • parent_id – Contract self-reference. When new work is started on a contract, a clone of that contract is made and the contract that was cloned is assigned as the new contract’s parent
  • children – A list of all of this object’s children (all contracts) that have this contract’s id as their parent_id
scout_contract_status

Returns a string with the contract’s status.

current_contract_stage

The contract’s current stage

Because the ContractStage model has a three-part compound primary key, we pass the contract’s ID, the contract’s Flow id and its Stage id

get_spec_number()[source]

Returns the spec number for a given contract

The spec number is a somewhat unique identifier for contracts used by Allegheny County. Because of the history of purchasing between the City and the County, the City uses spec numbers when they are available ( this tends to be contracts with County, A-Bid, and B-Bid ContractType.

The majority of contracts do not have spec numbers, but these numbers are quite important and used regularly for the contracts that do have them.

Returns:A ContractProperty object, either with the key of “Spec Number” or an empty object if none with that name exists
update_with_spec_number(data, company=None)[source]

Action to update both a contract and its spec number

Because a spec number is not a direct property of a contract, we have to go through some extra steps to update it.

Parameters:data – Form data to use in updating a contract
Keyword Arguments:
 company – A Company to add to the companies that are servicing the contract
build_complete_action_log()[source]

Returns the complete action log for this contract

filter_action_log()[source]

Returns a filtered action log for this contract

Because stages can be restarted, simple ordering by time an action was taken will lead to incorrectly ordered (and far too many) actions. Filtering these down is a multi-step process, which proceeds roughly as follows:

  1. Sort all actions based on the time that they were taken. This ensures that when we filter, we will get the most recent action. Putting them into proper time order for display takes place later

  2. Group actions by their respective Stage

  3. For each group of actions that takes place in each stage:

    1. Grab the most recent start or restart action for that stage (filtered by whether that action was taken on a stage prior to our current stage in our flow’s stage order)
    2. Grab the most recent end action for that stage (filtered by whether that action was taken on a stage prior to our current stage in our flow’s stage order, or the same stage)
    3. Grab all other actions that took place on that stage
  4. Re-sort them based on the action’s sort key, which will put them into the proper order for display

get_contract_stages()[source]

Returns the appropriate stages and their metadata based on a contract id

get_current_stage()[source]

Returns the details for the current contract stage

get_first_stage()[source]

Get the first ContractStage for this contract

Returns:ContractStage object representing the first stage, or None if no stage exists
completed_last_stage()[source]

Boolean to check if we have completed the last stage of our flow

add_follower(user)[source]

Add a follower from a contract’s list of followers

Parameters:user – A User
Returns:A two-tuple to use to flash an alert of (the message to display, the class to style the message with)
remove_follower(user)[source]

Remove a follower from a contract’s list of followers

Parameters:user – A User
Returns:A two-tuple to use to flash an alert of (the message to display, the class to style the message with)
transfer_followers_to_children()[source]

Transfer relationships from parent to all children and reset parent’s followers

extend(delete_children=True)[source]

Extends a contract.

Because conductor clones existing contracts when work begins, when we get an “extend” signal, we actually want to extend the parent conract of the clone. Optionally (by default), we also want to delete the child (cloned) contract.

complete()[source]

Do the steps to mark a contract as complete

  1. Transfer the followers to children
  2. Modify description to make contract explicitly completed/archived
  3. Mark self as archived and not visible
  4. Mark children as not archived and visible
kill()[source]

Remove the contract from the conductor visiblility list

classmethod clone(instance, parent_id=None, strip=True, new_conductor_contract=True)[source]

Takes a contract object and clones it

The clone always strips the following properties:

  • Current Stage

If the strip flag is set to true, the following are also stripped

  • Contract HREF
  • Financial ID
  • Expiration Date

If the new_conductor_contract flag is set to true, the following are set:

  • is_visible set to False
  • is_archived set to False

Relationships are handled as follows:

  • Stage, Flow - Duplicated
  • Properties, Notes, Line Items, Companies, Stars, Follows kept on old
Parameters:

instance – The instance of the contract to clone, will become the parent of the cloned contract unless a different parent_id is passed as a keyword argument

Keyword Arguments:
 
  • parent_id – The parent id of the contract to be passed, defaults to None
  • strip – Boolean, if true, the contract href, financial id and expiration date of the cloned contract will all be stripped. Defaults to True
  • new_conductor_contract – Boolean to mark if we are going to be starting new work in Conductor with the clone. If true, set both is_visible and is_archived to False. Defaults to True
Returns:

The cloned contract created from the passed instance

transition(user, destination=None, complete_time=None)[source]

Transition the contract to the appropriate stage.

  • If the contract has no current stage, transition it to the first stage
  • If the contract has a “destination”, transition it to that destination
  • If the current stage of the contract is the last stage of the contract’s flow order, exit the last stage and move to completion
  • If it is anything else, transition forward one stage in the flow order
Parameters:

user – The user taking the actions

Keyword Arguments:
 
  • destination – An optional revere destination to allow for rewinding to any point in time. Defaults to None
  • complete_time – A time other than the current time to perform the transitions. If one is given, the relevant ContractStageActionItem datetime fields and ContractStage enter and exit times are marked with the passed time. The actions’ taken_at times are still marked with the current time, however.
Returns:

A list of ContractStageActionItem objects which describe the actions in transition

switch_flow(new_flow_id, user)[source]

Switch the contract’s progress from one flow to another

Instead of trying to do anything too smart, we prefer instead to be dumb – it is better to force the user to click ahead through a bunch of stages than it is to incorrectly fast-forward them to an incorrect state.

There are five concrete actions here:

  1. Fully revert all stages in the old flow
  2. Rebuild our flow/stage model for the new order.
  3. Attach the complete log of the old flow into the first stage of the new order.
  4. Strip the contract’s current stage id.
  5. Transition into the first stage of the new order. This will ensure that everything is being logged in the correct order.
Parameters:
  • new_flow_id – ID of the new flow to switch to
  • user – The user performing the switch
build_subscribers()[source]

Build a list of subscribers and others to populate contacts in conductor

class ContractType(**kwargs)[source]

Model for contract types

Variables:
  • id – Primary key unique ID
  • name – Name of the contract type
  • allow_opportunities – Boolean flag as to whether to allow opportunities to be posted
  • managed_by_conductor – Boolean flag as to whether contracts of these types are managed through Conductor
  • opportunity_response_instructions – HTML string of instructions for bidders on how to respond to opportunities of this type
classmethod opportunity_type_query()[source]

Query factory filtered to include only types that allow opportunities

classmethod query_factory_all()[source]

Query factory to return all contract types

classmethod get_type(type_name)[source]

Get an individual type based on a passed type name

Parameters:type_name – Name of the type to look up
Returns:One ContractType object
class ContractProperty(**kwargs)[source]

Model for contract properties

The contract property model effectively serves as a key-value storage unit for properties that exist on a subset of contracts. For example, a common unit for County contracts is the so-called “spec number”, an identified used by Allegheny County for their electronic bidding system. Other contract types (such as PA state and COSTARS contracts), do not have this property but do have others (such as manufacturers offered, etc.). Therefore, we use this model as an extended key-value store for the base ContractBase model

Variables:
  • id – Primary key unique ID
  • contract – Sqlalchemy relationship to ContractBase
  • contract_id – Foreign key to ContractBase
  • key – The key for the property (for example, Spec Number)
  • value – The value for the property (for example, 7137)
class LineItem(**kwargs)[source]

Model for contract line items

Variables:
  • id – Primary key unique ID
  • contract – Sqlalchemy relationship to ContractBase
  • contract_id – Foreign key to ContractBase
  • description – Description of the line item in question
  • manufacturer – Name of the manufacturer of the line item
  • model_number – A model number for the item
  • quantity – The quantity of the item on contract
  • unit_of_measure – The unit of measure (for example EACH)
  • unit_cost – Cost on a per-unit basis
  • total_cost – Total cost (unit_cost * quantity)
  • percentage – Whether or not the unit cost should be represented as a percentage (NOTE: on the BidNet system, there is no differentiation between a percentage discount off of an item and actual unit cost for an item)
  • company_name – Name of the company that is providing the good
  • company_id – Foreign key to Company

Companies

class Company(**kwargs)[source]

Model for individual Compnaies

Variables:
  • id – Primary key unique ID
  • company_name – Name of the company
  • contracts – Many-to-many relationship with the :py:class:` purchasing.data.contracts.ContractBase` model
classmethod all_companies_query_factory()[source]

Query factory of all company ids and names ordered by name

class CompanyContact(**kwargs)[source]

Model for Company Contacts

Variables:
  • id – Primary key unique ID
  • company_id – Foreign key relationship to a Company
  • company – Sqlalchemy relationship with a Company
  • first_name – First name of the contact
  • last_name – Last name of the contact
  • addr1 – First line of the contact’s address
  • addr2 – Second line of the contract’s address
  • city – Contact address city
  • state – Contact address state
  • zip_code – Contact address zip code
  • phone_number – Contact phone number
  • fax_number – Contact fax number
  • email – Contact email

Searches

class SearchView(**kwargs)[source]

SearchView is a materialized view with all of our text columns

See also

For more detailed information about how this materialized view is set up, please refer to Multi-Table Full Text Search with Postgres, Flask, and Sqlalchemy (Part I).

For more information about Postgres Full-text search and TSVectors, refer to the Postgres documentation about full-text search

Variables:
  • id – Primary key unique ID for result
  • contract_id – Unique ID for one contract
  • company_id – Unique ID for one company
  • financial_id – Financial ID for a contract
  • expiration_date – Date a contract expires
  • contract_description – Description of the goods or services provided by a ContractBase
  • tsv_contract_descriptionTSVECTOR of the contract description
  • company_name – Name of the company providing services from the Company model
  • tsv_company_nameTSVECTOR of the company name
  • detail_keyContractProperty key
  • detail_valueContractProperty value
  • tsv_detail_valueTSVECTOR of the detail_value
  • line_item_description – Description of a line item from the LineItem model
  • tsv_line_item_descriptionTSVECTOR of the line item description

Stages

class Stage(**kwargs)[source]

Model for individual conductor stages

Variables:
  • id – Primary key unique ID
  • name – Name of the stage
  • post_opportunities – Whether you can post Opportunity objects to Beacon from this stage
  • default_message – Message to autopopulate the SendUpdateForm message body
classmethod choices_factory()[source]

Return a two-tuple of (stage id, stage name) for all stages

Flows

class Flow(**kwargs)[source]

Model for flows

A Flow is the series of Stage objects that a contract will go through as part of Conductor. It is meant to be as configurable and flexible as possible. Because of the nature of Flows, it is best to not allow them to be edited or deleted once they are in use. Instead, there is an is_archived flag. This is because of the difficulty of knowing how to handle contracts that are currently in the middle of a flow if that flow is edited. Instead, it is better to create a new flow.

Variables:
  • id – Primary key unique ID
  • flow_name – Name of this flow
  • contract – Many-to-one relationship with ContractBase (many contracts can share a flow)
  • stage_order – Array of stage_id integers
  • is_archived – Boolean of whether the flow is archived or active
classmethod all_flow_query_factory()[source]

Query factory that returns query of all flows

classmethod nonarchived_query_factory()[source]

Query factory that returns query of all non-archived flows

get_ordered_stages()[source]

Turns the flow’s stage_order attribute into Stage objects

Returns:Ordered list of Stage objects in the flow’s stage_order
create_contract_stages(contract)[source]

Creates new rows in contract_stage table.

Extracts the rows out of the given flow, and creates new rows in the contract_stage table for each of them.

If the stages already exist, that means that the contract is switching back into a flow that it had already been in. To handle this, the “revert” flag is set to true, which should signal to a downstream process to roll the stages back to the first one in the current flow.

Parameters:contract – A ContractBase object
Returns:A three-tuple of (the flow’s stage order, a list of the flow’s ContractStage objects, whether the we are “reverting”)
build_metrics_data()[source]

Build the raw data sets to be transformed client-side for metrics charts

Example

results = {
    'current': { 'contract id': {
        'description': 'a contract description',
        'email': 'the contract is assigned to this email',
        'department': 'the primary department for the contract',
        'contract_id': 'the contract id',
        'stages': [{
            'name': 'the stage name', 'id': 'the stage id',
            'entered': 'when the stage was entered',
            'exited': 'when the stage was exited',
            'seconds': 'number of seconds the contract spent in this stage',
        }, ...]
    }, ... },
    'complete': { 'contract id': {

    }, ... }
}
Returns:A results dictionary described in the example above.
reshape_metrics_granular(enter_and_exit=False)[source]

Transform long data from database into wide data for consumption

Take in a result set (list of tuples), return a dictionary of results. The key for the dictionary is the contract id, and the values are a list of (fieldname, value). Metadata (common to all rows) is listed first, and timing information from each stage is listed afterwords. Sorting is assumed to be done on the database layer

Parameters:enter_and_exit – A boolean option of whether to add both the enter and exit times to the results list
Returns:
  • Results - a dictionary of lists which can be used to generate a .csv or .tsv file to be downloaded by the client
  • Headers - A list of strings which can be used to create the headers for the downloadable file
get_metrics_csv_data()[source]

Raw SQL query that returns the raw data to be reshaped for download or charting

Contract Stages

class ContractStage(**kwargs)[source]

Model for contract stages

A Contract Stage is the term for a step that a ContractBase will occupy while going through a Flow. It has a three-part compound primary key of contract_id, stage_id, and flow_id. A contract stage’s primary role is to keep track of how long things take, which is accomplished through the object’s enter and exit attributes.

Variables:
  • id – Unique ID for each contract/stage/flow contract stage
  • contract_id – Part of compound primary key, foreign key to ContractBase
  • contract – Sqlalchemy relationship to ContractBase
  • stage_id – Part of compound primary key, foreign key to Stage
  • stage – Sqlalchemy relationship to Stage
  • flow_id – Part of compound primary key, foreign key to Flow
  • flow – Sqlalchemy relationship to Flow
  • entered – When work started for this particular contract stage
  • exited – When work completed for this particular contract stage
is_current_stage

Checks to see if this is the current stage

classmethod get_one(contract_id, flow_id, stage_id)[source]

Get one contract stage based on its three primary key elements

Parameters:
  • contract_id – ID of the relevant ContractBase
  • flow_id – ID of the relevant Flow
  • stage_id – ID of the relevant Stage
classmethod get_multiple(contract_id, flow_id, stage_ids)[source]

Get multiple contract stages based on multiple flow ids

Multiple only takes a single contract id and flow id because in Conductor, you would have multiple Stage per ContractBase/ Flow combination.

Parameters:
  • contract_id – ID of the relevant ContractBase
  • flow_id – ID of the relevant Flow
  • stage_id – IDs of the relevant Stage
enter(enter_time=None)[source]

Set the contract stage’s enter time

Parameters:enter_time – A datetime for this stage’s enter attribute. Defaults to utcnow.
log_enter(user, enter_time)[source]

Enter the contract stage and log its entry

Parameters:
  • user – A User object who triggered the enter event.
  • enter_time – A datetime for this stage’s enter attribute.
Returns:

A ContractStageActionItem that represents the log of the action item.

happens_before(target_stage_id)[source]

Check if this contract stage happens before a target stage

“Before” refers to the relative positions of these stages in their linked flow’s stage order based on the contract stage’s stage_id. If the passed target_stage_id is not in the flow’s stage order, this always returns False.

Parameters:target_stage_id – A Stage ID
happens_before_or_on(target_stage_id)[source]

Check if this contract stage happens before or is a target stage

“Before” refers to the relative positions of these stages in their linked flow’s stage order based on the contract stage’s stage_id. “On” refers to whether or not the passed target_stage_id shares an index with the contract stage’s stage_id. If the passed target_stage_id is not in the flow’s stage order, this always returns False.

Parameters:target_stage_id – A purchasing.data.stages.Stage ID
happens_after(target_stage_id)[source]

Check if this contract stage happens after a target stage

“after” refers to the relative positions of these stages in their linked flow’s stage order based on the contract stage’s stage_id. If the passed target_stage_id is not in the flow’s stage order, this always returns False.

Parameters:target_stage_id – A purchasing.data.stages.Stage ID
exit(exit_time=None)[source]

Set the contract stage’s exit time

Parameters:exit_time – A datetime for this stage’s exit attribute. Defaults to utcnow.
log_exit(user, exit_time)[source]

Exit the contract stage and log its exit

Parameters:
  • user – A User object who triggered the exit event.
  • exit_time – A datetime for this stage’s exit attribute.
Returns:

A ContractStageActionItem that represents the log of the action item.

log_reopen(user, reopen_time)[source]

Reopen the contract stage and log that re-opening

Parameters:
  • user – A User object who triggered the reopen event.
  • reopen_time – A datetime for this stage’s reopen attribute.
Returns:

A ContractStageActionItem that represents the log of the action item.

log_extension(user)[source]

Log an extension event

Parameters:user – A User object who triggered the extension event.
Returns:A ContractStageActionItem that represents the log of the action item.
full_revert()[source]

Clear timestamps for both enter and exit for this contract stage

strip_actions()[source]

Clear out non-stage-switch actions

This will prevent duplicate actions from piling up in the stream that is presented to the user

class ContractStageActionItem(**kwargs)[source]

Action logs for various actions that take place on a contract stage

Variables:
  • id – Primary key unique ID
  • contract_stage_id – Foreign key to ContractStage
  • contract_stage – Sqlalchemy relationship to ContractStage
  • action_type – A string describing the type of action taken
  • action_detail – A JSON blob representing details pertinent to the action in question
  • taken_at – Timestamp for when the action was taken
  • taken_by – Foriegn key to User
  • taken_by_user – Sqlalchemy relationship to User
non_null_items

Return the filtered actions where the action’s value is not none

non_null_items_count

Return a count of the non-null items in an action’s detailed log

is_start_type

Return true if the action type is either entered or reverted

is_exited_type

Return true if the action type is exited

is_other_type

Return true if the action type is not start or exited type

get_sort_key()[source]

Return the date field for sorting the action log

Beacon

Opportunities

class Opportunity(**kwargs)[source]

Base Opportunity Model – the central point for Beacon

The Beacon model is centered around three dates: planned_publish, planned_submission_start, and planned_submission_end. The publish date is when opportunities that are approved appear on Beacon. The publication date also is when vendors are notified via email.

Variables:
  • id – Primary key unique ID
  • title – Title of the Opportunity
  • description – Short (maximum 500-word) description of the opportunity
  • planned_publish – Date when the opportunity should show up on Beacon
  • planned_submission_start – Date when vendors can begin submitting responses to the opportunity
  • planned_submission_end – Deadline for submitted responses to the Opportunity
  • vendor_documents_needed – Array of integers that relate to RequiredBidDocument ids
  • is_public – True if opportunity is approved (publicly visible), False otherwise
  • is_archived – True if opportunity is archived (not visible), False otherwise
  • published_at – Date when an alert email was sent out to relevant vendors
  • publish_notification_sent – True is notification sent, False otherwise
  • department_id – ID of primary Department for this opportunity
  • department – Sqlalchemy relationship to primary Department for this opportunity
  • contact_id – ID of the User for this opportunity
  • contact – Sqlalchemy relationship to User for this opportunity
  • categories – Many-to-many relationship of the Category objects for this opportunity
  • created_from_id – ID of the ContractBase this opportunity was created from through Conductor
  • opportunity_type_id – ID of the ContractType
  • opportunity_type – Sqlalchemy relationship to the ContractType

See also

For more on the Conductor <–> Beacon relationship, look at the handle_form() Conductor utility method and the PostOpportunityForm Conductor Form

classmethod create(data, user, documents, publish=False)[source]

Create a new opportunity

Parameters:
  • data – dictionary of fields needed to populate new opportunity object
  • userUser object creating the new opportunity
  • documents – The documents FieldList from the OpportunityForm
Keyword Arguments:
 

publish – Boolean as to whether to publish this document. If True, it will set is_public to True.

See also

The OpportunityForm and OpportunityDocumentForm have more information about the documents.

raw_update(**kwargs)[source]

Performs a basic update based on the passed kwargs.

Parameters:**kwargs – Keyword arguments of fields to be updated in the existing Opportunity model
update(data, user, documents, publish=False)[source]

Performs an update, uploads new documents, and publishes

Parameters:
  • data – dictionary of fields needed to populate new opportunity object
  • userUser object updating the opportunity
  • documents – The documents FieldList from the OpportunityForm
Keyword Arguments:
 

publish – Boolean as to whether to publish this document. If True, it will set is_public to True.

is_published

Determine if an opportunity can be displayed

Returns:True if the planned publish date is before or on today, and the opportunity is approved, False otherwise
is_upcoming

Determine if an opportunity is upcoming

Returns:True if the planned publish date is before or on today, is approved, is not accepting submissions, and is not closed; False otherwise
is_submission_start

Determine if the oppportunity is accepting submissions

Returns:True if the submission start date and planned publish date are before or on today, is approved, and the opportunity is not closed; False otherwise
is_submission_end

Determine if an opportunity is closed to new submissions

Returns:True if the submission end date is on or before today, and it is approved
has_docs

True if the opportunity has at least one document, False otherwise

estimate_submission_start()[source]

Returns the month/year based on submission start date

estimate_submission_end()[source]

Returns the localized date and time based on submission end date

can_view(user)[source]

Check if a user can see opportunity detail

Parameters:user – A User object
Returns:Boolean indiciating if the user can view this opportunity
can_edit(user)[source]

Check if a user can edit the contract

Parameters:user – A User object
Returns:Boolean indiciating if the user can edit this opportunity. Conductors, the opportunity creator, and the primary opportunity contact can all edit the opportunity before it is published. After it is published, only conductors can edit it.
coerce_to_date(field)[source]

Coerces the input field to a datetime.date object

Parameters:field – A datetime.datetime or datetime.date object
Returns:A datetime.date object
get_vendor_emails()[source]

Return list of all signed up vendors

has_vendor_documents()[source]

Returns a Boolean for whether there are required bid documents

get_vendor_documents()[source]

Returns a list of documents the the vendor will need to provide

get_events()[source]

Returns the opportunity dates out as a nice ordered list for rendering

notify_approvals(user)[source]

Send the approval notifications to everyone with approval rights

Parameters:user – A User object
send_publish_email()[source]

Sends the “new opportunity available” email to subscribed vendors

If a new Opportunity is created and it has a publish date before or on today’s date, it will trigger an immediate publish email send. This operates in a very similar way to the nightly BeaconNewOppotunityOpenJob. It will build a list of all vendors signed up to the Opportunity or to any of the categories that describe the Opportunity.

class OpportunityDocument(**kwargs)[source]

Model for bid documents associated with opportunities

Variables:
  • id – Primary key unique ID
  • opportunity_id – Foreign Key relationship back to the related Opportunity
  • opportunity – Sqlalchemy relationship back to the related Opportunity
  • name – Name of the document for display
  • href – Link to the document
get_href()[source]

Builds link to the file

Returns:S3 link if using S3, local filesystem link otherwise
clean_name()[source]

Replaces underscores with spaces

class RequiredBidDocument(**kwargs)[source]

Model for documents that a vendor would be required to provide

There are two types of documents associated with an opportunity – documents that the City will provide (RFP/IFB/RFQ, Q&A documents, etc.), and documents that the bidder will need to provide upon bidding (Insurance certificates, Bid bonds, etc.). This model describes the latter.

See also

These models get rendered into a select multi with the descriptions rendered in tooltips. For more on how this works, see the select_multi_checkbox().

Variables:
  • id – Primary key unique ID
  • display_name – Display name for the document
  • description – Description of what the document is, rendered in a tooltip
  • form_href – A link to an example document
get_choices()[source]

Builds a custom two-tuple for the CHOICES.

Returns:Two-tuple of (ID, [name, description, href]), which can then be passed to select_multi_checkbox() to generate multi-checkbox fields
classmethod generate_choices()[source]

Builds a list of custom CHOICES

Returns:List of two-tuples described in the RequiredBidDocument.get_choices() method

Vendors

class Vendor(**kwargs)[source]

Base Vendor model for businesses interested in Beacon

The primary driving thought behind Beacon is that it should be as easy as possible to sign up to receive updates about new opportunities. Therefore, there are no Vendor accounts or anything like that, just email addresses and business names.

Variables:
  • id – Primary key unique ID
  • business_name – Name of the business, required
  • email – Email address for the vendor, required
  • first_name – First name of the vendor
  • last_name – Last name of the vendor
  • phone_number – Phone number for the vendor
  • fax_number – Fax number for the vendor
  • minority_owned – Whether the vendor is minority owned
  • veteran_owned – Whether the vendor is veteran owned
  • woman_owned – Whether the vendor is woman owned
  • disadvantaged_owned – Whether the vendor is any class of Disadvantaged Business Enterprise (DBE)
  • categories – Many-to-many relationship with Category; describes what the vendor is subscribed to
  • opportunities – Many-to-many relationship with Opportunity; describes what opportunities the vendor is subscribed to
  • subscribed_to_newsletter – Whether the vendor is subscribed to receive the biweekly newsletter of all opportunities
classmethod newsletter_subscribers()[source]

Query to return all vendors signed up to the newsletter

build_downloadable_row()[source]

Take a Vendor object and build a list for a .tsv download

Returns:List of all vendor fields in order for a bulk vendor download

Categories

class Category(**kwargs)[source]

Category model for opportunities and Vendor signups

Categories are based on the codes created by the National Institute of Government Purchasing (NIGP). The names of the categories have been re-written a bit to make them more human-readable and in some cases a bit more modern.

Variables:
  • id – Primary key unique ID
  • nigp_codes – Array of integers refering to NIGP codes.
  • category – parent top-level category
  • subcategory – NIGP designated subcategory name
  • category_friendly_name – Rewritten, more human-readable subcategory name
  • examples – Pipe-delimited examples of items that fall in each subcategory
  • examples_tsv – TSVECTOR of the examples for that subcategory

See also

The NIGP Importer contains more information about how NIGP codes are imported into the system.

classmethod parent_category_query_factory()[source]

Query factory to return a query of all of the distinct top-level categories

classmethod query_factory()[source]

Query factory that returns all category/subcategory pairs

Public and User

Users

class User(**kwargs)[source]

User model

Variables:
  • id – primary key
  • email – user email address
  • first_name – first name of user
  • last_name – last name of user
  • active – whether user is currently active or not
  • roles – relationship of user to role table
  • department_id – foreign key of user’s department
  • department – relationship of user to department table
full_name

Build full name of user

Returns:concatenated string of first_name and last_name values
get_following()[source]

Generate user contract subscriptions

Returns:list of ids for contracts followed by user
is_conductor()[source]

Check if user can access conductor application

Returns:True if user’s role is either conductor, admin, or superadmin, False otherwise
is_admin()[source]

Check if user can access admin applications

Returns:True if user’s role is admin or superadmin, False otherwise
print_pretty_name()[source]

Generate long version text representation of user

Returns:full_name if first_name and last_name exist, email otherwise
print_pretty_first_name()[source]

Generate abbreviated text representation of user

Returns:first_name if first_name exists, localpart otherwise
classmethod conductor_users_query()[source]

Query users with access to conductor

Returns:list of users with is_conductor value of True
class Role(**kwargs)[source]

Model to handle view-based permissions

Variables:
  • id – primary key
  • name – role name
  • description – description of an individual role
classmethod query_factory()[source]

Generates a query of all roles

Returns:sqla query of all roles
classmethod no_admins()[source]

Generates a query of non-admin roles

Returns:sqla query of roles without administrative access
classmethod staff_factory()[source]

Factory to return the staff role

Returns:Role object with the name ‘staff’
class Department(**kwargs)[source]

Department model

Variables:name – Name of department
classmethod query_factory()[source]

Generate a department query factory.

Returns:Department query with new users filtered out
classmethod get_dept(dept_name)[source]

Query Department by name.

Parameters:dept_name – name used for query
Returns:an instance of Department
classmethod choices(blank=False)[source]

Query available departments by name and id.

Parameters:blank – adds none choice to list when True, only returns Departments when False. Defaults to False.
Returns:list of (department id, department name) tuples
class AnonymousUser(*args, **kwargs)[source]

Custom mixin for handling anonymous (non-logged-in) users

Variables:
  • roles – List of a single Role object with name set to ‘anonymous’
  • departmentDepartment object with name set to ‘anonymous’
  • id – Defaults to -1

See also

AnonymousUser subclasses the flask_login anonymous user mixin, which contains a number of class and instance methods around determining if users are currently logged in.

App Status

class AppStatus(**kwargs)[source]

Model of current application status

Variables:
  • id – Primary key
  • status – Current application status
  • last_updated – Datetime of the last time the status was updated
  • county_max_deadline – Datetime of the last time the county scraper was updated
  • message – If the status is an error, the message will have more information about the nature of the error
  • last_beacon_newsletter – Datetime of the last time a beacon newsletter was sent
class AcceptedEmailDomains(**kwargs)[source]

Model of permitted email domains for new user creation

Because authentication is handled by persona, we still need to control some level of authorization. We do this on two levels. First, we use Role-based permissions using the Role class and the requires_roles() method. We also do this by restricting new user creation to people who have a certain set of email domains.

See also

User Logins

Variables:
  • id (int) – Primary key
  • domain (str) – string of an acceptable domain (for example, pittsburghpa.gov)
classmethod valid_domain(domain_to_lookup)[source]

Check if a domain is in the valid domains

Parameters:domain_to_lookup (str) – string of domain to be checked
Returns:True if domain is valid, False otherwise
Return type:bool

Job Status

class JobStatus(**kwargs)[source]

Model to track nightly job status and reporting

JobStatus has a primary compound key of name + date

Variables:
  • name – Name of the job
  • date – Date the job is scheduled for
  • status – String of the job status, defaults to ‘new’, set to ‘started’, ‘success’, ‘failure’, or ‘skipped’
  • info – Any additional reporting about the job status, such as an error message if the job fails