Files
notifications-admin/app/models/organisation.py
Chris Hill-Scott eb3f9aad2a Add pages to let users accept the agreement online
At the moment, the process for accepting the data sharing and financial
agreement is:

1. download a pdf
* print it out
* get someone to sign it
* scan it
* email it back to us
* we rename the file and save it in Google Drive
* we then update the organisation to say the MOU is signed
* sometimes we also:
 * print it out and get it counter-signed
 * scan it again
 * email it back to the service

Let's not do that any more.

When the first service for an organisation that doesn't have the
agreement in place is in the process of going live, then they should
be able to accept the agreement online as part of the go live flow. This
commit adds the pages that let someone do that.

Where the checklist shows the agreement as **[not completed]** then
they can follow a link where they can download it (as happens now).
From here, they should then also be able to provide some info to accept
it. The info that we need is:

**Version** – because we version the agreements occasionally, we need to
know which version they are accepting.  It may not be the latest one if
they downloaded it a while ago and it took time to be signed off

**Who is accepting the agreement** – this will often be someone in the
finance team, and not necessarily a team member, so we should let the
person either accept as themselves, or on behalf of someone else. If
it's on behalf of someone else we need to the name and email address of
that person so we have that on record. Obvs if it's them accepting it
themselves, we have that already (so we just store their user ID and
not their name or email address).

We then replay the collected info back in a sort of legally
binding kind of way pulling in the organisation name too. The wording
we’re using is inspired by what GOV.UK Pay have. Then there’s a big
green button they can click to accept the agreement, which stores their
user ID and and timestamp.
2019-06-19 13:14:02 +01:00

169 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from flask import Markup, abort
from werkzeug.utils import cached_property
from app.models import JSONModel, ModelList
from app.notify_client.organisations_api_client import organisations_client
class Organisation(JSONModel):
ALLOWED_PROPERTIES = {
'id',
'name',
'active',
'crown',
'organisation_type',
'letter_branding_id',
'email_branding_id',
'agreement_signed',
'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',
}
@classmethod
def from_id(cls, org_id):
return cls(organisations_client.get_organisation(org_id))
@classmethod
def from_domain(cls, domain):
return cls(organisations_client.get_organisation_by_domain(domain))
@classmethod
def from_service(cls, service_id):
return cls(organisations_client.get_service_organisation(service_id))
def __init__(self, _dict):
super().__init__(_dict)
if self._dict == {}:
self.name = None
self.crown = None
self.agreement_signed = None
self.domains = []
self.organisation_type = None
self.request_to_go_live_notes = None
def as_human_readable(self, fallback_domain):
if self.agreement_signed:
agreement_statement = 'Yes, on behalf of {}.'.format(self.name)
elif self.name:
agreement_statement = '{} (organisation is {}, {}).'.format(
{
False: 'No',
None: 'Cant tell',
}.get(self.agreement_signed),
self.name,
{
True: 'a crown body',
False: 'a non-crown body',
None: 'crown status unknown',
}.get(self.crown),
)
else:
agreement_statement = 'Cant tell (domain is {}).'.format(fallback_domain)
if self.request_to_go_live_notes:
agreement_statement = agreement_statement + ' ' + self.request_to_go_live_notes
return agreement_statement
def as_info_for_branding_request(self, fallback_domain):
return self.name or 'Cant tell (domain is {})'.format(fallback_domain)
@property
def as_jinja_template(self):
if self.crown is None:
return 'agreement-choose'
if self.agreement_signed:
return 'agreement-signed'
return 'agreement'
def as_terms_of_use_paragraph(self, **kwargs):
return Markup(self._as_terms_of_use_paragraph(**kwargs))
def _as_terms_of_use_paragraph(self, terms_link, download_link, support_link, signed_in):
if not signed_in:
return ((
'{} <a href="{}">Sign in</a> to download a copy '
'or find out if one is already in place.'
).format(self._acceptance_required, terms_link))
if self.agreement_signed is None:
return ((
'{} <a href="{}">Download the agreement</a> or '
'<a href="{}">contact us</a> to find out if we already '
'have one in place with your organisation.'
).format(self._acceptance_required, download_link, support_link))
if self.agreement_signed is False:
return ((
'{} <a href="{}">Download a copy</a>.'
).format(self._acceptance_required, download_link))
return (
'Your organisation ({}) has already accepted the '
'GOV.UK&nbsp;Notify data sharing and financial '
'agreement.'.format(self.name)
)
@property
def _acceptance_required(self):
return (
'Your organisation {} must also accept our data sharing '
'and financial agreement.'.format(
'({})'.format(self.name) if self.name else '',
)
)
@property
def crown_status_or_404(self):
if self.crown is None:
abort(404)
return self.crown
@cached_property
def services(self):
return organisations_client.get_organisation_services(self.id)
@property
def live_services(self):
return [s for s in self.services if s['active'] and not s['restricted']]
@property
def trial_services(self):
return [s for s in self.services if not s['active'] or s['restricted']]
@cached_property
def invited_users(self):
from app.models.user import OrganisationInvitedUsers
return OrganisationInvitedUsers(self.id)
@cached_property
def active_users(self):
from app.models.user import OrganisationUsers
return OrganisationUsers(self.id)
@cached_property
def team_members(self):
return sorted(
self.invited_users + self.active_users,
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
model = Organisation