Skip to content

Commit

Permalink
Fonctionnalités "attestation de service public" et "labellisation fra…
Browse files Browse the repository at this point in the history
…nce services" #580
  • Loading branch information
tut-tuuut authored Mar 28, 2022
2 parents 9efb75f + cabd264 commit 9c492b4
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 60 deletions.
54 changes: 47 additions & 7 deletions aidants_connect_habilitation/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
BooleanField,
CharField,
ChoiceField,
FileField,
modelformset_factory,
)
from django.forms.formsets import MAX_NUM_FORM_COUNT, TOTAL_FORM_COUNT
Expand Down Expand Up @@ -96,14 +95,16 @@ class OrganisationRequestForm(PatchedErrorListForm):
},
)

partner_administration = CharField(
label="Renseignez l’administration avec laquelle vous travaillez",
is_private_org = BooleanField(
label=(
"Cochez cette case si vous faites cette demande pour une structure privée "
"(hors associations)"
),
required=False,
)

public_service_delegation_attestation = FileField(
label="Téléversez ici une attestation de délégation de service public",
help_text="Taille maximale : 2 Mo. Formats supportés : PDF, JPG, PNG.",
partner_administration = CharField(
label="Renseignez l’administration avec laquelle vous travaillez",
required=False,
)

Expand All @@ -125,6 +126,20 @@ def __init__(self, **kwargs):
"data-other-value": RequestOriginConstants.OTHER.value,
},
)
self.widget_attrs(
"is_private_org",
{
"data-action": "change->dynamic-form#onIsPrivateOrgChange",
"data-dynamic-form-target": "privateOrgInput",
},
)
self.widget_attrs(
"france_services_label",
{
"data-action": "change->dynamic-form#onFranceServicesChange",
"data-dynamic-form-target": "franceServicesInput",
},
)

def clean_type(self):
return OrganisationType.objects.get(pk=int(self.data["type"]))
Expand All @@ -142,6 +157,30 @@ def clean_type_other(self):

return self.data["type_other"]

def clean_partner_administration(self):
if not self.data.get("is_private_org", False):
return ""

if not self.data["partner_administration"]:
raise ValidationError(
"Vous avez indiqué que la structure est privée : merci de renseigner "
"votre administration partenaire."
)

return self.data["partner_administration"]

def clean_france_services_number(self):
if not self.data.get("france_services_label", False):
return ""

if not self.data["france_services_number"]:
raise ValidationError(
"Vous avez indiqué que la structure est labellisée France Services : "
"merci de renseigner son numéro d’immatriculation France Services."
)

return self.data["france_services_number"]

class Meta:
model = models.OrganisationRequest
fields = [
Expand All @@ -152,9 +191,10 @@ class Meta:
"address",
"zipcode",
"city",
"is_private_org",
"partner_administration",
"public_service_delegation_attestation",
"france_services_label",
"france_services_number",
"web_site",
"mission_description",
"avg_nb_demarches",
Expand Down
31 changes: 31 additions & 0 deletions aidants_connect_habilitation/migrations/0014_auto_20220324_1713.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 3.2.12 on 2022-03-24 16:13

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('aidants_connect_habilitation', '0013_auto_20220321_0941'),
]

operations = [
migrations.AddField(
model_name='organisationrequest',
name='france_services_number',
field=models.CharField(blank=True, default='', max_length=200, verbose_name='Numéro d’immatriculation France Services'),
),
migrations.AddField(
model_name='organisationrequest',
name='is_private_org',
field=models.BooleanField(default=False, verbose_name='Structure privée'),
),
migrations.AddConstraint(
model_name='organisationrequest',
constraint=models.CheckConstraint(check=models.Q(models.Q(('is_private_org', True), ('partner_administration__isnull_or_blank', False)), models.Q(('is_private_org', False), ('partner_administration__isnull_or_blank', True)), _connector='OR'), name='partner_administration_if_org_is_private'),
),
migrations.AddConstraint(
model_name='organisationrequest',
constraint=models.CheckConstraint(check=models.Q(models.Q(('france_services_label', True), ('france_services_number__isnull_or_blank', False)), models.Q(('france_services_label', False), ('france_services_number__isnull_or_blank', True)), _connector='OR'), name='immatriculation_number_if_france_services_label'),
),
]
34 changes: 33 additions & 1 deletion aidants_connect_habilitation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,13 @@ class OrganisationRequest(models.Model):
zipcode = models.CharField("Code Postal", max_length=10)
city = models.CharField("Ville", max_length=255, blank=True)

