mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-20 22:40:31 -04:00
Merge pull request #3019 from alphagov/sign-online
Allow online acceptance of the contract/memorandum of understanding
This commit is contained in:
@@ -110,3 +110,9 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.conditional-radio-panel {
|
||||
border-left: 4px solid $border-colour;
|
||||
margin: -20px 0 0 17px;
|
||||
padding: 10px 0 0 28px;
|
||||
}
|
||||
|
||||
@@ -1462,3 +1462,68 @@ class GoLiveNotesForm(StripWhitespaceForm):
|
||||
'Go live notes',
|
||||
filters=[lambda x: x or None],
|
||||
)
|
||||
|
||||
|
||||
class AcceptAgreementForm(StripWhitespaceForm):
|
||||
|
||||
@classmethod
|
||||
def from_organisation(cls, org):
|
||||
|
||||
if org.agreement_signed_on_behalf_of_name and org.agreement_signed_on_behalf_of_email_address:
|
||||
who = 'someone-else'
|
||||
elif org.agreement_signed_version: # only set if user has submitted form previously
|
||||
who = 'me'
|
||||
else:
|
||||
who = None
|
||||
|
||||
return cls(
|
||||
version=org.agreement_signed_version,
|
||||
who=who,
|
||||
on_behalf_of_name=org.agreement_signed_on_behalf_of_name,
|
||||
on_behalf_of_email=org.agreement_signed_on_behalf_of_email_address,
|
||||
)
|
||||
|
||||
version = StringField(
|
||||
'Which version of the agreement are you accepting?'
|
||||
)
|
||||
|
||||
who = RadioField(
|
||||
'Who is accepting the agreement?',
|
||||
choices=(
|
||||
(
|
||||
'me',
|
||||
'I’m accepting the agreement',
|
||||
),
|
||||
(
|
||||
'someone-else',
|
||||
'I’m accepting the agreement on behalf of someone else',
|
||||
),
|
||||
),
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
on_behalf_of_name = StringField(
|
||||
'Who are you accepting the agreement on behalf of?'
|
||||
)
|
||||
|
||||
on_behalf_of_email = email_address(
|
||||
'What’s their email address?',
|
||||
required=False,
|
||||
gov_user=False,
|
||||
)
|
||||
|
||||
def __validate_if_nominating(self, field):
|
||||
if self.who.data == 'someone-else':
|
||||
if not field.data:
|
||||
raise ValidationError('Can’t be empty')
|
||||
else:
|
||||
field.data = ''
|
||||
|
||||
validate_on_behalf_of_name = __validate_if_nominating
|
||||
validate_on_behalf_of_email = __validate_if_nominating
|
||||
|
||||
def validate_version(self, field):
|
||||
try:
|
||||
float(field.data)
|
||||
except (TypeError, ValueError):
|
||||
raise ValidationError("Must be a number")
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
from flask import abort, render_template, request, send_file, url_for
|
||||
from datetime import datetime
|
||||
|
||||
from flask import abort, redirect, render_template, request, send_file, url_for
|
||||
from flask_login import current_user, login_required
|
||||
|
||||
from app import current_service
|
||||
from app.main import main
|
||||
from app.main.forms import AcceptAgreementForm
|
||||
from app.main.views.sub_navigation_dictionaries import features_nav
|
||||
from app.s3_client.s3_mou_client import get_mou
|
||||
|
||||
@@ -26,6 +29,50 @@ def service_agreement(service_id):
|
||||
)
|
||||
|
||||
|
||||
@main.route('/services/<uuid:service_id>/agreement/accept', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def service_accept_agreement(service_id):
|
||||
|
||||
if not current_service.organisation:
|
||||
abort(404)
|
||||
|
||||
form = AcceptAgreementForm.from_organisation(current_service.organisation)
|
||||
|
||||
if form.validate_on_submit():
|
||||
current_service.organisation.update(
|
||||
agreement_signed_version=float(form.version.data),
|
||||
agreement_signed_on_behalf_of_name=form.on_behalf_of_name.data,
|
||||
agreement_signed_on_behalf_of_email_address=form.on_behalf_of_email.data,
|
||||
)
|
||||
return redirect(url_for('main.service_confirm_agreement', service_id=current_service.id))
|
||||
|
||||
return render_template(
|
||||
'views/agreement/agreement-accept.html',
|
||||
form=form,
|
||||
)
|
||||
|
||||
|
||||
@main.route('/services/<uuid:service_id>/agreement/confirm', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def service_confirm_agreement(service_id):
|
||||
|
||||
if (
|
||||
not current_service.organisation
|
||||
or current_service.organisation.agreement_signed_version is None
|
||||
):
|
||||
abort(403)
|
||||
|
||||
if request.method == 'POST':
|
||||
current_service.organisation.update(
|
||||
agreement_signed=True,
|
||||
agreement_signed_at=str(datetime.utcnow()),
|
||||
agreement_signed_by_id=current_user.id,
|
||||
)
|
||||
return redirect(url_for('main.request_to_go_live', service_id=current_service.id))
|
||||
|
||||
return render_template('views/agreement/agreement-confirm.html')
|
||||
|
||||
|
||||
@main.route('/agreement.pdf')
|
||||
@login_required
|
||||
def download_agreement():
|
||||
|
||||
@@ -19,6 +19,8 @@ class Organisation(JSONModel):
|
||||
'agreement_signed_at',
|
||||
'agreement_signed_by_id',
|
||||
'agreement_signed_version',
|
||||
'agreement_signed_on_behalf_of_name',
|
||||
'agreement_signed_on_behalf_of_email_address',
|
||||
'domains',
|
||||
'request_to_go_live_notes',
|
||||
'count_of_live_services',
|
||||
@@ -156,6 +158,10 @@ class Organisation(JSONModel):
|
||||
key=lambda user: user.email_address.lower(),
|
||||
)
|
||||
|
||||
def update(self, **kwargs):
|
||||
response = organisations_client.update_organisation(self.id, **kwargs)
|
||||
self.__init__(response)
|
||||
|
||||
|
||||
class Organisations(ModelList):
|
||||
client = organisations_client.get_organisations
|
||||
|
||||
@@ -244,6 +244,8 @@ class HeaderNavigation(Navigation):
|
||||
'service_add_letter_contact',
|
||||
'service_add_sms_sender',
|
||||
'service_agreement',
|
||||
'service_accept_agreement',
|
||||
'service_confirm_agreement',
|
||||
'service_confirm_delete_email_reply_to',
|
||||
'service_confirm_delete_sms_sender',
|
||||
'service_dashboard',
|
||||
@@ -377,6 +379,8 @@ class MainNavigation(Navigation):
|
||||
'service_add_letter_contact',
|
||||
'service_add_sms_sender',
|
||||
'service_agreement',
|
||||
'service_accept_agreement',
|
||||
'service_confirm_agreement',
|
||||
'service_confirm_delete_email_reply_to',
|
||||
'service_confirm_delete_sms_sender',
|
||||
'service_edit_email_reply_to',
|
||||
@@ -765,6 +769,8 @@ class CaseworkNavigation(Navigation):
|
||||
'service_add_letter_contact',
|
||||
'service_add_sms_sender',
|
||||
'service_agreement',
|
||||
'service_accept_agreement',
|
||||
'service_confirm_agreement',
|
||||
'service_confirm_delete_email_reply_to',
|
||||
'service_confirm_delete_sms_sender',
|
||||
'service_dashboard',
|
||||
@@ -1034,6 +1040,8 @@ class OrgNavigation(Navigation):
|
||||
'service_add_letter_contact',
|
||||
'service_add_sms_sender',
|
||||
'service_agreement',
|
||||
'service_accept_agreement',
|
||||
'service_confirm_agreement',
|
||||
'service_confirm_delete_email_reply_to',
|
||||
'service_confirm_delete_sms_sender',
|
||||
'service_dashboard',
|
||||
|
||||
@@ -1,35 +1,12 @@
|
||||
<p>
|
||||
Before you can go live on GOV.UK Notify, your organisation needs to agree to our data sharing and financial agreement.
|
||||
Before you can go live on GOV.UK Notify, your organisation needs to
|
||||
accept to our data sharing and financial agreement.
|
||||
</p>
|
||||
<h2 class="heading-small">
|
||||
Crown bodies
|
||||
</h2>
|
||||
<p>
|
||||
Download the <a href="{{ url_for('main.public_download_agreement', variant='crown') }}">crown agreement</a>.
|
||||
There are different agreements for crown and non-crown organisations.
|
||||
</p>
|
||||
<h2 class="heading-small">
|
||||
Non-crown bodies
|
||||
</h2>
|
||||
<p>
|
||||
Download the <a href="{{ url_for('main.public_download_agreement', variant='non-crown') }}">non-crown agreement</a>.
|
||||
</p>
|
||||
<div class="panel panel-border-wide">
|
||||
<p>
|
||||
<a href="{{ url_for('main.support') }}">Contact us</a> if you’re
|
||||
not sure whether your organisation is a crown or non-crown body.
|
||||
</p>
|
||||
</div>
|
||||
<h2 class="heading-small">
|
||||
Next steps
|
||||
</h2>
|
||||
<ol class="list list-number">
|
||||
<li>
|
||||
Get the agreement signed by someone who has the authority to do so on behalf of {{ owner or 'your organisation' }}.
|
||||
</li>
|
||||
<li>
|
||||
Return the signed copy to <a href="mailto:notify-support@digital.cabinet-office.gov.uk">notify-support@digital.cabinet-office.gov.uk</a>.
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
The agreement contains commercially sensitive information, so don’t share it more widely than you need to.
|
||||
<a href="{{ url_for('main.support') }}">Get in touch</a> to tell us
|
||||
whether or not you work for a crown organisation. If you’re not sure
|
||||
we’ll help you work it out.
|
||||
</p>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<p>
|
||||
Before you can go live on GOV.UK Notify, your organisation needs to agree to our data sharing and financial agreement.
|
||||
To use GOV.UK Notify your organisation (Cabinet Office) must accept the GOV.UK Notify data sharing and financial agreement.
|
||||
</p>
|
||||
<p>
|
||||
This agreement only needs to be accepted once and will then cover all Notify services from
|
||||
{{ current_service.organisation.name }}.
|
||||
</p>
|
||||
<p>
|
||||
It needs to be accepted by, or on behalf of someone who can sign contracts for your organisation.
|
||||
</p>
|
||||
<p>
|
||||
<a href="{{ url_for('main.download_agreement') }}">Download a copy of the agreement</a>.
|
||||
</p>
|
||||
<ol class="list list-number">
|
||||
<li>
|
||||
<a href="{{ url_for('main.download_agreement') }}">Download the agreement</a>.
|
||||
</li>
|
||||
<li>
|
||||
Get it signed by someone who has the authority to do so on behalf of {{ owner }}.
|
||||
</li>
|
||||
<li>
|
||||
Return the signed copy to <a href="mailto:notify-support@digital.cabinet-office.gov.uk">notify-support@digital.cabinet-office.gov.uk</a>.
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
The agreement contains commercially sensitive information, so don’t share it more widely than you need to.
|
||||
</p>
|
||||
<a href="{{ url_for('main.service_accept_agreement', service_id=current_service.id) }}" class="button">Continue</a>
|
||||
|
||||
42
app/templates/views/agreement/agreement-accept.html
Normal file
42
app/templates/views/agreement/agreement-accept.html
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/textbox.html" import textbox %}
|
||||
{% from "components/radios.html" import radio %}
|
||||
{% from "components/select-input.html" import select_wrapper %}
|
||||
{% from "components/form.html" import form_wrapper %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/page-header.html" import page_header %}
|
||||
|
||||
{% block per_page_title %}
|
||||
Accept data sharing and financial agreement
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<div class="grid-row">
|
||||
<div class="column-five-sixths">
|
||||
|
||||
{{ page_header(
|
||||
'Accept data sharing and financial agreement',
|
||||
back_link=url_for('main.service_agreement', service_id=current_service.id)
|
||||
) }}
|
||||
|
||||
{% call form_wrapper(class='top-gutter') %}
|
||||
|
||||
{{ textbox(form.version, width='1-3', hint='The version number is on the front page, for example ‘3.6’') }}
|
||||
{% call select_wrapper(form.who) %}
|
||||
{% for option in form.who %}
|
||||
{{ radio(option, data_target='on-behalf-of' if option.data == 'someone-else' else None) }}
|
||||
{% endfor %}
|
||||
{% endcall %}
|
||||
<div class="conditional-radio-panel js-hidden" id="on-behalf-of">
|
||||
{{ textbox(form.on_behalf_of_name, width='1-1') }}
|
||||
{{ textbox(form.on_behalf_of_email, width='1-1') }}
|
||||
</div>
|
||||
{{ page_footer('Continue') }}
|
||||
|
||||
{% endcall %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
39
app/templates/views/agreement/agreement-confirm.html
Normal file
39
app/templates/views/agreement/agreement-confirm.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/form.html" import form_wrapper %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/page-header.html" import page_header %}
|
||||
|
||||
{% block per_page_title %}
|
||||
GOV.UK Notify data sharing and financial agreement
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<div class="grid-row">
|
||||
<div class="column-five-sixths">
|
||||
|
||||
{{ page_header(
|
||||
'GOV.UK Notify data sharing and financial agreement',
|
||||
back_link=url_for('main.service_accept_agreement', service_id=current_service.id)
|
||||
) }}
|
||||
|
||||
{% call form_wrapper(class='top-gutter') %}
|
||||
|
||||
{% if current_service.organisation.agreement_signed_on_behalf_of_name and current_service.organisation.agreement_signed_on_behalf_of_email_address %}
|
||||
<p>
|
||||
I confirm that I have the legal authority to accept the GOV.UK Notify data sharing and financial agreement (version {{ current_service.organisation.agreement_signed_version }}) on behalf of {{ current_service.organisation.agreement_signed_on_behalf_of_name }} ({{ current_service.organisation.agreement_signed_on_behalf_of_email_address }}) and that {{ current_service.organisation.name }} will be bound by it.
|
||||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
I confirm that I have the legal authority to accept the GOV.UK Notify data sharing and financial agreement (version {{ current_service.organisation.agreement_signed_version }}) and that {{ current_service.organisation.name }} will be bound by it.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{{ page_footer('Accept this agreement') }}
|
||||
|
||||
{% endcall %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -51,7 +51,7 @@
|
||||
{% if show_agreement %}
|
||||
{{ task_list_item(
|
||||
agreement_signed,
|
||||
'Sign our data sharing and financial agreement',
|
||||
'Accept our data sharing and financial agreement',
|
||||
url_for('main.service_agreement', service_id=current_service.id),
|
||||
) }}
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user