diff --git a/lemarche/templates/tenders/create_step_survey.html b/lemarche/templates/tenders/create_step_survey.html
index 18493200e..63d575f7a 100644
--- a/lemarche/templates/tenders/create_step_survey.html
+++ b/lemarche/templates/tenders/create_step_survey.html
@@ -29,7 +29,7 @@
- {% bootstrap_field form.le_marche_doesnt_exist_how_to_find_siae form_group_class="form-group" %}
+ {% bootstrap_field form.le_marche_doesnt_exist_how_to_find_siae form_group_class="form-group mb-lg-5" %}
diff --git a/lemarche/tenders/admin.py b/lemarche/tenders/admin.py
index 31472276b..50effb560 100644
--- a/lemarche/tenders/admin.py
+++ b/lemarche/tenders/admin.py
@@ -476,7 +476,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
),
(
"Utilité du marché de l'inclusion",
- {"fields": ("scale_marche_useless",)},
+ {"fields": ("scale_marche_useless", "le_marche_doesnt_exist_how_to_find_siae")},
),
(
"Status",
diff --git a/lemarche/tenders/constants.py b/lemarche/tenders/constants.py
index a8f1c3f5a..84768e9b1 100644
--- a/lemarche/tenders/constants.py
+++ b/lemarche/tenders/constants.py
@@ -167,19 +167,6 @@
(TENDER_SIAE_STATUS_DETAIL_NOT_INTERESTED_CLICK_DATE, TENDER_SIAE_STATUS_DETAIL_NOT_INTERESTED_CLICK_DATE_DISPLAY),
)
-
-SURVEY_SCALE_QUESTION_0 = "0"
-SURVEY_SCALE_QUESTION_1 = "1"
-SURVEY_SCALE_QUESTION_2 = "2"
-SURVEY_SCALE_QUESTION_3 = "3"
-
-SURVEY_SCALE_QUESTION_CHOICES = (
- (SURVEY_SCALE_QUESTION_0, "Non"),
- (SURVEY_SCALE_QUESTION_1, "Peu probablement"),
- (SURVEY_SCALE_QUESTION_2, "Très probablement"),
- (SURVEY_SCALE_QUESTION_3, "Oui"),
-)
-
# survey choices
SURVEY_YES_NO_DONT_KNOW_CHOICES = (
(constants.NO, "Non"),
diff --git a/lemarche/tenders/enums.py b/lemarche/tenders/enums.py
new file mode 100644
index 000000000..477eedd57
--- /dev/null
+++ b/lemarche/tenders/enums.py
@@ -0,0 +1,30 @@
+"""
+Enums fields used in Tender models.
+"""
+
+from django.db import models
+
+
+class SurveyScaleQuestionChoices(models.TextChoices):
+ NON = "0", "Non"
+ PEU_PROBABLE = "1", "Peu probablement"
+ TRES_PROBABLE = "2", "Très probablement"
+ OUI = "3", "Oui"
+
+
+class SurveyDoesNotExistQuestionChoices(models.TextChoices):
+ DONT_KNOW = "DK", "Je ne sais pas"
+ INTERNET_SEARCH = "IS", "Recherche sur Internet (Google, page jaune, recherche sur le web)"
+ NETWORKS = "NW", "Réseaux professionnels et partenariats"
+ DIRECTORY = "DI", "Annuaire spécialisé (GESAT, UNEA, Handeco)"
+ RECOMMENDATIONS = (
+ "RC",
+ "Recommandations et bouche-à-oreille (Réseaux sociaux, recommandations personnelles, collègues)",
+ )
+ KNOWN_PROVIDERS = "KP", "Prestataires connus et habituels (Fournisseurs actuels)"
+ PUBLIC_TENDERS = "PT", "Appel d'offres et consultations publiques (BOAMP, JOUE, AWS, appels d'offres)"
+ FACILITATORS = "FA", "Facilitateurs de clauses sociales"
+ LOCAL_SOURCING = (
+ "LS",
+ "Sourcing local et salons professionnels (Recherche locale, salons, événements professionnels)",
+ )
diff --git a/lemarche/tenders/migrations/0089_tender_le_marche_doesnt_exist_how_to_find_siae.py b/lemarche/tenders/migrations/0089_tender_le_marche_doesnt_exist_how_to_find_siae.py
new file mode 100644
index 000000000..389cc7e42
--- /dev/null
+++ b/lemarche/tenders/migrations/0089_tender_le_marche_doesnt_exist_how_to_find_siae.py
@@ -0,0 +1,45 @@
+# Generated by Django 4.2.13 on 2024-06-26 15:11
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("tenders", "0088_alter_tender_contact_phone"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="tender",
+ name="le_marche_doesnt_exist_how_to_find_siae",
+ field=models.CharField(
+ choices=[
+ ("DK", "Je ne sais pas"),
+ ("IS", "Recherche sur Internet (Google, page jaune, recherche sur le web)"),
+ ("NW", "Réseaux professionnels et partenariats"),
+ ("DI", "Annuaire spécialisé (GESAT, UNEA, Handeco)"),
+ (
+ "RC",
+ (
+ "Recommandations et bouche-à-oreille (Réseaux sociaux, "
+ "recommandations personnelles, collègues)"
+ ),
+ ),
+ ("KP", "Prestataires connus et habituels (Fournisseurs actuels)"),
+ ("PT", "Appel d'offres et consultations publiques (BOAMP, JOUE, AWS, appels d'offres)"),
+ ("FA", "Facilitateurs de clauses sociales"),
+ (
+ "LS",
+ (
+ "Sourcing local et salons professionnels (Recherche locale, "
+ "salons, événements professionnels)"
+ ),
+ ),
+ ],
+ default="DK",
+ help_text="Comment auriez-vous fait pour consulter des prestataires inclusifs ?",
+ max_length=2,
+ verbose_name="Sans le marché de l'inclusion",
+ ),
+ ),
+ ]
diff --git a/lemarche/tenders/models.py b/lemarche/tenders/models.py
index 2965c112c..fae6bd95d 100644
--- a/lemarche/tenders/models.py
+++ b/lemarche/tenders/models.py
@@ -32,6 +32,7 @@
from lemarche.siaes import constants as siae_constants
from lemarche.siaes.models import Siae
from lemarche.tenders import constants as tender_constants
+from lemarche.tenders.enums import SurveyDoesNotExistQuestionChoices, SurveyScaleQuestionChoices
from lemarche.tenders.utils import find_amount_ranges
from lemarche.users.models import User
from lemarche.utils.apis import api_elasticsearch
@@ -528,8 +529,15 @@ class Tender(models.Model):
verbose_name="Utilité du marché de l'inclusion",
help_text="Si le Marché de l'inclusion n'existait pas, auriez-vous consulté des prestataires inclusifs* pour ce besoin ?", # noqa
max_length=2,
- choices=tender_constants.SURVEY_SCALE_QUESTION_CHOICES,
- default=tender_constants.SURVEY_SCALE_QUESTION_0,
+ choices=SurveyScaleQuestionChoices.choices,
+ default=SurveyScaleQuestionChoices.NON,
+ )
+ le_marche_doesnt_exist_how_to_find_siae = models.CharField(
+ verbose_name="Sans le marché de l'inclusion",
+ help_text="Comment auriez-vous fait pour consulter des prestataires inclusifs ?",
+ max_length=2,
+ choices=SurveyDoesNotExistQuestionChoices.choices,
+ default=SurveyDoesNotExistQuestionChoices.DONT_KNOW,
)
marche_benefits = ChoiceArrayField(
diff --git a/lemarche/www/pages/views.py b/lemarche/www/pages/views.py
index 9c4edb61b..29f01a3cb 100644
--- a/lemarche/www/pages/views.py
+++ b/lemarche/www/pages/views.py
@@ -295,7 +295,6 @@ def csrf_failure(request, reason=""): # noqa C901
)
tender_published_at = None if request.POST.get("is_draft") else timezone.now()
tender_dict = dict(
- extra_data={},
status=tender_status,
published_at=tender_published_at,
source=tender_constants.SOURCE_FORM_CSRF,
@@ -308,17 +307,13 @@ def csrf_failure(request, reason=""): # noqa C901
if not key.startswith(("csrfmiddlewaretoken", "tender_create_multi_step_view")):
value = formtools_session_step_data.get(step).get(key)
key_cleaned = key.replace(f"{step}-", "")
- if key_cleaned == "le_marche_doesnt_exist_how_to_find_siae":
- tender_dict["extra_data"] |= {key_cleaned: value[0]}
- elif key_cleaned == "location":
+ if key_cleaned == "location":
tender_dict[key_cleaned] = Perimeter.objects.get(slug=value[0])
-
elif key_cleaned in [
"is_country_area",
"accept_share_amount",
]:
tender_dict[key_cleaned] = value[0] == "on"
-
elif key_cleaned == "sectors":
tender_dict[key_cleaned] = Sector.objects.filter(slug__in=value)
elif key_cleaned == "questions_list" and value:
diff --git a/lemarche/www/tenders/forms.py b/lemarche/www/tenders/forms.py
index e0afd9ba3..2effa8ded 100644
--- a/lemarche/www/tenders/forms.py
+++ b/lemarche/www/tenders/forms.py
@@ -5,6 +5,7 @@
from lemarche.sectors.models import Sector
from lemarche.tenders import constants as tender_constants
+from lemarche.tenders.enums import SurveyDoesNotExistQuestionChoices, SurveyScaleQuestionChoices
from lemarche.tenders.models import Tender, TenderSiae
from lemarche.users.models import User
from lemarche.utils import constants
@@ -257,15 +258,15 @@ def clean(self):
class TenderCreateStepSurveyForm(forms.ModelForm):
scale_marche_useless = forms.ChoiceField(
label=Tender._meta.get_field("scale_marche_useless").help_text,
- choices=tender_constants.SURVEY_SCALE_QUESTION_CHOICES,
+ choices=SurveyScaleQuestionChoices.choices,
widget=forms.RadioSelect,
required=True,
)
- le_marche_doesnt_exist_how_to_find_siae = forms.CharField(
- label="Si le Marché de l'inclusion n'existait pas, comment auriez-vous fait pour trouver un prestataire inclusif ?", # noqa
+ le_marche_doesnt_exist_how_to_find_siae = forms.ChoiceField(
+ label=Tender._meta.get_field("le_marche_doesnt_exist_how_to_find_siae").help_text,
+ choices=SurveyDoesNotExistQuestionChoices.choices,
required=False,
- widget=forms.Textarea(attrs={"rows": 2, "cols": 15, "data-expandable": "true"}),
)
class Meta:
@@ -276,23 +277,9 @@ class Meta:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- if self.instance.id:
- self.initial["le_marche_doesnt_exist_how_to_find_siae"] = self.instance.extra_data.get(
- "le_marche_doesnt_exist_how_to_find_siae"
- )
- else:
+ if not self.instance.id:
self.initial["scale_marche_useless"] = None
- def clean(self) -> dict[str, any]:
- if not self.errors:
- super_cleaned_data = super().clean()
- if super_cleaned_data:
- cleaned_data = {
- "scale_marche_useless": super_cleaned_data.pop("scale_marche_useless"),
- "extra_data": super_cleaned_data,
- }
- return cleaned_data
-
class TenderCreateStepConfirmationForm(forms.Form):
pass
diff --git a/lemarche/www/tenders/tests.py b/lemarche/www/tenders/tests.py
index 29152d7e0..4805d7dac 100644
--- a/lemarche/www/tenders/tests.py
+++ b/lemarche/www/tenders/tests.py
@@ -17,6 +17,7 @@
from lemarche.siaes.factories import SiaeFactory
from lemarche.siaes.models import Siae
from lemarche.tenders import constants as tender_constants
+from lemarche.tenders.enums import SurveyDoesNotExistQuestionChoices, SurveyScaleQuestionChoices
from lemarche.tenders.factories import TenderFactory, TenderQuestionFactory
from lemarche.tenders.models import Tender, TenderSiae, TenderStepsData
from lemarche.users.factories import UserFactory
@@ -67,8 +68,8 @@ def _generate_fake_data_form(
} | _step_3
step_4 = {
"tender_create_multi_step_view-current_step": "survey",
- "survey-scale_marche_useless": tender_constants.SURVEY_SCALE_QUESTION_0,
- "survey-le_marche_doesnt_exist_how_to_find_siae": "TEST",
+ "survey-scale_marche_useless": SurveyScaleQuestionChoices.NON,
+ "survey-le_marche_doesnt_exist_how_to_find_siae": SurveyDoesNotExistQuestionChoices.INTERNET_SEARCH,
} | _step_4
step_5 = {
@@ -134,6 +135,11 @@ def test_tender_wizard_form_all_good_authenticated(self):
self.assertEqual(tender.contact_last_name, self.user_buyer.last_name)
self.assertEqual(tender.contact_email, self.user_buyer.email)
self.assertEqual(tender.contact_phone_display, self.user_buyer.phone_display)
+ self.assertEqual(tender.scale_marche_useless, tenders_step_data[3].get("survey-scale_marche_useless"))
+ self.assertEqual(
+ tender.le_marche_doesnt_exist_how_to_find_siae,
+ tenders_step_data[3].get("survey-le_marche_doesnt_exist_how_to_find_siae"),
+ )
def test_tender_wizard_form_not_created(self):
self.client.force_login(self.user_buyer)
@@ -1516,7 +1522,7 @@ def test_user_can_notify_cocontracting_wish_with_authenticated_user(self):
self.assertContains(response, self.cta_message_success)
mock_send_mail_async.assert_called_once()
email_body = mock_send_mail_async.call_args[1]["email_body"]
- self.assertTrue(f"La structure {self.siae.name } souhaite répondre en co-traitance" in email_body)
+ self.assertTrue(f"La structure {self.siae.name} souhaite répondre en co-traitance" in email_body)
self.assertIsNotNone(tendersiae.detail_cocontracting_click_date)
response = self.client.get(self.tender_detail_url)
self.assertNotContains(response, self.cta_message)
diff --git a/lemarche/www/tenders/views.py b/lemarche/www/tenders/views.py
index 9557418ce..fa0d5acc0 100644
--- a/lemarche/www/tenders/views.py
+++ b/lemarche/www/tenders/views.py
@@ -196,25 +196,21 @@ def save_instance_tender(self, tender_dict: dict, form_dict: dict, is_draft: boo
sectors = None
for step, model_form in form_dict.items():
if model_form.has_changed():
- if step != self.STEP_SURVEY:
- for attribute in model_form.changed_data:
- match attribute:
- case "sectors":
- sectors = tender_dict.get("sectors", None)
- self.instance.sectors.set(sectors)
- case "location":
- location = tender_dict.get("location")
- self.instance.location = location
- self.instance.perimeters.set([location])
- case "questions_list":
- update_or_create_questions_list(
- tender=self.instance, questions_list=tender_dict.get("questions_list")
- )
- case _:
- setattr(self.instance, attribute, tender_dict.get(attribute))
- elif step == self.STEP_SURVEY:
- setattr(self.instance, "scale_marche_useless", tender_dict.get("scale_marche_useless"))
- self.instance.extra_data.update(tender_dict.get("extra_data"))
+ for attribute in model_form.changed_data:
+ match attribute:
+ case "sectors":
+ sectors = tender_dict.get("sectors", None)
+ self.instance.sectors.set(sectors)
+ case "location":
+ location = tender_dict.get("location")
+ self.instance.location = location
+ self.instance.perimeters.set([location])
+ case "questions_list":
+ update_or_create_questions_list(
+ tender=self.instance, questions_list=tender_dict.get("questions_list")
+ )
+ case _:
+ setattr(self.instance, attribute, tender_dict.get(attribute))
self.instance.save()
else:
tender_dict |= {"status": tender_status, "published_at": tender_published_at}