def transition(contract_id, stage_id):

    contract = ContractBase.query.get(contract_id)
    stage = ContractStage.query.filter(ContractStage.id == stage_id).first()
    complete_form = CompleteForm(started=stage.entered)

    if (request.method == 'POST' and complete_form.validate_on_submit()) or (request.method == 'GET'):
        if request.method == 'POST':
            completed_time = current_app.config['DISPLAY_TIMEZONE'].localize(
                complete_form.complete.data
            ).astimezone(pytz.UTC).replace(tzinfo=None)
        else:
            completed_time = datetime.datetime.utcnow()

        if not contract:
            abort(404)

        clicked = int(request.args.get('destination')) if \
            request.args.get('destination') else None

        try:
            actions = contract.transition(current_user, destination=clicked, complete_time=completed_time)
            for action in actions:
                db.session.add(action)
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            pass
        except Exception:
            db.session.rollback()
            raise

        current_app.logger.info(
            'CONDUCTOR TRANSITION - Contract for {} (ID: {}) transition to {}'.format(
                contract.description, contract.id, contract.current_stage.name
            )
        )

        if contract.completed_last_stage():
            url = url_for('conductor.edit', contract_id=contract.id)
        else:
            url = url_for('conductor.detail', contract_id=contract.id)

        return redirect(url)

    session['invalid_date-{}'.format(contract_id)] = complete_form.errors['complete'][0]
    return redirect(url_for('conductor.detail', contract_id=contract.id))
def detail(contract_id, stage_id=-1):
    '''View to control an individual stage update process
    '''
    contract = ContractBase.query.get(contract_id)
    if not contract:
        abort(404)

    if contract.completed_last_stage():
        return redirect(url_for('conductor.edit', contract_id=contract.id))

    if stage_id == -1:
        # redirect to the current stage page
        contract_stage = contract.get_current_stage()

        if contract_stage:
            return redirect(url_for(
                'conductor.detail', contract_id=contract_id, stage_id=contract_stage.id
            ))
        current_app.logger.warning('Could not find stages for this contract, aborting!')
        abort(500)

    stages = get_contract_stages(contract)

    try:
        active_stage = [i for i in stages if i.id == stage_id][0]
        current_stage = [i for i in stages if i.entered and not i.exited][0]
        if active_stage.entered is None:
            abort(404)
    except IndexError:
        abort(404)

    note_form = NoteForm()
    update_form = SendUpdateForm(obj=UpdateFormObj(current_stage))
    opportunity_form = PostOpportunityForm(
        obj=contract.opportunity if contract.opportunity else ConductorObj(contract)
    )
    metadata_form = ContractMetadataForm(obj=ContractMetadataObj(contract))
    complete_form = CompleteForm()

    if session.get('invalid_date-{}'.format(contract_id), False):
        complete_form.errors['complete'] = session.pop('invalid_date-{}'.format(contract_id))

    forms = {
        'activity': note_form, 'update': update_form,
        'post': opportunity_form, 'update-metadata': metadata_form
    }

    active_tab = '#activity'

    submitted_form = request.args.get('form', None)

    if submitted_form:
        if handle_form(
            forms[submitted_form], submitted_form, stage_id,
            current_user, contract, active_stage
        ):
            return redirect(url_for(
                'conductor.detail', contract_id=contract_id, stage_id=stage_id
            ))
        else:
            active_tab = '#' + submitted_form

    actions = contract.filter_action_log()
    # actions = contract.build_complete_action_log()
    subscribers, total_subscribers = build_subscribers(contract)
    flows = Flow.query.filter(Flow.id != contract.flow_id).all()

    current_app.logger.info(
        'CONDUCTOR DETAIL VIEW - Detail view for contract {} (ID: {}), stage {}'.format(
            contract.description, contract.id, current_stage.name
        )
    )

    opportunity_form.display_cleanup()
    if len(stages) > 0:
        return render_template(
            'conductor/detail.html',
            stages=stages, actions=actions, active_tab=active_tab,
            note_form=note_form, update_form=update_form,
            opportunity_form=opportunity_form, metadata_form=metadata_form,
            complete_form=complete_form, contract=contract,
            current_user=current_user, active_stage=active_stage,
            current_stage=current_stage, flows=flows, subscribers=subscribers,
            total_subscribers=total_subscribers,
            current_stage_enter=pytz.UTC.localize(
                current_stage.entered
            ).astimezone(current_app.config['DISPLAY_TIMEZONE']),
            categories=opportunity_form.get_categories(),
            subcategories=opportunity_form.get_subcategories()
        )
    abort(404)
Esempio n. 3
0
def detail(contract_id, stage_id=-1):
    '''View to control an individual stage update process

    This is the primary view for conductor. All actions that users can
    take with a :py:class:`~purchasing.data.contracts.ContractBase` flow
    through here.

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

        * :py:class:`~purchasing.conductor.forms.NoteForm` to allow
          users to take notes
        * :py:class:`~purchasing.conductor.forms.SendUpdateForm` to allow
          users to send email updates
        * :py:class:`~purchasing.conductor.forms.PostOpportunityForm` to allow
          users to post opportunities directly to :doc:`/beacon`
        * :py:class:`~purchasing.conductor.forms.ContractMetadataForm` to allow
          users to update a contract's metadata
        * :py:class:`~purchasing.conductor.forms.CompleteForm` to allow
          users to transition to the next :py:class:`~purchasing.data.stages.Stage`
          in the contract's :py:class:`~purchasing.data.flows.Flow`

    :param contract_id: Primary key ID for a
        :py:class:`~purchasing.data.contracts.ContractBase`
    :param stage_id: Primary key ID for a
        :py:class:`~purchasing.data.contract_stages.ContractStage`

    :status 200: Render the detail
    :status 302: Post a specific form. This form will either transition
        to the next contract stage if it is a
        :py:class:`~purchasing.conductor.forms.CompleteForm`, or perform
        whatever action is in that form's ``post_validate_action`` method
    :status 404: Contract not found
    '''
    contract = ContractBase.query.get(contract_id)
    if not contract:
        abort(404)

    if contract.completed_last_stage():
        return redirect(url_for('conductor.edit', contract_id=contract.id))

    if stage_id == -1:
        # redirect to the current stage page
        contract_stage = contract.get_current_stage()

        if contract_stage:
            return redirect(
                url_for('conductor.detail',
                        contract_id=contract_id,
                        stage_id=contract_stage.id))
        current_app.logger.warning(
            'Could not find stages for this contract, aborting!')
        abort(500)

    stages = contract.get_contract_stages()

    try:
        active_stage = [i for i in stages if i.id == stage_id][0]
        current_stage = [i for i in stages if i.entered and not i.exited][0]
        if active_stage.entered is None:
            abort(404)
    except IndexError:
        abort(404)

    note_form = NoteForm()
    update_form = SendUpdateForm(obj=UpdateFormObj(current_stage))
    opportunity_form = PostOpportunityForm(
        obj=contract.opportunity if contract.
        opportunity else ConductorToBeaconObj(contract))
    metadata_form = ContractMetadataForm(obj=ContractMetadataObj(contract))
    complete_form = CompleteForm()

    if session.get('invalid_date-{}'.format(contract_id), False):
        complete_form.errors['complete'] = session.pop(
            'invalid_date-{}'.format(contract_id))

    forms = {
        'activity': note_form,
        'update': update_form,
        'post': opportunity_form,
        'update-metadata': metadata_form
    }

    active_tab = '#activity'

    submitted_form_name = request.args.get('form', None)

    if submitted_form_name:
        submitted_form = forms[submitted_form_name]

        if submitted_form.validate_on_submit():
            action = ContractStageActionItem(
                contract_stage_id=stage_id,
                action_type=submitted_form_name,
                taken_by=current_user.id,
                taken_at=datetime.datetime.utcnow())
            action = submitted_form.post_validate_action(
                action, contract, current_stage)

            db.session.add(action)
            db.session.commit()

            return redirect(
                url_for('conductor.detail',
                        contract_id=contract_id,
                        stage_id=stage_id))
        else:
            active_tab = '#' + submitted_form_name

    actions = contract.filter_action_log()
    # actions = contract.build_complete_action_log()
    subscribers, total_subscribers = contract.build_subscribers()
    flows = Flow.query.filter(Flow.id != contract.flow_id).all()

    current_app.logger.info(
        'CONDUCTOR DETAIL VIEW - Detail view for contract {} (ID: {}), stage {}'
        .format(contract.description, contract.id, current_stage.name))

    opportunity_form.display_cleanup()
    if len(stages) > 0:
        return render_template(
            'conductor/detail.html',
            stages=stages,
            actions=actions,
            active_tab=active_tab,
            note_form=note_form,
            update_form=update_form,
            opportunity_form=opportunity_form,
            metadata_form=metadata_form,
            complete_form=complete_form,
            contract=contract,
            current_user=current_user,
            active_stage=active_stage,
            current_stage=current_stage,
            flows=flows,
            subscribers=subscribers,
            total_subscribers=total_subscribers,
            current_stage_enter=localize_datetime(current_stage.entered),
            categories=opportunity_form.get_categories(),
            subcategories=opportunity_form.get_subcategories())
    abort(404)
Esempio n. 4
0
def transition(contract_id, stage_id):
    '''Transition a contract from one date to the next date

    :param contract_id: Primary key ID for a
        :py:class:`~purchasing.data.contracts.ContractBase`
    :param stage_id: Primary key ID for a
        :py:class:`~purchasing.data.contract_stages.ContractStage`

    .. seealso::
        For the transition, see the
        :py:meth:`~purchasing.data.contracts.ContractBase.transition`
        method directly

    :status 302: Perform the transition, and redirect back to the detail view
        with either the new stage or the appropriate error message
    :status 404: Contract not found
    '''
    contract = ContractBase.query.get(contract_id)
    stage = ContractStage.query.filter(ContractStage.id == stage_id).first()
    complete_form = CompleteForm(started=stage.entered)

    if (request.method == 'POST'
            and complete_form.validate_on_submit()) or (request.method
                                                        == 'GET'):
        if request.method == 'POST':
            completed_time = current_app.config['DISPLAY_TIMEZONE'].localize(
                complete_form.complete.data).astimezone(
                    pytz.UTC).replace(tzinfo=None)
        else:
            completed_time = datetime.datetime.utcnow()

        if not contract:
            abort(404)

        clicked = int(request.args.get('destination')) if \
            request.args.get('destination') else None

        try:
            actions = contract.transition(current_user,
                                          destination=clicked,
                                          complete_time=completed_time)
            for action in actions:
                db.session.add(action)
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            pass
        except Exception:
            db.session.rollback()
            raise

        current_app.logger.info(
            'CONDUCTOR TRANSITION - Contract for {} (ID: {}) transition to {}'.
            format(contract.description, contract.id,
                   contract.current_stage.name))

        if contract.completed_last_stage():
            url = url_for('conductor.edit', contract_id=contract.id)
        else:
            url = url_for('conductor.detail', contract_id=contract.id)

        return redirect(url)

    session['invalid_date-{}'.format(
        contract_id)] = complete_form.errors['complete'][0]
    return redirect(url_for('conductor.detail', contract_id=contract.id))
def detail(contract_id, stage_id=-1):
    '''View to control an individual stage update process

    This is the primary view for conductor. All actions that users can
    take with a :py:class:`~purchasing.data.contracts.ContractBase` flow
    through here.

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

        * :py:class:`~purchasing.conductor.forms.NoteForm` to allow
          users to take notes
        * :py:class:`~purchasing.conductor.forms.SendUpdateForm` to allow
          users to send email updates
        * :py:class:`~purchasing.conductor.forms.PostOpportunityForm` to allow
          users to post opportunities directly to :doc:`/beacon`
        * :py:class:`~purchasing.conductor.forms.ContractMetadataForm` to allow
          users to update a contract's metadata
        * :py:class:`~purchasing.conductor.forms.CompleteForm` to allow
          users to transition to the next :py:class:`~purchasing.data.stages.Stage`
          in the contract's :py:class:`~purchasing.data.flows.Flow`

    :param contract_id: Primary key ID for a
        :py:class:`~purchasing.data.contracts.ContractBase`
    :param stage_id: Primary key ID for a
        :py:class:`~purchasing.data.contract_stages.ContractStage`

    :status 200: Render the detail
    :status 302: Post a specific form. This form will either transition
        to the next contract stage if it is a
        :py:class:`~purchasing.conductor.forms.CompleteForm`, or perform
        whatever action is in that form's ``post_validate_action`` method
    :status 404: Contract not found
    '''
    contract = ContractBase.query.get(contract_id)
    if not contract:
        abort(404)

    if contract.completed_last_stage():
        return redirect(url_for('conductor.edit', contract_id=contract.id))

    if stage_id == -1:
        # redirect to the current stage page
        contract_stage = contract.get_current_stage()

        if contract_stage:
            return redirect(url_for(
                'conductor.detail', contract_id=contract_id, stage_id=contract_stage.id
            ))
        current_app.logger.warning('Could not find stages for this contract, aborting!')
        abort(500)

    stages = contract.get_contract_stages()

    try:
        active_stage = [i for i in stages if i.id == stage_id][0]
        current_stage = [i for i in stages if i.entered and not i.exited][0]
        if active_stage.entered is None:
            abort(404)
    except IndexError:
        abort(404)

    note_form = NoteForm()
    update_form = SendUpdateForm(obj=UpdateFormObj(current_stage))
    opportunity_form = PostOpportunityForm(
        obj=contract.opportunity if contract.opportunity else ConductorToBeaconObj(contract)
    )
    metadata_form = ContractMetadataForm(obj=ContractMetadataObj(contract))
    complete_form = CompleteForm()

    if session.get('invalid_date-{}'.format(contract_id), False):
        complete_form.errors['complete'] = session.pop('invalid_date-{}'.format(contract_id))

    forms = {
        'activity': note_form, 'update': update_form,
        'post': opportunity_form, 'update-metadata': metadata_form
    }

    active_tab = '#activity'

    submitted_form_name = request.args.get('form', None)

    if submitted_form_name:
        submitted_form = forms[submitted_form_name]

        if submitted_form.validate_on_submit():
            action = ContractStageActionItem(
                contract_stage_id=stage_id, action_type=submitted_form_name,
                taken_by=current_user.id, taken_at=datetime.datetime.utcnow()
            )
            action = submitted_form.post_validate_action(action, contract, current_stage)

            db.session.add(action)
            db.session.commit()

            return redirect(url_for(
                'conductor.detail', contract_id=contract_id, stage_id=stage_id
            ))
        else:
            active_tab = '#' + submitted_form_name

    actions = contract.filter_action_log()
    # actions = contract.build_complete_action_log()
    subscribers, total_subscribers = contract.build_subscribers()
    flows = Flow.query.filter(Flow.id != contract.flow_id).all()

    current_app.logger.info(
        'CONDUCTOR DETAIL VIEW - Detail view for contract {} (ID: {}), stage {}'.format(
            contract.description, contract.id, current_stage.name
        )
    )

    opportunity_form.display_cleanup()
    if len(stages) > 0:
        return render_template(
            'conductor/detail.html',
            stages=stages, actions=actions, active_tab=active_tab,
            note_form=note_form, update_form=update_form,
            opportunity_form=opportunity_form, metadata_form=metadata_form,
            complete_form=complete_form, contract=contract,
            current_user=current_user, active_stage=active_stage,
            current_stage=current_stage, flows=flows, subscribers=subscribers,
            total_subscribers=total_subscribers,
            current_stage_enter=localize_datetime(current_stage.entered),
            categories=opportunity_form.get_categories(),
            subcategories=opportunity_form.get_subcategories()
        )
    abort(404)
def transition(contract_id, stage_id):
    '''Transition a contract from one date to the next date

    :param contract_id: Primary key ID for a
        :py:class:`~purchasing.data.contracts.ContractBase`
    :param stage_id: Primary key ID for a
        :py:class:`~purchasing.data.contract_stages.ContractStage`

    .. seealso::
        For the transition, see the
        :py:meth:`~purchasing.data.contracts.ContractBase.transition`
        method directly

    :status 302: Perform the transition, and redirect back to the detail view
        with either the new stage or the appropriate error message
    :status 404: Contract not found
    '''
    contract = ContractBase.query.get(contract_id)
    stage = ContractStage.query.filter(ContractStage.id == stage_id).first()
    complete_form = CompleteForm(started=stage.entered)

    if (request.method == 'POST' and complete_form.validate_on_submit()) or (request.method == 'GET'):
        if request.method == 'POST':
            completed_time = current_app.config['DISPLAY_TIMEZONE'].localize(
                complete_form.complete.data
            ).astimezone(pytz.UTC).replace(tzinfo=None)
        else:
            completed_time = datetime.datetime.utcnow()

        if not contract:
            abort(404)

        clicked = int(request.args.get('destination')) if \
            request.args.get('destination') else None

        try:
            actions = contract.transition(
                current_user, destination=clicked,
                complete_time=completed_time
            )

            for action in actions:
                db.session.add(action)
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            pass
        except Exception:
            db.session.rollback()
            raise

        current_app.logger.info(
            'CONDUCTOR TRANSITION - Contract for {} (ID: {}) transition to {}'.format(
                contract.description, contract.id, contract.current_stage.name
            )
        )

        if contract.completed_last_stage():
            url = url_for('conductor.edit', contract_id=contract.id)
        else:
            url = url_for('conductor.detail', contract_id=contract.id)

        return redirect(url)

    session['invalid_date-{}'.format(contract_id)] = complete_form.errors['complete'][0]
    return redirect(url_for('conductor.detail', contract_id=contract.id))