Conductor

Conductor is a tool for the Office of Management and Budget (OMB) to manage contracts as they move through the city’s various processes for renewal, rebid, extension, etc. From the user’s perspective, the way this works is that they define different Flow objects that are comprised of an ordered array of Stage objects. ContractBase objects are then assigned to a User and a Flow. At this point, the ContractStage are all created, and the contract is essentially on rails. The “Conductor”, then, is the person who drives this contract through the various stages towards completion.

Once a contract is in progress, Conductors complete various stages by marking them as such in the UI. They can also perform various actions in each stage, including making notes, sending emails to different people interested in the process, change metadata about the contract, and adverstise through a new Opportunity on Beacon.

See also

How to use Conductor, an internal product guide for more information about the user interface and user experience.

Forms

Forms

class DynamicStageSelectField(label=None, validators=None, coerce=<type 'unicode'>, choices=None, **kwargs)[source]

Select field to allow dynamic choice construction

pre_validate(form)[source]

Raise an error if there is nothing in the data, otherwise return true

class FlowForm(formdata=<object object>, **kwargs)[source]

Form for editing existing form metadata

Variables:
  • id – Hidden field to hold the form’s ID
  • flow_name – Name of the flow
  • is_archived – Whether or not the flow is archived
class NewFlowForm(stages=[], *args, **kwargs)[source]

Form for creating new flows

Variables:
  • flow_name – Name of the flow
  • stage_order – A list of DynamicStageSelectField fields that represent different stages
Parameters:
  • stages – A list of (id, name) values used to build choices
  • *args – List of arguments passed to the form’s superclass
  • **kwargs – List of keyword arguments passed to the form’s superclass
class CompleteForm(started=None, *args, **kwargs)[source]

Form to hold the completion times

Variables:
  • complete – Field to hold the date/time for when to complete a certain ContractStage
  • maximum – (instance variable) The current utc time
Parameters:

started – Datetime of what the minimum time should be, such as when the ContractStage started. Because the complete form attribute uses the validate_date() validator, passing a minumim is important to ensure the validator works properly (if you want to make sure that ContractStage objects don’t end before they start. Optional to allow the first stage in a give Flow to start in the past.

class NewContractForm(formdata=<object object>, **kwargs)[source]

Form for starting new work on a contract through conductor

Variables:
  • description – The contract’s description
  • flow – The Flow the contract should follow
  • assigned – The User the contract should be assigned to
  • department – The Department the contract should be assigned to
  • start – The start time for the first ContractStage for the contract
class ContractMetadataForm(formdata=<object object>, **kwargs)[source]

Edit a contract’s metadata during the renewal process

Variables:
  • financial_id – The ContractBase financial_id
  • spec_number – The spec number for a contrat. See get_spec_number() for more information about spec numbers
  • department – The Department to set for the contract
  • all_blank – Placeholder to indicate if all other fields are blank
post_validate_action(action, contract, current_stage)[source]

Update the contract’s metadata

Parameters:
Returns:

The modified ContractStageActionItem with the action detail updated to include the form’s data

class AttachmentForm(formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs)[source]

Form to hold individual attachments for email updates

Wrapped in a list by SendUpdateForm

Variables:upload – File field which holds an uploaded file. Must be a Word, Excel, or .pdf document
class SendUpdateForm(formdata=<object object>, **kwargs)[source]

Form to send an email update

Variables:
  • send_to – Email or semicolon-delimited list of email addresses to send the update email to
  • send_to_cc – Email or semicolon-delimited list of email addresses to cc on the update
  • subject – The subject the update should have
  • body – The body of the message the subject should have. This can be configured as a property of a Stage
  • attachments – A list of files. Wraps AttachmentForm
get_attachment_filenames()[source]

Return the names of all of the attached files or None

post_validate_action(action, contract, current_stage)[source]

Send the email updates

Parameters:
Returns:

The modified ContractStageActionItem with the action detail updated to include the form’s data

class PostOpportunityForm(formdata=<object object>, **kwargs)[source]

Form to post opportunities to Beacon

Variables:contact_email – Override the base form to make the contact email optional for a opportunity posted from conductor

See also

OpportunityForm

post_validate_action(action, contract, current_stage)[source]

Post the opportunity to Beacon

Parameters:
Returns:

The modified ContractStageActionItem with the action detail updated to include the form’s data

class NoteForm(formdata=<object object>, **kwargs)[source]

Form to take notes

Variables:note – Text of the note to be taken
post_validate_action(action, contract, current_stage)[source]

Post the note

Parameters:
Returns:

The modified ContractStageActionItem with the action detail updated to include the form’s data

class FileUploadForm(formdata=<object object>, **kwargs)[source]

Form to take new costars data for upload

Variables:upload – csv file to be uploaded
class ContractUploadForm(formdata=<object object>, **kwargs)[source]

Form to upload a pdf for a costars contract

Variables:
  • contract_id – ID of the contract to be uploaded (hidden field)
  • upload – The file to be uploaded
class EditContractForm(formdata=<object object>, **kwargs)[source]

Form to control details needed to finalize a new/renewed contract

Variables:
  • description – The final description of the contract (required)
  • expiration_date – The new expiration date for the new/renewed contract (required)
  • spec_number – The county spec number (see get_spec_number() , required)
  • contract_href – A link to the actual contract document
class CompanyContactForm(formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs)[source]

Form to capture contact information for a company

Variables:
  • 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

See also

CompanyContact

class CompanyForm(formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs)[source]

A form to assign a company to a contract

This is an individual new/existing company that is part of the CompanyListForm entries. For an individual entry, both the new_company_name and the new_company_controller_number or the company_name and the controller_number must be filled out. Both cannot be filled out and they cannot be partially filled out.

Variables:
  • new_company_controller_number – Controller number for a new company
  • new_company_name – Name for a new company
  • controller_number – Controller number for an existing company
  • company_name – Name of an existing copany, uses a query select field
class CompanyListForm(formdata=<object object>, **kwargs)[source]

Form that holds lists of new/existing companies

Variables:companies – List of CompanyForm form fields
class CompanyContactList(formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs)[source]

Form to hold lists of company contacts

This form is the inner level of a twice-nested list. On the outer level (see CompanyContactListForm ), we have a list of companies. Each of those companies could have multiple contacts, though, so we need an inner nested list to handle that. This is that inner portion.

Variables:contacts – List of CompanyContactForm form fields
class CompanyContactListForm(formdata=<object object>, **kwargs)[source]

Outer form to collect all contacts for all companies for the contract

Variables:companies – A outer list around the nested CompanyContactList

Validators

not_all_hidden(form, field)[source]

Makes sure that every field isn’t blank

validate_multiple_emails(form, field)[source]

Parses a semicolon-delimited list of emails, validating each

validate_different(form, field)[source]

Ensures that all subfields have a different value

validate_unique_name(form, field)[source]

Ensure that the name isn’t an existing flow name

validate_integer(form, field)[source]

Ensures that a passed value can be coerced to an integer

validate_date(form, field)[source]

Ensures that a date occured after a form’s started and before its maximum time

Note

This validator is only meant to be used on forms that have started and maximum instance variables, like the CompleteForm

Helper Methods

class ContractMetadataObj(contract)[source]

Base object to populate the contract metadata form

Sets the expiration date, financial id, spec number, and department on the contract metadata form

Parameters:contract – The ContractBase contract that is currently being worked on, will be used to pre-populate the relevant form
class UpdateFormObj(stage)[source]

Base object to populate the send email update form

Sets the cc email as the current user’s email, and sets the email body as the default message from the passed Stage, or an empty string.

Parameters:stage – a Stage object

See also

SendUpdateForm

class ConductorToBeaconObj(contract)[source]

Base object to populate posting from Conductor to Beacon

Sets the title of the opportunity as the contract’s description, and then sets the default opportunity type and department from the app’s configuration.

Parameters:contract – The ContractBase contract that is currently being worked on, will be used to pre-populate the relevant form
json_serial(obj)[source]

Add JSON serialization support for datetime and date objects

Parameters:obj – Object to serialize into JSON
Returns:If obj is a datetime or date object, serialize it by converting it into an isoformat string. Otherwise, return the object itself
parse_companies(companies)[source]

Normalize new and existing companies into Contract model fields

Parameters:companies – A list of companies and new companies passed in from the user’s session.
Returns:A list of dictionaries, normalized to be added as properties to a new ContractBase object
assign_a_contract(contract, flow, user, start_time=None, clone=True)[source]

Assign a contract a flow and a user

If a flow is passed in, the following steps are performed:

  1. If the clone flag is set to True, make a new cloned copy of the passed ContractBase
  2. Try to get or create the contract stages for the passed Flow
  3. Inspect the output for the “revert” flag – if the flag is set, that means that we are resetting the entry time on the first stage. In order to do this, we clear out the current stage information, which will make the contract transition to the first stage of it’s flow
  4. If that raises an error, it is because something went wrong with the creation/getting of the contract stages
  5. Assign the contract’s flow to the passed Flow and its assigned user to the passed User and commit

See also

Parameters:
  • contract – A ContractBase object to assign
  • flow – A Flow object to assign
  • user – A User object to assign
Keyword Arguments:
 
  • start_time – An optional start time for starting work on the ContractBase when it starts its first ContractStage
  • clone – A boolean flag of whether or not to make a clone of the passed ContractBase
Returns:

An assigned ContractBase if we are given a flow, False otherwise

upload_costars_contract(_file)[source]

Upload a COSTARS pdf document to S3

Parameters:_file – A werkzeug FileStorage object
Returns:A two-tuple of (the name of the uploaded file, the path/url to the file)

Views

Main

POST /conductor/contract/(int: contract_id)/start
POST /conductor/contract/new

Start work on a contract

When new work is started on a contract, a new contract is created (either as a clone of an existing contract, or as brand new work), assigned to the Flow and User indicated in the NewContractForm

Parameters:

See also

clone() for more information on how new contracts get started, and NewContractForm for more on the form to start new work.

Status Codes:
  • 200 OK – Render the new contract view
  • 302 Found – Create or start new work on a cloned contract
GET /conductor/contract/(int: contract_id)/start
GET /conductor/contract/new

Start work on a contract

When new work is started on a contract, a new contract is created (either as a clone of an existing contract, or as brand new work), assigned to the Flow and User indicated in the NewContractForm

Parameters:

See also

clone() for more information on how new contracts get started, and NewContractForm for more on the form to start new work.

Status Codes:
  • 200 OK – Render the new contract view
  • 302 Found – Create or start new work on a cloned contract
POST /conductor/flow/new

Create a new flow

Status Codes:
  • 200 OK – Render the new flow template
  • 302 Found – Try to create a new flow using the NewFlowForm, redirect to the flows list view if successful
GET /conductor/flow/new

Create a new flow

Status Codes:
  • 200 OK – Render the new flow template
  • 302 Found – Try to create a new flow using the NewFlowForm, redirect to the flows list view if successful
GET /conductor/flows

List all flows

Status Codes:
  • 200 OK – Render the all flows list template
GET /conductor/

Main conductor index page/splash view

Renders two tables that conductors can use to track their progress: in_progress, which contains all of the ContractBase objects that are currently being worked on by a conductor. in_progress contracts are generated by selecting only ContractBase objects that have a parent_id, have an existing flow, non-null entered current contract stage, and are neither is_archived nor is_visible.

all_contracts contains all contracts that are eligible to show up in conductor to be worked on. These are filtered based on the ContractType managed_by_conductor field. Additionally, these are filtered by having no children, and is_visible set to True

Status Codes:
  • 200 OK – Render the main conductor index page
GET /conductor/contract/(int: contract_id)/stage/(int: stage_id)/note/(int: note_id)/delete

Delete a note from a conductor step

Parameters:
Status Codes:
  • 302 Found – Deletes the note and redirects to the conductor detail view
GET /conductor/contract/(int: contract_id)/stage/(int: stage_id)/flow-switch/(int: flow_id)

Switch a contract’s flow

Parameters:

See also

See switch_flow() for more on the flow-switch logic

Status Codes:
  • 302 Found – Redirect to the detail view for the first stage of the new flow
  • 404 Not Found – Contract not found
POST /conductor/contract/(int: contract_id)/stage/(int: stage_id)/transition

Transition a contract from one date to the next date

Parameters:

See also

For the transition, see the transition() method directly

Status Codes:
  • 302 Found – Perform the transition, and redirect back to the detail view with either the new stage or the appropriate error message
  • 404 Not Found – Contract not found
GET /conductor/contract/(int: contract_id)/stage/(int: stage_id)/transition

Transition a contract from one date to the next date

Parameters:

See also

For the transition, see the transition() method directly

Status Codes:
  • 302 Found – Perform the transition, and redirect back to the detail view with either the new stage or the appropriate error message
  • 404 Not Found – Contract not found
GET /conductor/contract/(int: contract_id)/stage/(int: stage_id)/extend

Extend a contract

Parameters:

See also

See log_extension() for information about thea actual extend logging, and extend() for more on the extend event itself

Status Codes:
POST /conductor/contract/(int: contract_id)/edit/url-exists

Check to see if a url returns an actual page

Parameters:
Status Codes:
  • 2xx – Successful HEAD request – valid URL
  • 404 Not Found – Invalid URL given
  • 4xx – Something went wrong checking that URL
  • 5xx – Something went wrong checking that URL
POST /conductor/contract/(int: contract_id)/edit/contract

Update information about a contract

Parameters:

See also

EditContractForm for the form to edit the contract information, and update_with_spec_number() for information on how the contract is updated.

Status Codes:
  • 200 OK – Render the edit contract form
  • 302 Found – Redirect to the conductor detail page if the contract was not completed, the edit company page if the edit form was filled and the contract isn’t being extended, and back to the conductor detial view if the contract isn’t finished yet
  • 404 Not Found – Could not find the contract
GET /conductor/contract/(int: contract_id)/edit/contract

Update information about a contract

Parameters:

See also

EditContractForm for the form to edit the contract information, and update_with_spec_number() for information on how the contract is updated.

Status Codes:
  • 200 OK – Render the edit contract form
  • 302 Found – Redirect to the conductor detail page if the contract was not completed, the edit company page if the edit form was filled and the contract isn’t being extended, and back to the conductor detial view if the contract isn’t finished yet
  • 404 Not Found – Could not find the contract
POST /conductor/contract/(int: contract_id)/edit/contacts

Update information about company contacts, and save all information

New ContractBase objects are created for each unique controller number. Notifications are also sent to all of the original contract’s followers to say that the contract information has been replaced/updated with new info.

Parameters:
Status Codes:
  • 200 OK – Render the CompanyContactListForm form
  • 302 Found – Post the data and redirect back to the success view, or redirect back to contract or company views if those haven’t been completed yet.
  • 404 Not Found – Contract not found
GET /conductor/contract/(int: contract_id)/edit/contacts

Update information about company contacts, and save all information

New ContractBase objects are created for each unique controller number. Notifications are also sent to all of the original contract’s followers to say that the contract information has been replaced/updated with new info.

Parameters:
Status Codes:
  • 200 OK – Render the CompanyContactListForm form
  • 302 Found – Post the data and redirect back to the success view, or redirect back to contract or company views if those haven’t been completed yet.
  • 404 Not Found – Contract not found
POST /conductor/contract/(int: contract_id)/edit/company

Update information about companies

Parameters:

See also

parse_companies() for information on how the companies are cleaned and normalized, and CompanyListForm for more on the form used in this view

Status Codes:
  • 200 OK – Render the company/controller number view
  • 302 Found – Redirect to the company contact view if the company form is submitted correctly, and the edit contract view if that form hasn’t been completed yet
  • 404 Not Found – Contract not found
GET /conductor/contract/(int: contract_id)/edit/company

Update information about companies

Parameters:

See also

parse_companies() for information on how the companies are cleaned and normalized, and CompanyListForm for more on the form used in this view

Status Codes:
  • 200 OK – Render the company/controller number view
  • 302 Found – Redirect to the company contact view if the company form is submitted correctly, and the edit contract view if that form hasn’t been completed yet
  • 404 Not Found – Contract not found
GET /conductor/contract/(int: contract_id)/edit/success

Render the success template after completing a contract

Parameters:
Status Codes:
  • 200 OK – Render the success template
  • 302 Found – Redirect back to the edit company contacts
GET /conductor/contract/(int: contract_id)/assign/(int: user_id)

Reassign a contract to a new user

Parameters:
  • contract_id – Primary key ID for a ContractBase
  • user_id – Primary key ID for a User
Status Codes:
  • 302 Found – Reassign a contract redirect to the conductor index view
  • 404 Not Found – Contract or user not found
GET /conductor/contract/(int: contract_id)/remove

Remove a contract from conductor

We do this by setting the is_visible flag to False, which won’t affect the contract’s visibility on Scout but will remove it from the conductor “all contracts” list.

Parameters:
Status Codes:
  • 302 Found – Set contract visibility to false and redirect to the conductor index view
  • 404 Not Found – Contract not found
POST /conductor/contract/(int: contract_id)/stage/(int: stage_id)
POST /conductor/contract/(int: contract_id)

View to control an individual stage update process

This is the primary view for conductor. All actions that users can take with a ContractBase flow through here.

See also

There are a number of forms that are used on this page to allow the users to do actions directly from the management step:

Parameters:
Status Codes:
  • 200 OK – Render the detail
  • 302 Found – Post a specific form. This form will either transition to the next contract stage if it is a CompleteForm, or perform whatever action is in that form’s post_validate_action method
  • 404 Not Found – Contract not found
GET /conductor/contract/(int: contract_id)/stage/(int: stage_id)
GET /conductor/contract/(int: contract_id)

View to control an individual stage update process

This is the primary view for conductor. All actions that users can take with a ContractBase flow through here.

See also

There are a number of forms that are used on this page to allow the users to do actions directly from the management step:

Parameters:
Status Codes:
  • 200 OK – Render the detail
  • 302 Found – Post a specific form. This form will either transition to the next contract stage if it is a CompleteForm, or perform whatever action is in that form’s post_validate_action method
  • 404 Not Found – Contract not found
GET /conductor/contract/(int: contract_id)/kill

Remove a contract from conductor and scout

Parameters:

See also

See kill() for more on the kill logic

Status Codes:
  • 302 Found – Remove the contract entirely and redirect to the index page
  • 404 Not Found – Contract not found
POST /conductor/flow/(int: flow_id)

View/edit a flow’s details

Status Codes:
  • 200 OK – Render the flow edit template
  • 302 Found – Post changes to the a flow using the submitted FlowForm, redirect back to the current flow’s detail page if successful
GET /conductor/flow/(int: flow_id)

View/edit a flow’s details

Status Codes:
  • 200 OK – Render the flow edit template
  • 302 Found – Post changes to the a flow using the submitted FlowForm, redirect back to the current flow’s detail page if successful

Uploads

GET /conductor/upload/costars/processing

Push the filepath and filename into the template to do the upload via ajax

Status Codes:
  • 200 OK – render the upload success template
POST /conductor/upload/costars/contracts

Upload a contract document pdf for costars

Because the COSTARS website streams contract documents via POST requests instead having them live at some static endpoint, they are re-hosted in S3.

Status Codes:
  • 200 OK – render the upload costars document template
  • 302 Found – attempt to upload a costars document to S3 and set the contract_href on the relevant ContractBase object. Redirect to the same page.
GET /conductor/upload/costars/contracts

Upload a contract document pdf for costars

Because the COSTARS website streams contract documents via POST requests instead having them live at some static endpoint, they are re-hosted in S3.

Status Codes:
  • 200 OK – render the upload costars document template
  • 302 Found – attempt to upload a costars document to S3 and set the contract_href on the relevant ContractBase object. Redirect to the same page.
POST /conductor/upload/costars/_process

Perform the costars upload on the saved file

See also

COSTARS Importer

Status Codes:
POST /conductor/upload/costars

Uploads a new csv file with properly-formatted COSTARS data

Status Codes:
GET /conductor/upload/costars

Uploads a new csv file with properly-formatted COSTARS data

Status Codes:

Metrics

GET /conductor/metrics/download/all

Returns a tsv stream of all conductor contracts

This works as a union of two large queries:

  • A query that gets all contracts that have no children
  • A query that gets all contracts which have parents

The downloaded tsv file has the following fields:

  • the contract’s id (item_number)
  • contract’s parent id (parent_item_number)
  • the contract’s description (description)
  • the contract’s expiration date (expiration_date)
  • the contract parent’s expiration date (parent_expiration)
  • the department name (department)
  • the assigned user’s email address (assigned_to),
  • the contract’s spec number (spec_number)
  • the contract parent’s spec number (parent_spec)
  • a string with the status of a contract (status)
Return:A streamed tsv with the fields described above
GET /conductor/metrics/

Metrics home view

Status Codes:
  • 200 OK – Render metrics index template
GET /conductor/metrics/overview/(int: flow_id)/data

Data to support the metrics charts

The returned object contains the complete and current dictionaries as described in build_metrics_data() along with a stageOrder key of the flow’s stage order for proper sorting on the client side and stageDataObj, which contains metadata about each stage in the proper order

Status Codes:
GET /conductor/metrics/download/(int: flow_id)

Download entry/exit stats for a given flow

Status Codes:
  • 200 OK – Download a tab-separated file with entry/exit information for each contract with a given Flow
  • 404 Not Found – Could not find given Flow
GET /conductor/metrics/overview/(int: flow_id)

Metrics dashboard page for a given flow

Metrics dashboards support charts to answer the following questions:

  • Stage-level average days spent: for each Stage in the stage order for the given Flow, what is the average time contracts spend in that stage?
  • Stage-level in-progress distribution charts: for each Stage in the stage order for the given Flow, what is the distribution of in-progress contracts?
  • Individual stage average distribution detail: For a given Stage, what is the breakdown on timing for each individual ContractBase?
Status Codes: