Skip to content

Workflow

hypha.apply.funds.workflow

PHASE_BG_COLORS module-attribute

PHASE_BG_COLORS = {'Draft': 'bg-gray-200', 'Accepted': 'bg-green-200', 'Need screening': 'bg-cyan-200', 'Ready for Determination': 'bg-blue-200', 'Ready For Discussion': 'bg-blue-100', 'Invited for Proposal': 'bg-green-100', 'Internal Review': 'bg-yellow-200', 'External Review': 'bg-yellow-200', 'More information required': 'bg-yellow-100', 'Accepted but additional info required': 'bg-green-100', 'Dismissed': 'bg-rose-200'}

staff_can module-attribute

staff_can = lambda user: is_apply_staff

applicant_can module-attribute

applicant_can = lambda user: is_applicant

reviewer_can module-attribute

reviewer_can = lambda user: is_reviewer

partner_can module-attribute

partner_can = lambda user: is_partner

community_can module-attribute

community_can = lambda user: is_community_reviewer

no_permissions module-attribute

no_permissions = make_permissions()

default_permissions module-attribute

default_permissions = make_permissions(edit=[staff_can], review=[staff_can])

hidden_from_applicant_permissions module-attribute

hidden_from_applicant_permissions = make_permissions(edit=[staff_can], review=[staff_can], view=[staff_can, reviewer_can])

reviewer_review_permissions module-attribute

reviewer_review_permissions = make_permissions(edit=[staff_can], review=[staff_can, reviewer_can])

community_review_permissions module-attribute

community_review_permissions = make_permissions(edit=[staff_can], review=[staff_can, reviewer_can, community_can])

applicant_edit_permissions module-attribute

applicant_edit_permissions = make_permissions(edit=[applicant_can, partner_can], review=[staff_can])

staff_edit_permissions module-attribute

staff_edit_permissions = make_permissions(edit=[staff_can])

RequestSame module-attribute

RequestSame = Stage('RequestSame', True)

RequestExt module-attribute

RequestExt = Stage('RequestExt', True)

RequestCom module-attribute

RequestCom = Stage('RequestCom', True)

Concept module-attribute

Concept = Stage('Concept', False)

Proposal module-attribute

Proposal = Stage('Proposal', True)

DRAFT_STATE module-attribute

DRAFT_STATE = 'draft'

INITIAL_STATE module-attribute

INITIAL_STATE = 'in_discussion'

SingleStageDefinition module-attribute

SingleStageDefinition = [{DRAFT_STATE: {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('Draft'), 'stage': Request, 'permissions': applicant_edit_permissions}}, {INITIAL_STATE: {'transitions': {'more_info': gettext('Request More Information'), 'internal_review': gettext('Open Review'), 'determination': gettext('Ready For Determination'), 'almost': gettext('Accept but additional info required'), 'accepted': gettext('Accept'), 'rejected': gettext('Dismiss')}, 'display': gettext('Need screening'), 'public': gettext('Application Received'), 'stage': Request, 'permissions': default_permissions}, 'more_info': {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}, 'determination': gettext('Ready For Determination'), 'almost': gettext('Accept but additional info required'), 'accepted': gettext('Accept'), 'rejected': gettext('Dismiss')}, 'display': gettext('More information required'), 'stage': Request, 'permissions': applicant_edit_permissions}}, {'internal_review': {'transitions': {'post_review_discussion': gettext('Close Review'), INITIAL_STATE: gettext('Need screening (revert)')}, 'display': gettext('Internal Review'), 'public': format(org_short_name=ORG_SHORT_NAME), 'stage': Request, 'permissions': default_permissions}}, {'post_review_discussion': {'transitions': {'post_review_more_info': gettext('Request More Information'), 'determination': gettext('Ready For Determination'), 'internal_review': gettext('Open Review (revert)'), 'almost': gettext('Accept but additional info required'), 'accepted': gettext('Accept'), 'rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': Request, 'permissions': hidden_from_applicant_permissions}, 'post_review_more_info': {'transitions': {'post_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}, 'determination': gettext('Ready For Determination'), 'almost': gettext('Accept but additional info required'), 'accepted': gettext('Accept'), 'rejected': gettext('Dismiss')}, 'display': gettext('More information required'), 'stage': Request, 'permissions': applicant_edit_permissions}}, {'determination': {'transitions': {'post_review_discussion': gettext('Ready For Discussion (revert)'), 'almost': gettext('Accept but additional info required'), 'accepted': gettext('Accept'), 'rejected': gettext('Dismiss')}, 'display': gettext('Ready for Determination'), 'permissions': hidden_from_applicant_permissions, 'stage': Request}}, {'accepted': {'display': gettext('Accepted'), 'future': gettext('Application Outcome'), 'stage': Request, 'permissions': staff_edit_permissions}, 'almost': {'transitions': {'accepted': gettext('Accept'), 'post_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('Accepted but additional info required'), 'stage': Request, 'permissions': applicant_edit_permissions}, 'rejected': {'display': gettext('Dismissed'), 'stage': Request, 'permissions': no_permissions}}]

SingleStageSameDefinition module-attribute

SingleStageSameDefinition = [{DRAFT_STATE: {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('Draft'), 'stage': RequestSame, 'permissions': applicant_edit_permissions}}, {INITIAL_STATE: {'transitions': {'same_more_info': gettext('Request More Information'), 'same_internal_review': gettext('Open Review'), 'same_determination': gettext('Ready For Determination'), 'same_rejected': gettext('Dismiss')}, 'display': gettext('Need screening'), 'public': gettext('Application Received'), 'stage': RequestSame, 'permissions': default_permissions}, 'same_more_info': {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestSame, 'permissions': applicant_edit_permissions}}, {'same_internal_review': {'transitions': {'same_post_review_discussion': gettext('Close Review'), INITIAL_STATE: gettext('Need screening (revert)')}, 'display': gettext('Review'), 'public': format(org_short_name=ORG_SHORT_NAME), 'stage': RequestSame, 'permissions': reviewer_review_permissions}}, {'same_post_review_discussion': {'transitions': {'same_post_review_more_info': gettext('Request More Information'), 'same_determination': gettext('Ready For Determination'), 'same_internal_review': gettext('Open Review (revert)'), 'same_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': RequestSame, 'permissions': hidden_from_applicant_permissions}, 'same_post_review_more_info': {'transitions': {'same_post_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestSame, 'permissions': applicant_edit_permissions}}, {'same_determination': {'transitions': {'same_post_review_discussion': gettext('Ready For Discussion (revert)'), 'same_almost': gettext('Accept but additional info required'), 'same_accepted': gettext('Accept'), 'same_rejected': gettext('Dismiss')}, 'display': gettext('Ready for Determination'), 'permissions': hidden_from_applicant_permissions, 'stage': RequestSame}}, {'same_accepted': {'display': gettext('Accepted'), 'future': gettext('Application Outcome'), 'stage': RequestSame, 'permissions': staff_edit_permissions}, 'same_almost': {'transitions': {'same_accepted': gettext('Accept'), 'same_post_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('Accepted but additional info required'), 'stage': RequestSame, 'permissions': applicant_edit_permissions}, 'same_rejected': {'display': gettext('Dismissed'), 'stage': RequestSame, 'permissions': no_permissions}}]

SingleStageExternalDefinition module-attribute

SingleStageExternalDefinition = [{DRAFT_STATE: {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('Draft'), 'stage': RequestExt, 'permissions': applicant_edit_permissions}}, {INITIAL_STATE: {'transitions': {'ext_more_info': gettext('Request More Information'), 'ext_internal_review': gettext('Open Review'), 'ext_determination': gettext('Ready For Determination'), 'ext_rejected': gettext('Dismiss')}, 'display': gettext('Need screening'), 'public': gettext('Application Received'), 'stage': RequestExt, 'permissions': default_permissions}, 'ext_more_info': {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestExt, 'permissions': applicant_edit_permissions}}, {'ext_internal_review': {'transitions': {'ext_post_review_discussion': gettext('Close Review'), INITIAL_STATE: gettext('Need screening (revert)')}, 'display': gettext('Internal Review'), 'public': format(org_short_name=ORG_SHORT_NAME), 'stage': RequestExt, 'permissions': default_permissions}}, {'ext_post_review_discussion': {'transitions': {'ext_post_review_more_info': gettext('Request More Information'), 'ext_external_review': gettext('Open External Review'), 'ext_determination': gettext('Ready For Determination'), 'ext_internal_review': gettext('Open Internal Review (revert)'), 'ext_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': RequestExt, 'permissions': hidden_from_applicant_permissions}, 'ext_post_review_more_info': {'transitions': {'ext_post_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestExt, 'permissions': applicant_edit_permissions}}, {'ext_external_review': {'transitions': {'ext_post_external_review_discussion': gettext('Close Review'), 'ext_post_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('External Review'), 'stage': RequestExt, 'permissions': reviewer_review_permissions}}, {'ext_post_external_review_discussion': {'transitions': {'ext_post_external_review_more_info': gettext('Request More Information'), 'ext_determination': gettext('Ready For Determination'), 'ext_external_review': gettext('Open External Review (revert)'), 'ext_almost': gettext('Accept but additional info required'), 'ext_accepted': gettext('Accept'), 'ext_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': RequestExt, 'permissions': hidden_from_applicant_permissions}, 'ext_post_external_review_more_info': {'transitions': {'ext_post_external_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestExt, 'permissions': applicant_edit_permissions}}, {'ext_determination': {'transitions': {'ext_post_external_review_discussion': gettext('Ready For Discussion (revert)'), 'ext_almost': gettext('Accept but additional info required'), 'ext_accepted': gettext('Accept'), 'ext_rejected': gettext('Dismiss')}, 'display': gettext('Ready for Determination'), 'permissions': hidden_from_applicant_permissions, 'stage': RequestExt}}, {'ext_accepted': {'display': gettext('Accepted'), 'future': gettext('Application Outcome'), 'stage': RequestExt, 'permissions': staff_edit_permissions}, 'ext_almost': {'transitions': {'ext_accepted': gettext('Accept'), 'ext_post_external_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('Accepted but additional info required'), 'stage': RequestExt, 'permissions': applicant_edit_permissions}, 'ext_rejected': {'display': gettext('Dismissed'), 'stage': RequestExt, 'permissions': no_permissions}}]

SingleStageCommunityDefinition module-attribute

SingleStageCommunityDefinition = [{DRAFT_STATE: {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('Draft'), 'stage': RequestCom, 'permissions': applicant_edit_permissions}}, {INITIAL_STATE: {'transitions': {'com_more_info': gettext('Request More Information'), 'com_open_call': 'Open Call (public)', 'com_internal_review': gettext('Open Review'), 'com_community_review': gettext('Open Community Review'), 'com_determination': gettext('Ready For Determination'), 'com_rejected': gettext('Dismiss')}, 'display': gettext('Need screening'), 'public': gettext('Application Received'), 'stage': RequestCom, 'permissions': default_permissions}, 'com_more_info': {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestCom, 'permissions': applicant_edit_permissions}, 'com_open_call': {'transitions': {INITIAL_STATE: gettext('Need screening (revert)'), 'com_rejected': gettext('Dismiss')}, 'display': 'Open Call (public)', 'stage': RequestCom, 'permissions': staff_edit_permissions}}, {'com_internal_review': {'transitions': {'com_community_review': gettext('Open Community Review'), 'com_post_review_discussion': gettext('Close Review'), INITIAL_STATE: gettext('Need screening (revert)'), 'com_rejected': gettext('Dismiss')}, 'display': gettext('Internal Review'), 'public': format(org_short_name=ORG_SHORT_NAME), 'stage': RequestCom, 'permissions': default_permissions}, 'com_community_review': {'transitions': {'com_post_review_discussion': gettext('Close Review'), 'com_internal_review': gettext('Open Internal Review (revert)'), 'com_rejected': gettext('Dismiss')}, 'display': gettext('Community Review'), 'public': format(org_short_name=ORG_SHORT_NAME), 'stage': RequestCom, 'permissions': community_review_permissions}}, {'com_post_review_discussion': {'transitions': {'com_post_review_more_info': gettext('Request More Information'), 'com_external_review': gettext('Open External Review'), 'com_determination': gettext('Ready For Determination'), 'com_internal_review': gettext('Open Internal Review (revert)'), 'com_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': RequestCom, 'permissions': hidden_from_applicant_permissions}, 'com_post_review_more_info': {'transitions': {'com_post_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestCom, 'permissions': applicant_edit_permissions}}, {'com_external_review': {'transitions': {'com_post_external_review_discussion': gettext('Close Review'), 'com_post_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('External Review'), 'stage': RequestCom, 'permissions': reviewer_review_permissions}}, {'com_post_external_review_discussion': {'transitions': {'com_post_external_review_more_info': gettext('Request More Information'), 'com_determination': gettext('Ready For Determination'), 'com_external_review': gettext('Open External Review (revert)'), 'com_almost': gettext('Accept but additional info required'), 'com_accepted': gettext('Accept'), 'com_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': RequestCom, 'permissions': hidden_from_applicant_permissions}, 'com_post_external_review_more_info': {'transitions': {'com_post_external_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': RequestCom, 'permissions': applicant_edit_permissions}}, {'com_determination': {'transitions': {'com_post_external_review_discussion': gettext('Ready For Discussion (revert)'), 'com_almost': gettext('Accept but additional info required'), 'com_accepted': gettext('Accept'), 'com_rejected': gettext('Dismiss')}, 'display': gettext('Ready for Determination'), 'permissions': hidden_from_applicant_permissions, 'stage': RequestCom}}, {'com_accepted': {'display': gettext('Accepted'), 'future': gettext('Application Outcome'), 'stage': RequestCom, 'permissions': staff_edit_permissions}, 'com_almost': {'transitions': {'com_accepted': gettext('Accept'), 'com_post_external_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('Accepted but additional info required'), 'stage': RequestCom, 'permissions': applicant_edit_permissions}, 'com_rejected': {'display': gettext('Dismissed'), 'stage': RequestCom, 'permissions': no_permissions}}]

DoubleStageDefinition module-attribute

DoubleStageDefinition = [{DRAFT_STATE: {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('Draft'), 'stage': Concept, 'permissions': applicant_edit_permissions}}, {INITIAL_STATE: {'transitions': {'concept_more_info': gettext('Request More Information'), 'concept_internal_review': gettext('Open Review'), 'concept_determination': gettext('Ready For Preliminary Determination'), 'invited_to_proposal': gettext('Invite to Proposal'), 'concept_rejected': gettext('Dismiss')}, 'display': gettext('Need screening'), 'public': gettext('Concept Note Received'), 'stage': Concept, 'permissions': default_permissions}, 'concept_more_info': {'transitions': {INITIAL_STATE: {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}, 'concept_rejected': gettext('Dismiss'), 'invited_to_proposal': gettext('Invite to Proposal'), 'concept_determination': gettext('Ready For Preliminary Determination')}, 'display': gettext('More information required'), 'stage': Concept, 'permissions': applicant_edit_permissions}}, {'concept_internal_review': {'transitions': {'concept_review_discussion': gettext('Close Review'), INITIAL_STATE: gettext('Need screening (revert)'), 'invited_to_proposal': gettext('Invite to Proposal')}, 'display': gettext('Internal Review'), 'public': format(org_short_name=ORG_SHORT_NAME), 'stage': Concept, 'permissions': default_permissions}}, {'concept_review_discussion': {'transitions': {'concept_review_more_info': gettext('Request More Information'), 'concept_determination': gettext('Ready For Preliminary Determination'), 'concept_internal_review': gettext('Open Review (revert)'), 'invited_to_proposal': gettext('Invite to Proposal'), 'concept_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': Concept, 'permissions': hidden_from_applicant_permissions}, 'concept_review_more_info': {'transitions': {'concept_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}, 'invited_to_proposal': gettext('Invite to Proposal')}, 'display': gettext('More information required'), 'stage': Concept, 'permissions': applicant_edit_permissions}}, {'concept_determination': {'transitions': {'concept_review_discussion': gettext('Ready For Discussion (revert)'), 'invited_to_proposal': gettext('Invite to Proposal'), 'concept_rejected': gettext('Dismiss')}, 'display': gettext('Ready for Preliminary Determination'), 'permissions': hidden_from_applicant_permissions, 'stage': Concept}}, {'invited_to_proposal': {'display': gettext('Concept Accepted'), 'future': gettext('Preliminary Determination'), 'transitions': {'draft_proposal': {'display': gettext('Progress'), 'method': 'progress_application', 'permissions': {STAFF, LEAD, ADMIN}, 'conditions': 'not_progressed'}}, 'stage': Concept, 'permissions': no_permissions}, 'concept_rejected': {'display': gettext('Dismissed'), 'stage': Concept, 'permissions': no_permissions}}, {'draft_proposal': {'transitions': {'proposal_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}, 'external_review': gettext('Open External Review'), 'proposal_determination': gettext('Ready For Final Determination'), 'proposal_rejected': gettext('Dismiss')}, 'display': gettext('Invited for Proposal'), 'stage': Proposal, 'permissions': applicant_edit_permissions}}, {'proposal_discussion': {'transitions': {'proposal_more_info': gettext('Request More Information'), 'proposal_internal_review': gettext('Open Review'), 'external_review': gettext('Open External Review'), 'proposal_determination': gettext('Ready For Final Determination'), 'proposal_rejected': gettext('Dismiss')}, 'display': gettext('Proposal Received'), 'stage': Proposal, 'permissions': default_permissions}, 'proposal_more_info': {'transitions': {'proposal_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}, 'external_review': gettext('Open External Review'), 'proposal_determination': gettext('Ready For Final Determination'), 'proposal_rejected': gettext('Dismiss')}, 'display': gettext('More information required'), 'stage': Proposal, 'permissions': applicant_edit_permissions}}, {'proposal_internal_review': {'transitions': {'post_proposal_review_discussion': gettext('Close Review'), 'proposal_discussion': gettext('Proposal Received (revert)')}, 'display': gettext('Internal Review'), 'public': format(org_short_name=ORG_SHORT_NAME), 'stage': Proposal, 'permissions': default_permissions}}, {'post_proposal_review_discussion': {'transitions': {'post_proposal_review_more_info': gettext('Request More Information'), 'external_review': gettext('Open External Review'), 'proposal_determination': gettext('Ready For Final Determination'), 'proposal_internal_review': gettext('Open Internal Review (revert)'), 'proposal_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': Proposal, 'permissions': hidden_from_applicant_permissions}, 'post_proposal_review_more_info': {'transitions': {'post_proposal_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}, 'external_review': gettext('Open External Review')}, 'display': gettext('More information required'), 'stage': Proposal, 'permissions': applicant_edit_permissions}}, {'external_review': {'transitions': {'post_external_review_discussion': gettext('Close Review'), 'post_proposal_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('External Review'), 'stage': Proposal, 'permissions': reviewer_review_permissions}}, {'post_external_review_discussion': {'transitions': {'post_external_review_more_info': gettext('Request More Information'), 'proposal_determination': gettext('Ready For Final Determination'), 'external_review': gettext('Open External Review (revert)'), 'proposal_almost': gettext('Accept but additional info required'), 'proposal_accepted': gettext('Accept'), 'proposal_rejected': gettext('Dismiss')}, 'display': gettext('Ready For Discussion'), 'stage': Proposal, 'permissions': hidden_from_applicant_permissions}, 'post_external_review_more_info': {'transitions': {'post_external_review_discussion': {'display': gettext('Submit'), 'permissions': {APPLICANT, STAFF, LEAD, ADMIN}, 'method': 'create_revision', 'custom': {'trigger_on_submit': True}}}, 'display': gettext('More information required'), 'stage': Proposal, 'permissions': applicant_edit_permissions}}, {'proposal_determination': {'transitions': {'post_external_review_discussion': gettext('Ready For Discussion (revert)'), 'proposal_almost': gettext('Accept but additional info required'), 'proposal_accepted': gettext('Accept'), 'proposal_rejected': gettext('Dismiss')}, 'display': gettext('Ready for Final Determination'), 'permissions': hidden_from_applicant_permissions, 'stage': Proposal}}, {'proposal_accepted': {'display': gettext('Accepted'), 'future': gettext('Final Determination'), 'stage': Proposal, 'permissions': staff_edit_permissions}, 'proposal_almost': {'transitions': {'proposal_accepted': gettext('Accept'), 'post_external_review_discussion': gettext('Ready For Discussion (revert)')}, 'display': gettext('Accepted but additional info required'), 'stage': Proposal, 'permissions': applicant_edit_permissions}, 'proposal_rejected': {'display': gettext('Dismissed'), 'stage': Proposal, 'permissions': no_permissions}}]

Request module-attribute

Request = Workflow('Request', 'single', **phase_data(SingleStageDefinition))

RequestSameTime module-attribute

RequestSameTime = Workflow('Request with same time review', 'single_same', **phase_data(SingleStageSameDefinition))

RequestExternal module-attribute

RequestExternal = Workflow('Request with external review', 'single_ext', **phase_data(SingleStageExternalDefinition))

RequestCommunity module-attribute

RequestCommunity = Workflow('Request with community review', 'single_com', **phase_data(SingleStageCommunityDefinition))

ConceptProposal module-attribute

ConceptProposal = Workflow('Concept & Proposal', 'double', **phase_data(DoubleStageDefinition))

WORKFLOWS module-attribute

WORKFLOWS = {admin_name: Request, admin_name: RequestSameTime, admin_name: RequestExternal, admin_name: RequestCommunity, admin_name: ConceptProposal}

PHASES module-attribute

PHASES = list(from_iterable(items() for workflow in values()))

STAGE_CHANGE_ACTIONS module-attribute

STAGE_CHANGE_ACTIONS = get_stage_change_actions()

STATUSES module-attribute

STATUSES = defaultdict(set)

active_statuses module-attribute

active_statuses = [status for (status, gettext) in PHASES if 'accepted' not in status and 'rejected' not in status and 'invited' not in status]

review_statuses module-attribute

review_statuses = get_review_statuses()

ext_review_statuses module-attribute

ext_review_statuses = get_ext_review_statuses()

ext_or_higher_statuses module-attribute

ext_or_higher_statuses = get_ext_or_higher_statuses()

accepted_statuses module-attribute

accepted_statuses = get_accepted_statuses()

dismissed_statuses module-attribute

dismissed_statuses = get_dismissed_statuses()

DETERMINATION_PHASES module-attribute

DETERMINATION_PHASES = [phase_name for (phase_name, gettext) in PHASES if '_discussion' in phase_name]

DETERMINATION_RESPONSE_PHASES module-attribute

DETERMINATION_RESPONSE_PHASES = ['post_review_discussion', 'concept_review_discussion', 'same_post_review_discussion', 'post_external_review_discussion', 'ext_post_external_review_discussion', 'com_post_external_review_discussion']

DETERMINATION_OUTCOMES module-attribute

DETERMINATION_OUTCOMES = get_determination_transitions()

PHASES_MAPPING module-attribute

PHASES_MAPPING = {'received': {'name': gettext('Received'), 'statuses': [INITIAL_STATE, 'proposal_discussion']}, 'internal-review': {'name': gettext('Internal Review'), 'statuses': phases_matching('internal_review')}, 'in-discussion': {'name': gettext('Ready for Discussion'), 'statuses': phases_matching('discussion', exclude=[INITIAL_STATE, 'proposal_discussion'])}, 'more-information': {'name': gettext('More Information Requested'), 'statuses': phases_matching('more_info')}, 'invited-for-proposal': {'name': gettext('Invited for Proposal'), 'statuses': ['draft_proposal']}, 'external-review': {'name': gettext('External Review'), 'statuses': phases_matching('external_review')}, 'ready-for-determination': {'name': gettext('Ready for Determination'), 'statuses': phases_matching('determination')}, 'accepted': {'name': gettext('Accepted'), 'statuses': phases_matching('accepted')}, 'dismissed': {'name': gettext('Dismissed'), 'statuses': phases_matching('rejected')}}

OPEN_CALL_PHASES module-attribute

OPEN_CALL_PHASES = ['com_open_call']

COMMUNITY_REVIEW_PHASES module-attribute

COMMUNITY_REVIEW_PHASES = ['com_community_review']

UserPermissions

Bases: Enum

STAFF class-attribute instance-attribute

STAFF = 1

ADMIN class-attribute instance-attribute

ADMIN = 2

LEAD class-attribute instance-attribute

LEAD = 3

APPLICANT class-attribute instance-attribute

APPLICANT = 4

Workflow

Workflow(name, admin_name, **data)

Bases: dict

Source code in hypha/apply/funds/workflow.py
def __init__(self, name, admin_name, **data):
    self.name = name
    self.admin_name = admin_name
    super().__init__(**data)

name instance-attribute

name = name

admin_name instance-attribute

admin_name = admin_name

stages property

stages

stepped_phases property

stepped_phases

phases_for

phases_for(user=None)
Source code in hypha/apply/funds/workflow.py
def phases_for(self, user=None):
    # Grab the first phase for each step - visible only, the display phase
    return [
        phase
        for phase, *_ in self.stepped_phases.values()
        if not user or phase.permissions.can_view(user)
    ]

previous_visible

previous_visible(current, user)

Find the latest phase that the user has view permissions for

Source code in hypha/apply/funds/workflow.py
def previous_visible(self, current, user):
    """Find the latest phase that the user has view permissions for"""
    display_phase = self.stepped_phases[current.step][0]
    phases = self.phases_for()
    index = phases.index(display_phase)
    for phase in phases[index - 1 :: -1]:
        if phase.permissions.can_view(user):
            return phase

Phase

Phase(name, display, stage, permissions, step, public=None, future=None, transitions=None)

Phase Names: display_name = phase name displayed to staff members in the system public_name = phase name displayed to applicants in the system future_name = phase_name displayed to applicants if they haven't passed this stage

Source code in hypha/apply/funds/workflow.py
def __init__(
    self,
    name,
    display,
    stage,
    permissions,
    step,
    public=None,
    future=None,
    transitions=None,
):
    if transitions is None:
        transitions = {}
    self.name = name
    self.display_name = display
    self.display_slug = slugify(display)
    if public and future:
        raise ValueError("Cant provide both a future and a public name")

    self.public_name = public or self.display_name
    self.future_name_staff = future or self.display_name
    self.bg_color = PHASE_BG_COLORS.get(self.display_name, "bg-gray-200")
    self.future_name_public = future or self.public_name
    self.stage = stage
    self.permissions = Permissions(permissions)
    self.step = step

    # For building transition methods on the parent
    self.transitions = {}

    default_permissions = {
        UserPermissions.STAFF,
        UserPermissions.LEAD,
        UserPermissions.ADMIN,
    }

    for transition_target, action in transitions.items():
        transition = {}
        try:
            transition["display"] = action.get("display")
        except AttributeError:
            transition["display"] = action
            transition["permissions"] = default_permissions
        else:
            transition["method"] = action.get("method")
            conditions = action.get("conditions", "")
            transition["conditions"] = conditions.split(",") if conditions else []
            transition["permissions"] = action.get(
                "permissions", default_permissions
            )
            if "custom" in action:
                transition["custom"] = action["custom"]

        self.transitions[transition_target] = transition

name instance-attribute

name = name

display_name instance-attribute

display_name = display

display_slug instance-attribute

display_slug = slugify(display)

public_name instance-attribute

public_name = public or display_name

future_name_staff instance-attribute

future_name_staff = future or display_name

bg_color instance-attribute

bg_color = get(display_name, 'bg-gray-200')

future_name_public instance-attribute

future_name_public = future or public_name

stage instance-attribute

stage = stage

permissions instance-attribute

permissions = Permissions(permissions)

step instance-attribute

step = step

transitions instance-attribute

transitions = {}

Stage

Stage(name, has_external_review=False)
Source code in hypha/apply/funds/workflow.py
def __init__(self, name, has_external_review=False):
    self.name = name
    self.has_external_review = has_external_review

name instance-attribute

name = name

has_external_review instance-attribute

has_external_review = has_external_review

Permissions

Permissions(permissions)
Source code in hypha/apply/funds/workflow.py
def __init__(self, permissions):
    self.permissions = permissions

permissions instance-attribute

permissions = permissions

can_do

can_do(user, action)
Source code in hypha/apply/funds/workflow.py
def can_do(self, user, action):
    checks = self.permissions.get(action, [])
    return any(check(user) for check in checks)

can_edit

can_edit(user)
Source code in hypha/apply/funds/workflow.py
def can_edit(self, user):
    return self.can_do(user, "edit")

can_review

can_review(user)
Source code in hypha/apply/funds/workflow.py
def can_review(self, user):
    return self.can_do(user, "review")

can_view

can_view(user)
Source code in hypha/apply/funds/workflow.py
def can_view(self, user):
    return self.can_do(user, "view")

make_permissions

make_permissions(edit=None, review=None, view=None)
Source code in hypha/apply/funds/workflow.py
def make_permissions(edit=None, review=None, view=None):
    return {
        "edit": edit or [],
        "review": review or [],
        "view": view
        or [
            staff_can,
            applicant_can,
            reviewer_can,
            partner_can,
        ],
    }

unpack_phases

unpack_phases(phases)

Unpack a list of phases into a generator of step, name, phase_data.

Source code in hypha/apply/funds/workflow.py
def unpack_phases(phases):
    """Unpack a list of phases into a generator of step, name, phase_data."""
    return (
        (step, name, phase_data)
        for step, step_data in enumerate(phases)
        for name, phase_data in step_data.items()
    )

phase_data

phase_data(phases)

Convert a list of phases into a dictionary of Phase objects.

Adds the step number to the phase data. The step number is the index of the phase in the list of phases.

Source code in hypha/apply/funds/workflow.py
def phase_data(phases):
    """Convert a list of phases into a dictionary of Phase objects.

    Adds the step number to the phase data. The step number is the index of the
    phase in the list of phases.
    """
    return {
        phase_name: Phase(phase_name, step=step, **phase_data)
        for step, phase_name, phase_data in unpack_phases(phases)
    }

get_stage_change_actions

get_stage_change_actions()
Source code in hypha/apply/funds/workflow.py
def get_stage_change_actions():
    changes = set()
    for workflow in WORKFLOWS.values():
        stage = None
        for phase in workflow.values():
            if phase.stage != stage and stage:
                changes.add(phase.name)
            stage = phase.stage

    return changes

get_review_active_statuses

get_review_active_statuses(user=None)
Source code in hypha/apply/funds/workflow.py
def get_review_active_statuses(user=None):
    reviews = set()

    for phase_name, phase in PHASES:
        if phase_name in active_statuses:
            if user is None:
                reviews.add(phase_name)
            elif phase.permissions.can_review(user):
                reviews.add(phase_name)
    return reviews

get_review_statuses

get_review_statuses(user=None)
Source code in hypha/apply/funds/workflow.py
def get_review_statuses(user=None):
    reviews = set()

    for phase_name, phase in PHASES:
        if "review" in phase_name and "discussion" not in phase_name:
            if user is None:
                reviews.add(phase_name)
            elif phase.permissions.can_review(user):
                reviews.add(phase_name)
    return reviews

get_ext_review_statuses

get_ext_review_statuses()
Source code in hypha/apply/funds/workflow.py
def get_ext_review_statuses():
    reviews = set()

    for phase_name, _phase in PHASES:
        if phase_name.endswith("external_review"):
            reviews.add(phase_name)
    return reviews

get_ext_or_higher_statuses

get_ext_or_higher_statuses()

Returns a set of all the statuses for all workflow which are External Review or higher than that.

Source code in hypha/apply/funds/workflow.py
def get_ext_or_higher_statuses():
    """
    Returns a set of all the statuses for all workflow which are
    External Review or higher than that.
    """
    reviews = set()

    for workflow in WORKFLOWS.values():
        step = None
        for phase in workflow.values():
            if phase.name.endswith("external_review"):
                # Update the step for this workflow as External review state
                step = phase.step

            # Phase should have step higher or equal than External
            # review state for this workflow
            if step and phase.step >= step:
                reviews.add(phase.name)
    return reviews

get_accepted_statuses

get_accepted_statuses()
Source code in hypha/apply/funds/workflow.py
def get_accepted_statuses():
    accepted_statuses = set()
    for phase_name, phase in PHASES:
        if phase.display_name == "Accepted":
            accepted_statuses.add(phase_name)
    return accepted_statuses

get_dismissed_statuses

get_dismissed_statuses()
Source code in hypha/apply/funds/workflow.py
def get_dismissed_statuses():
    dismissed_statuses = set()
    for phase_name, phase in PHASES:
        if phase.display_name == "Dismissed":
            dismissed_statuses.add(phase_name)
    return dismissed_statuses

get_determination_transitions

get_determination_transitions()
Source code in hypha/apply/funds/workflow.py
def get_determination_transitions():
    transitions = {}
    for _phase_name, phase in PHASES:
        for transition_name in phase.transitions:
            if "accepted" in transition_name:
                transitions[transition_name] = "accepted"
            elif "rejected" in transition_name:
                transitions[transition_name] = "rejected"
            elif "more_info" in transition_name:
                transitions[transition_name] = "more_info"
            elif "invited_to_proposal" in transition_name:
                transitions[transition_name] = "accepted"

    return transitions

get_action_mapping

get_action_mapping(workflow)
Source code in hypha/apply/funds/workflow.py
def get_action_mapping(workflow):
    # Maps action names to the phase they originate from
    transitions = defaultdict(lambda: {"display": "", "transitions": []})
    if workflow:
        phases = workflow.items()
    else:
        phases = PHASES
    for _phase_name, phase in phases:
        for transition_name, transition in phase.transitions.items():
            transition_display = transition["display"]
            transition_key = slugify(transition_display)
            transitions[transition_key]["transitions"].append(transition_name)
            transitions[transition_key]["display"] = transition_display

    return transitions

phases_matching

phases_matching(phrase, exclude=None)
Source code in hypha/apply/funds/workflow.py
def phases_matching(phrase, exclude=None):
    if exclude is None:
        exclude = []
    return [
        status
        for status, _ in PHASES
        if status.endswith(phrase) and status not in exclude
    ]