is_private_org = models.BooleanField("Structure privée", default=False)
partner_administration = models.CharField(
"Administration partenaire",
blank=True,
default="",
max_length=200,
)

public_service_delegation_attestation = models.FileField(
"Attestation de délégation de service public",
blank=True,
Expand All @@ -238,6 +238,12 @@ class OrganisationRequest(models.Model):
france_services_label = models.BooleanField(
"Labellisation France Services", default=False
)
france_services_number = models.CharField(
"Numéro d’immatriculation France Services",
blank=True,
default="",
max_length=200,
)

web_site = models.URLField("Site web", blank=True, default="")

Expand Down Expand Up @@ -289,6 +295,32 @@ class Meta:
),
name="type_other_correctly_set",
),
models.CheckConstraint(
check=(
(
Q(is_private_org=True)
& Q(partner_administration__isnull_or_blank=False)
)
| (
Q(is_private_org=False)
& Q(partner_administration__isnull_or_blank=True)
)
),
name="partner_administration_if_org_is_private",
),
models.CheckConstraint(
check=(
(
Q(france_services_label=True)
& Q(france_services_number__isnull_or_blank=False)
)
| (
Q(france_services_label=False)
& Q(france_services_number__isnull_or_blank=True)
)
),
name="immatriculation_number_if_france_services_label",
),
models.CheckConstraint(
check=Q(status=RequestStatusConstants.NEW.name)
| (~Q(status=RequestStatusConstants.NEW.name) & Q(cgu=True)),
Expand Down

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 19 additions & 1 deletion aidants_connect_habilitation/static/js/organisation_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,30 @@
Object.assign(DynamicForm.prototype, {
"connect": function connect() {
this.selectOrgType(this.typeInputTarget.value);
this.showHide(this.onlyShownIfPrivateOrgTarget, this.privateOrgInputTarget.checked);
this.showHide(this.onlyShownIfFranceServicesTarget, this.franceServicesInputTarget.checked);
},

"onTypeChange": function onTypeChange(evt) {
this.selectOrgType(evt.target.value);
},

"onIsPrivateOrgChange": function onIsPrivateOrgChange(evt) {
this.showHide(this.onlyShownIfPrivateOrgTarget, evt.target.checked);
},

"onFranceServicesChange": function truc(evt) {
this.showHide(this.onlyShownIfFranceServicesTarget, evt.target.checked)
},

"showHide": function showHide(element, show) {
if (show) {
element.removeAttribute("hidden");
} else {
element.setAttribute("hidden", "hidden");
}
},

"selectOrgType": function selectOrgType(value) {
if (value === this.typeInputTarget.dataset.otherValue) {
this.showTypeOtherInputContainer();
Expand All @@ -32,7 +50,7 @@
});

/* Static fields */
DynamicForm.targets = ["typeOtherInputContainer", "typeOtherInput", "typeInput"];
DynamicForm.targets = ["typeOtherInputContainer", "typeOtherInput", "typeInput", "onlyShownIfPrivateOrg", "privateOrgInput", "franceServicesInput", "onlyShownIfFranceServices"];

function init() {
const application = Stimulus.Application.start();
Expand Down
18 changes: 17 additions & 1 deletion aidants_connect_habilitation/static/scss/main-habilitation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,26 @@ fieldset {
transform: translateY(3rem);
}

.partner-administration {
.grey-background {
background: #f2f2f2;
padding: 1rem;
margin: 1rem 0;

&.shown-on-checkbox {
position: relative;

&::before {
position: absolute;
content: "";
width: 1.5rem;
height: 1.5rem;
background: #f2f2f2;
transform: rotate(45deg);
left: 0.2rem;
top: -.6rem;
border-radius: 0 0 100% 0;
}
}
}

.form-in-3-cols {
Expand Down
25 changes: 8 additions & 17 deletions aidants_connect_habilitation/templates/organisation_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@

<div class="fr-col-12 fr-col-md-8">
<form
method="post"
data-controller="dynamic-form"
data-dynamic-form-type-input-container-class="type-input-container"
method="post"
data-controller="dynamic-form"
data-dynamic-form-type-input-container-class="type-input-container"
>
<h2>Structure d’accueil</h2>
<p class="subtitle">Vous pouvez faire autant de demandes qu’il existe de structures d’accueil.</p>
<div class="shadowed">

<h3>Informations générales</h3>
{% csrf_token %}
{{ form.non_field_errors }}
Expand Down Expand Up @@ -57,20 +56,10 @@ <h3>Informations administratives</h3>

{% field_as_fr_grid_row form.siret %}

<div class="fr-grid-row fr-grid-row--gutters">
<div class="fr-col-12 checkbox-col">
<input id="is_private_org" type="checkbox">
<label for="is_private_org">
Cochez cette case si vous faites cette demande pour une structure privée<br>
(hors associations)
</label>
</div>
</div>

{% checkbox_fr_grid_row form.is_private_org %}

<section class="partner-administration">
<section class="grey-background shown-on-checkbox" data-dynamic-form-target="onlyShownIfPrivateOrg">
{% field_as_fr_grid_row form.partner_administration %}
{% field_as_fr_grid_row form.public_service_delegation_attestation %}
</section>

<h3>Informations descriptives</h3>
Expand All @@ -83,13 +72,15 @@ <h3>Autres caractéristiques de la structure</h3>

{% checkbox_fr_grid_row form.france_services_label %}

<section class="grey-background shown-on-checkbox" data-dynamic-form-target="onlyShownIfFranceServices">
{% field_as_fr_grid_row form.france_services_number %}
</section>
<div class="button-box">
<a class="button" href="{% url 'habilitation_modify_issuer' issuer_id=issuer.issuer_id %}">
Revenir à l’étape précédente
</a>
<button type="submit" class="primary">Valider cette étape</button>
</div>

</div>
</form>
</div>
Expand Down
6 changes: 1 addition & 5 deletions aidants_connect_habilitation/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,7 @@ class OrganisationRequestFactory(DjangoModelFactory):
zipcode = FactoryFaker("postcode")
city = FactoryFaker("city")

partner_administration = FactoryFaker("company")

public_service_delegation_attestation = ""

france_services_label = FuzzyChoice([True, False])
france_services_label = False

web_site = FactoryFaker("url")

Expand Down
58 changes: 58 additions & 0 deletions aidants_connect_habilitation/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,64 @@ def test_clean_type_other_unspecified_raises_error(self):
],
)

def test_private_org_requires_partner_administration(self):
form = get_form(
OrganisationRequestForm,
ignore_errors=True,
is_private_org=True,
partner_administration="",
)
self.assertFalse(form.is_valid())
self.assertIn("merci de renseigner", form.errors["partner_administration"][0])

def test_private_org_keeps_partner_administration(self):
form = get_form(
OrganisationRequestForm,
is_private_org=True,
partner_administration="Beta.Gouv",
)
self.assertTrue(form.is_valid())
self.assertEqual("Beta.Gouv", form.cleaned_data["partner_administration"])

def test_non_private_org_clears_partner_administration(self):
form = get_form(
OrganisationRequestForm,
is_private_org=False,
partner_administration="Beta.Gouv",
)
self.assertTrue(form.is_valid())
self.assertEqual("", form.cleaned_data["partner_administration"])

def test_france_services_label_requires_fs_number(self):
form = get_form(
OrganisationRequestForm,
france_services_label=True,
france_services_number=None,
ignore_errors=True,
)
self.assertFalse(form.is_valid())
self.assertIn(
"merci de renseigner son numéro", form.errors["france_services_number"][0]
)

def test_france_services_label_keeps_fs_number(self):
form = get_form(
OrganisationRequestForm,
france_services_label=True,
france_services_number=444666999,
)
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data["france_services_number"], 444666999)

def test_no_france_services_label_clears_fs_number(self):
form = get_form(
OrganisationRequestForm,
france_services_label=False,
france_services_number=444666999,
)
self.assertTrue(form.is_valid())
self.assertEqual("", form.cleaned_data["france_services_number"])


class TestPersonnelForm(TestCase):
@patch("aidants_connect_habilitation.forms.ManagerForm.is_valid")
Expand Down
Loading

0 comments on commit 9c492b4

Please sign in to comment.