mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-06-10 06:24:45 +02:00
Add Type of Work section for special districts/interstate orgs
This commit is contained in:
parent
f30b83f904
commit
8b76490794
8 changed files with 311 additions and 3 deletions
|
@ -27,6 +27,7 @@ for step, view in [
|
|||
(Step.ORGANIZATION_FEDERAL, views.OrganizationFederal),
|
||||
(Step.ORGANIZATION_ELECTION, views.OrganizationElection),
|
||||
(Step.ORGANIZATION_CONTACT, views.OrganizationContact),
|
||||
(Step.TYPE_OF_WORK, views.TypeOfWork),
|
||||
(Step.AUTHORIZING_OFFICIAL, views.AuthorizingOfficial),
|
||||
(Step.CURRENT_SITES, views.CurrentSites),
|
||||
(Step.DOTGOV_DOMAIN, views.DotgovDomain),
|
||||
|
|
|
@ -151,7 +151,7 @@ class OrganizationContactForm(RegistrarForm):
|
|||
raise forms.ValidationError(
|
||||
"Please select your federal agency.", code="required"
|
||||
)
|
||||
if self.application.is_federal:
|
||||
if self.application.is_federal():
|
||||
if not federal_agency:
|
||||
# no answer was selected
|
||||
raise forms.ValidationError(
|
||||
|
@ -160,6 +160,17 @@ class OrganizationContactForm(RegistrarForm):
|
|||
return federal_agency
|
||||
|
||||
|
||||
class TypeOfWorkForm(RegistrarForm):
|
||||
type_of_work = forms.CharField(
|
||||
label="What type of work does your organization do?", widget=forms.Textarea()
|
||||
)
|
||||
|
||||
more_organization_information = forms.CharField(
|
||||
label="Describe how your organization is a government organization that is independent of a state government. Include links to authorizing legislation, applicable bylaws or charter, or other documentation to support your claims.",
|
||||
widget=forms.Textarea(),
|
||||
)
|
||||
|
||||
|
||||
class AuthorizingOfficialForm(RegistrarForm):
|
||||
def to_database(self, obj):
|
||||
if not self.is_valid():
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
# Generated by Django 4.1.5 on 2023-01-10 20:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("registrar", "0006_alter_contact_phone"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="domainapplication",
|
||||
name="more_organization_information",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Further information about the government organization",
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="domainapplication",
|
||||
name="type_of_work",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="Type of work of the organization", null=True
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="address_line1",
|
||||
field=models.TextField(blank=True, help_text="Street address", null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="address_line2",
|
||||
field=models.CharField(
|
||||
blank=True, help_text="Street address line 2", max_length=15, null=True
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="federal_agency",
|
||||
field=models.TextField(blank=True, help_text="Federal agency", null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="federal_type",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("executive", "Executive"),
|
||||
("judicial", "Judicial"),
|
||||
("legislative", "Legislative"),
|
||||
],
|
||||
help_text="Federal government branch",
|
||||
max_length=50,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="organization_type",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
(
|
||||
"federal",
|
||||
"Federal: an agency of the U.S. government's executive, legislative, or judicial branches",
|
||||
),
|
||||
("interstate", "Interstate: an organization of two or more states"),
|
||||
(
|
||||
"state_or_territory",
|
||||
"State or territory: one of the 50 U.S. states, the District of Columbia, American Samoa, Guam, Northern Mariana Islands, Puerto Rico, or the U.S. Virgin Islands",
|
||||
),
|
||||
(
|
||||
"tribal",
|
||||
"Tribal: a tribal government recognized by the federal or a state government",
|
||||
),
|
||||
("county", "County: a county, parish, or borough"),
|
||||
("city", "City: a city, town, township, village, etc."),
|
||||
(
|
||||
"special_district",
|
||||
"Special district: an independent organization within a single state",
|
||||
),
|
||||
(
|
||||
"school_district",
|
||||
"School district: a school district that is not part of a local government",
|
||||
),
|
||||
],
|
||||
help_text="Type of Organization",
|
||||
max_length=255,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="purpose",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="Purpose of your domain", null=True
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="state_territory",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
help_text="State, territory, or military post",
|
||||
max_length=2,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="urbanization",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="Urbanization (Puerto Rico only)", null=True
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="domainapplication",
|
||||
name="zipcode",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
db_index=True,
|
||||
help_text="Zip code",
|
||||
max_length=10,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -350,6 +350,18 @@ class DomainApplication(TimeStampedModel):
|
|||
help_text="Urbanization (Puerto Rico only)",
|
||||
)
|
||||
|
||||
type_of_work = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Type of work of the organization",
|
||||
)
|
||||
|
||||
more_organization_information = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Further information about the government organization",
|
||||
)
|
||||
|
||||
authorizing_official = models.ForeignKey(
|
||||
"registrar.Contact",
|
||||
null=True,
|
||||
|
@ -474,6 +486,14 @@ class DomainApplication(TimeStampedModel):
|
|||
]
|
||||
return bool(user_choice and user_choice not in excluded)
|
||||
|
||||
def show_type_of_work(self) -> bool:
|
||||
"""Show this step if this is a special district or interstate."""
|
||||
user_choice = self.organization_type
|
||||
return user_choice in [
|
||||
DomainApplication.OrganizationChoices.SPECIAL_DISTRICT,
|
||||
DomainApplication.OrganizationChoices.INTERSTATE,
|
||||
]
|
||||
|
||||
def is_federal(self) -> Union[bool, None]:
|
||||
"""Is this application for a federal agency?
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
Incomplete
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if step == Step.TYPE_OF_WORK %}
|
||||
<p>{{ application.type_of_work|default:"Incomplete" }}</p>
|
||||
<p>{{ application.more_organization_information|default:"Incomplete" }}</p>
|
||||
{% endif %}
|
||||
{% if step == Step.AUTHORIZING_OFFICIAL %}
|
||||
{% if application.authorizing_official %}
|
||||
{% include "includes/contact.html" with contact=application.authorizing_official %}
|
||||
|
|
57
src/registrar/templates/application_type_of_work.html
Normal file
57
src/registrar/templates/application_type_of_work.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
<!-- Test page -->
|
||||
{% extends 'application_form.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block form_content %}
|
||||
|
||||
<form id="step__{{steps.current}}" class="usa-form usa-form--large" method="post" novalidate>
|
||||
<div class="usa-form-group">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="usa-character-count">
|
||||
{% with field=forms.0.type_of_work %}
|
||||
{% if field.errors %}
|
||||
<div class="usa-form-group usa-form-group--error">
|
||||
{{ field|add_label_class:"usa-label usa-label--error" }}
|
||||
{% for error in field.errors %}
|
||||
<span class="usa-error-message" id="input-error-message" role="alert">
|
||||
{{ error }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
{{ field|add_class:"usa-input--error usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500"|attr:"aria-invalid:true" }}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ field|add_label_class:"usa-label" }}
|
||||
{{ field|add_class:"usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500" }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<span class="usa-character-count__message" id="with-hint-textarea-info with-hint-textarea-hint"> You can enter up to 500 characters </span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="usa-form-group">
|
||||
<div class="usa-character-count">
|
||||
{% with field=forms.0.more_organization_information %}
|
||||
{% if field.errors %}
|
||||
<div class="usa-form-group usa-form-group--error">
|
||||
{{ field|add_label_class:"usa-label usa-label--error" }}
|
||||
{% for error in field.errors %}
|
||||
<span class="usa-error-message" id="input-error-message" role="alert">
|
||||
{{ error }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
{{ field|add_class:"usa-input--error usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500"|attr:"aria-invalid:true" }}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ field|add_label_class:"usa-label" }}
|
||||
{{ field|add_class:"usa-textarea usa-character-count__field"|attr:"aria-describedby:instructions"|attr:"maxlength=500" }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<span class="usa-character-count__message" id="with-hint-textarea-info with-hint-textarea-hint"> You can enter up to 500 characters </span>
|
||||
</div>
|
||||
</div>
|
||||
{{ block.super }}
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -8,7 +8,7 @@ from django.contrib.auth import get_user_model
|
|||
from django_webtest import WebTest # type: ignore
|
||||
|
||||
from registrar.models import DomainApplication, Domain, Contact, Website
|
||||
from registrar.views.application import ApplicationWizard
|
||||
from registrar.views.application import ApplicationWizard, Step
|
||||
|
||||
from .common import less_console_noise
|
||||
|
||||
|
@ -120,7 +120,7 @@ class DomainApplicationTests(TestWithUser, WebTest):
|
|||
this test work.
|
||||
"""
|
||||
num_pages_tested = 0
|
||||
SKIPPED_PAGES = 1 # elections
|
||||
SKIPPED_PAGES = 2 # elections, type_of_work
|
||||
num_pages = len(self.TITLES) - SKIPPED_PAGES
|
||||
|
||||
type_page = self.app.get(reverse("application:")).follow()
|
||||
|
@ -660,6 +660,82 @@ class DomainApplicationTests(TestWithUser, WebTest):
|
|||
0,
|
||||
)
|
||||
|
||||
def test_application_form_nonfederal(self):
|
||||
"""Non-federal organizations don't have to provide their federal agency."""
|
||||
type_page = self.app.get(reverse("application:")).follow()
|
||||
# django-webtest does not handle cookie-based sessions well because it keeps
|
||||
# resetting the session key on each new request, thus destroying the concept
|
||||
# of a "session". We are going to do it manually, saving the session ID here
|
||||
# and then setting the cookie on each request.
|
||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||
|
||||
type_form = type_page.form
|
||||
type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
type_result = type_page.form.submit()
|
||||
|
||||
# follow first redirect
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
contact_page = type_result.follow()
|
||||
org_contact_form = contact_page.form
|
||||
|
||||
self.assertNotIn("federal_agency", org_contact_form.fields)
|
||||
|
||||
# minimal fields that must be filled out
|
||||
org_contact_form["organization_contact-organization_name"] = "Testorg"
|
||||
org_contact_form["organization_contact-address_line1"] = "address 1"
|
||||
org_contact_form["organization_contact-city"] = "NYC"
|
||||
org_contact_form["organization_contact-state_territory"] = "NY"
|
||||
org_contact_form["organization_contact-zipcode"] = "10002"
|
||||
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
contact_result = org_contact_form.submit()
|
||||
|
||||
# the post request should return a redirect to the type of work page
|
||||
# if it was successful.
|
||||
self.assertEquals(contact_result.status_code, 302)
|
||||
self.assertEquals(contact_result["Location"], "/register/type_of_work/")
|
||||
|
||||
|
||||
def test_application_type_of_work_special(self):
|
||||
"""Special districts have to answer an additional question."""
|
||||
type_page = self.app.get(reverse("application:")).follow()
|
||||
# django-webtest does not handle cookie-based sessions well because it keeps
|
||||
# resetting the session key on each new request, thus destroying the concept
|
||||
# of a "session". We are going to do it manually, saving the session ID here
|
||||
# and then setting the cookie on each request.
|
||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||
|
||||
type_form = type_page.form
|
||||
type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.SPECIAL_DISTRICT
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
type_result = type_page.form.submit()
|
||||
# follow first redirect
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
contact_page = type_result.follow()
|
||||
|
||||
self.assertContains(contact_page, self.TITLES[Step.TYPE_OF_WORK])
|
||||
|
||||
def test_application_type_of_work_interstate(self):
|
||||
"""Special districts have to answer an additional question."""
|
||||
type_page = self.app.get(reverse("application:")).follow()
|
||||
# django-webtest does not handle cookie-based sessions well because it keeps
|
||||
# resetting the session key on each new request, thus destroying the concept
|
||||
# of a "session". We are going to do it manually, saving the session ID here
|
||||
# and then setting the cookie on each request.
|
||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||
|
||||
type_form = type_page.form
|
||||
type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
type_result = type_page.form.submit()
|
||||
# follow first redirect
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
contact_page = type_result.follow()
|
||||
|
||||
self.assertContains(contact_page, self.TITLES[Step.TYPE_OF_WORK])
|
||||
|
||||
|
||||
@skip("WIP")
|
||||
def test_application_edit_restore(self):
|
||||
"""
|
||||
|
|
|
@ -27,6 +27,7 @@ class Step(StrEnum):
|
|||
ORGANIZATION_FEDERAL = "organization_federal"
|
||||
ORGANIZATION_ELECTION = "organization_election"
|
||||
ORGANIZATION_CONTACT = "organization_contact"
|
||||
TYPE_OF_WORK = "type_of_work"
|
||||
AUTHORIZING_OFFICIAL = "authorizing_official"
|
||||
CURRENT_SITES = "current_sites"
|
||||
DOTGOV_DOMAIN = "dotgov_domain"
|
||||
|
@ -70,6 +71,7 @@ class ApplicationWizard(LoginRequiredMixin, TemplateView):
|
|||
Step.ORGANIZATION_FEDERAL: _("Type of organization — Federal"),
|
||||
Step.ORGANIZATION_ELECTION: _("Type of organization — Election board"),
|
||||
Step.ORGANIZATION_CONTACT: _("Organization name and mailing address"),
|
||||
Step.TYPE_OF_WORK: _("Type of Work"),
|
||||
Step.AUTHORIZING_OFFICIAL: _("Authorizing official"),
|
||||
Step.CURRENT_SITES: _("Organization website"),
|
||||
Step.DOTGOV_DOMAIN: _(".gov domain"),
|
||||
|
@ -93,6 +95,7 @@ class ApplicationWizard(LoginRequiredMixin, TemplateView):
|
|||
Step.ORGANIZATION_ELECTION: lambda w: w.from_model(
|
||||
"show_organization_election", False
|
||||
),
|
||||
Step.TYPE_OF_WORK: lambda w: w.from_model("show_type_of_work", False),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
|
@ -353,6 +356,11 @@ class OrganizationContact(ApplicationWizard):
|
|||
return context
|
||||
|
||||
|
||||
class TypeOfWork(ApplicationWizard):
|
||||
template_name = "application_type_of_work.html"
|
||||
forms = [forms.TypeOfWorkForm]
|
||||
|
||||
|
||||
class AuthorizingOfficial(ApplicationWizard):
|
||||
template_name = "application_authorizing_official.html"
|
||||
forms = [forms.AuthorizingOfficialForm]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue