Skip to content

Commit

Permalink
feat(Besoins): Sondage transaction : ajouter une option "Pas encore" (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
raphodn authored Apr 8, 2024
1 parent 84547bb commit bf8a23d
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 57 deletions.
69 changes: 38 additions & 31 deletions lemarche/tenders/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from lemarche.utils import constants


KIND_TENDER = "TENDER"
KIND_TENDER_DISPLAY = "Appel d'offres"
KIND_QUOTE = "QUOTE"
Expand Down Expand Up @@ -82,37 +85,6 @@
(WHY_AMOUNT_IS_BLANK_DONT_WANT_TO_SHARE, "Je ne souhaite pas communiquer le montant"),
)

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 for yes, no or don't know
SURVEY_NO = "0"
SURVEY_YES = "1"
SURVEY_DONT_KNOW = "?"

SURVEY_YES_NO_DONT_KNOW_CHOICES = (
(SURVEY_NO, "Non"),
(SURVEY_YES, "Oui"),
(SURVEY_DONT_KNOW, "Je ne sais pas"),
)


SURVEY_NOT_ENCOURAGED_ONLY_BY_US = "+"

SURVEY_ENCOURAGED_BY_US_CHOICES = (
(SURVEY_NO, "Non"),
(SURVEY_NOT_ENCOURAGED_ONLY_BY_US, "Un outil parmi d'autres"),
(SURVEY_YES, "Oui"),
)

STATUS_DRAFT = "DRAFT"
STATUS_PUBLISHED = "PUBLISHED"
Expand Down Expand Up @@ -194,3 +166,38 @@
(TENDER_SIAE_STATUS_DETAIL_CONTACT_CLICK_DATE, TENDER_SIAE_STATUS_DETAIL_CONTACT_CLICK_DATE_DISPLAY),
(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"),
(constants.YES, "Oui"),
(constants.DONT_KNOW, "Je ne sais pas"),
)

SURVEY_NOT_ENCOURAGED_ONLY_BY_US = "+"

SURVEY_ENCOURAGED_BY_US_CHOICES = (
(constants.NO, "Non"),
(SURVEY_NOT_ENCOURAGED_ONLY_BY_US, "Un outil parmi d'autres"),
(constants.YES, "Oui"),
)

SURVEY_TRANSACTIONED_ANSWER_CHOICES = (
(constants.YES, "Oui"),
(constants.NO, "Non"),
(constants.DONT_KNOW, "Pas encore"),
)
SURVEY_TRANSACTIONED_ANSWER_CHOICE_LIST = [choice[0] for choice in SURVEY_TRANSACTIONED_ANSWER_CHOICES]
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 4.2.9 on 2024-04-08 08:12

from django.db import migrations, models


def transform_boolean_to_char(apps, schema_editor):
Tender = apps.get_model("tenders", "Tender")
for obj in Tender.objects.all():
if obj.survey_transactioned_answer in [True, "true"]:
obj.survey_transactioned_answer = "1"
elif obj.survey_transactioned_answer in [False, "false"]:
obj.survey_transactioned_answer = "0"
obj.save()


class Migration(migrations.Migration):
dependencies = [
("tenders", "0083_tendersiae_user"),
]

operations = [
migrations.AlterField(
model_name="tender",
name="survey_transactioned_answer",
field=models.CharField(
blank=True,
choices=[("1", "Oui"), ("0", "Non"), ("?", "Pas encore")],
null=True,
verbose_name="Sondage transaction : réponse",
),
),
migrations.RunPython(transform_boolean_to_char),
]
7 changes: 5 additions & 2 deletions lemarche/tenders/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,11 @@ class Tender(models.Model):
survey_transactioned_send_date = models.DateTimeField(
verbose_name="Sondage transaction : date d'envoi de l'e-mail", blank=True, null=True
)
survey_transactioned_answer = models.BooleanField(
verbose_name="Sondage transaction : réponse", blank=True, null=True
survey_transactioned_answer = models.CharField(
verbose_name="Sondage transaction : réponse",
blank=True,
null=True,
choices=tender_constants.SURVEY_TRANSACTIONED_ANSWER_CHOICES,
)
survey_transactioned_amount = models.PositiveIntegerField(
verbose_name="Sondage transaction : montant du besoin", blank=True, null=True
Expand Down
11 changes: 11 additions & 0 deletions lemarche/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@

EMPTY_CHOICE = (("", ""),)

YES = "1"
NO = "0"
YES_NO_CHOICE_LIST = [YES, NO]
YES_NO_MAPPING = {YES: True, NO: False}
DONT_KNOW = "?"

TRUE_VALUES = ["true", "True", "TRUE", NO, 1, True, "Oui", "oui", "OUI"]
FALSE_VALUES = ["false", "False", "FALSE", YES, 0, False, "Non", "non", "NON"]
FALSE_OR_DONT_KNOW_VALUES = FALSE_VALUES + [DONT_KNOW]


ADMIN_FIELD_HELP_TEXT = "Champ renseigné par un ADMIN"
AUTO_FIELD_HELP_TEXT = "Champ mis à jour automatiquement"
RECALCULATED_FIELD_HELP_TEXT = "Champ recalculé à intervalles réguliers"
Expand Down
5 changes: 3 additions & 2 deletions lemarche/www/tenders/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from lemarche.tenders import constants as tender_constants
from lemarche.tenders.models import Tender, TenderSiae
from lemarche.users.models import User
from lemarche.utils import constants
from lemarche.utils.fields import GroupedModelMultipleChoiceField


Expand Down Expand Up @@ -313,7 +314,7 @@ def __init__(self, tender_survey_transactioned_answer=None, *args, **kwargs):
)
if tender_survey_transactioned_answer is not None:
self.fields["survey_transactioned_answer"].disabled = True
if tender_survey_transactioned_answer is False:
if tender_survey_transactioned_answer in constants.FALSE_VALUES + [constants.DONT_KNOW]:
self.fields["survey_transactioned_amount"].widget = forms.HiddenInput()


Expand All @@ -338,7 +339,7 @@ def __init__(self, tender_survey_transactioned_answer=None, *args, **kwargs):
)
if tender_survey_transactioned_answer is not None:
self.fields["survey_transactioned_answer"].disabled = True
if tender_survey_transactioned_answer is False:
if tender_survey_transactioned_answer in constants.FALSE_VALUES:
self.fields["survey_transactioned_amount"].widget = forms.HiddenInput()


Expand Down
6 changes: 4 additions & 2 deletions lemarche/www/tenders/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from lemarche.siaes.models import Siae
from lemarche.tenders.models import PartnerShareTender, Tender, TenderSiae
from lemarche.users.models import User
from lemarche.utils import constants
from lemarche.utils.apis import api_hubspot, api_mailjet, api_slack
from lemarche.utils.data import date_to_string
from lemarche.utils.emails import send_mail_async, whitelist_recipient_list
Expand Down Expand Up @@ -546,8 +547,9 @@ def send_tenders_author_feedback_or_survey(tender: Tender, kind="feedback_30d"):
+ reverse("tenders:detail-survey-transactioned", args=[tender.slug])
+ user_sesame_query_string
)
variables["ANSWER_YES_URL"] = answer_url_with_sesame_token + "&answer=True"
variables["ANSWER_NO_URL"] = answer_url_with_sesame_token + "&answer=False"
variables["ANSWER_YES_URL"] = f"{answer_url_with_sesame_token}&answer={constants.YES}"
variables["ANSWER_NO_URL"] = f"{answer_url_with_sesame_token}&answer={constants.NO}"
variables["ANSWER_DONT_KNOW_URL"] = f"{answer_url_with_sesame_token}&answer={constants.DONT_KNOW}"
# add timestamp
tender.survey_transactioned_send_date = timezone.now()
else:
Expand Down
54 changes: 40 additions & 14 deletions lemarche/www/tenders/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from lemarche.tenders.models import Tender, TenderSiae, TenderStepsData
from lemarche.users.factories import UserFactory
from lemarche.users.models import User
from lemarche.utils import constants
from lemarche.www.tenders.views import TenderCreateMultiStepView


Expand Down Expand Up @@ -1883,12 +1884,12 @@ def test_update_tender_stats_on_tender_survey_transactioned_answer_true(self):
self.assertIsNone(t.siae_transactioned)
self.assertIsNone(t.siae_transactioned_source)
self.assertIsNone(t.siae_transactioned_last_updated)
# load with answer 'True': partial form
url = self.url + self.user_buyer_1_sesame_query_string + "&answer=True"
# load with answer True: partial form
url = f"{self.url}{self.user_buyer_1_sesame_query_string}&answer={constants.YES}"
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
t = Tender.objects.get(id=self.tender.id)
self.assertTrue(t.survey_transactioned_answer)
self.assertEqual(t.survey_transactioned_answer, constants.YES)
self.assertTrue(t.siae_transactioned)
self.assertEqual(
t.siae_transactioned_source,
Expand All @@ -1903,44 +1904,69 @@ def test_update_tender_stats_on_tender_survey_transactioned_answer_true(self):
t = Tender.objects.get(id=self.tender.id)
self.assertRedirects(response, reverse("tenders:detail", kwargs={"slug": self.tender.slug}))
self.assertContains(response, "Merci pour votre réponse")
self.assertTrue(t.survey_transactioned_answer)
self.assertEqual(t.survey_transactioned_answer, constants.YES)
self.assertEqual(t.survey_transactioned_amount, 1000)
# reload with answer, ignore changes and redirect
url = self.url + self.user_buyer_1_sesame_query_string + "&answer=False"
# reload with new answer, ignore changes and redirect
url = f"{self.url}{self.user_buyer_1_sesame_query_string}&answer={constants.NO}"
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200) # redirect
t = Tender.objects.get(id=self.tender.id)
self.assertRedirects(response, reverse("tenders:detail", kwargs={"slug": self.tender.slug}))
self.assertContains(response, "Votre réponse a déjà été prise en compte")
self.assertTrue(t.survey_transactioned_answer)
self.assertEqual(t.survey_transactioned_answer, constants.YES)
self.assertTrue(t.siae_transactioned)

def test_update_tender_stats_on_tender_survey_transactioned_answer_false(self):
# load with answer 'False': partial form
url = self.url + self.user_buyer_1_sesame_query_string + "&answer=False"
# load with answer False: partial form
url = f"{self.url}{self.user_buyer_1_sesame_query_string}&answer={constants.NO}"
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
t = Tender.objects.get(id=self.tender.id)
self.assertFalse(t.survey_transactioned_answer)
self.assertEqual(t.survey_transactioned_answer, constants.NO)
self.assertFalse(t.siae_transactioned)
# fill in form
response = self.client.post(url, data={"survey_transactioned_feedback": "Feedback"}, follow=True)
self.assertEqual(response.status_code, 200) # redirect
t = Tender.objects.get(id=self.tender.id)
self.assertRedirects(response, reverse("tenders:detail", kwargs={"slug": self.tender.slug}))
self.assertContains(response, "Merci pour votre réponse")
self.assertFalse(t.survey_transactioned_answer)
self.assertEqual(t.survey_transactioned_answer, constants.NO)
self.assertIsNone(t.survey_transactioned_amount)
# reload with answer, ignore changes
url = self.url + self.user_buyer_1_sesame_query_string + "&answer=True"
# reload with new answer, ignore changes
url = f"{self.url}{self.user_buyer_1_sesame_query_string}&answer={constants.YES}"
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200) # redirect
t = Tender.objects.get(id=self.tender.id)
self.assertRedirects(response, reverse("tenders:detail", kwargs={"slug": self.tender.slug}))
self.assertContains(response, "Votre réponse a déjà été prise en compte")
self.assertFalse(t.survey_transactioned_answer)
self.assertEqual(t.survey_transactioned_answer, constants.NO)
self.assertFalse(t.siae_transactioned)

def test_update_tender_stats_on_tender_survey_transactioned_answer_dont_know(self):
# load with answer ?: partial form
url = f"{self.url}{self.user_buyer_1_sesame_query_string}&answer={constants.DONT_KNOW}"
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
t = Tender.objects.get(id=self.tender.id)
self.assertEqual(t.survey_transactioned_answer, constants.DONT_KNOW)
self.assertIsNone(t.siae_transactioned)
# fill in form
response = self.client.post(url, data={"survey_transactioned_feedback": "Feedback"}, follow=True)
self.assertEqual(response.status_code, 200) # redirect
t = Tender.objects.get(id=self.tender.id)
self.assertRedirects(response, reverse("tenders:detail", kwargs={"slug": self.tender.slug}))
self.assertContains(response, "Merci pour votre réponse")
self.assertEqual(t.survey_transactioned_answer, constants.DONT_KNOW)
self.assertIsNone(t.survey_transactioned_amount)
# reload with new answer, update
url = f"{self.url}{self.user_buyer_1_sesame_query_string}&answer={constants.YES}"
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
t = Tender.objects.get(id=self.tender.id)
self.assertNotContains(response, "Votre réponse a déjà été prise en compte")
self.assertEqual(t.survey_transactioned_answer, constants.YES)
self.assertTrue(t.siae_transactioned)


class TenderDetailSiaeSurveyTransactionedViewTest(TestCase):
@classmethod
Expand Down
14 changes: 8 additions & 6 deletions lemarche/www/tenders/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from lemarche.tenders.models import Tender, TenderSiae, TenderStepsData
from lemarche.users import constants as user_constants
from lemarche.users.models import User
from lemarche.utils import constants
from lemarche.utils.data import get_choice
from lemarche.utils.mixins import (
SesameSiaeMemberRequiredMixin,
Expand Down Expand Up @@ -624,16 +625,17 @@ def get(self, request, *args, **kwargs):
self.object = self.get_object()
survey_transactioned_answer = request.GET.get("answer", None)
# first time answering
if self.object.survey_transactioned_answer is None:
if survey_transactioned_answer in ["True", "False"]:
# transform survey_transactioned_answer into bool
survey_transactioned_answer = survey_transactioned_answer == "True"
if self.object.survey_transactioned_answer in [None, constants.DONT_KNOW]:
if survey_transactioned_answer in tender_constants.SURVEY_TRANSACTIONED_ANSWER_CHOICE_LIST:
# update tender
self.object.survey_transactioned_answer = survey_transactioned_answer
self.object.survey_transactioned_answer_date = timezone.now()
if self.object.siae_transactioned is None:
self.object.siae_transactioned = survey_transactioned_answer
self.object.siae_transactioned_source = tender_constants.TENDER_SIAE_TRANSACTIONED_SOURCE_AUTHOR
if survey_transactioned_answer in constants.YES_NO_CHOICE_LIST:
self.object.siae_transactioned = constants.YES_NO_MAPPING[survey_transactioned_answer]
self.object.siae_transactioned_source = (
tender_constants.TENDER_SIAE_TRANSACTIONED_SOURCE_AUTHOR
)
self.object.save()
else:
pass
Expand Down

0 comments on commit bf8a23d

Please sign in to comment.