diff --git a/lemarche/templates/tenders/_list_item_buyer.html b/lemarche/templates/tenders/_list_item_buyer.html
index f00044066..9887e8407 100644
--- a/lemarche/templates/tenders/_list_item_buyer.html
+++ b/lemarche/templates/tenders/_list_item_buyer.html
@@ -9,15 +9,15 @@
{% if tender.deadline_date_is_outdated_annotated %}
Clôturé
{% endif %}
- {% if tender.status == tender.STATUS_DRAFT %}
+ {% if tender.is_draft %}
Brouillon
- {% elif tender.status == tender.STATUS_PUBLISHED %}
+ {% elif tender.is_pending_validation_or_validated %}
En cours de validation
- {% elif tender.status == tender.STATUS_VALIDATED %}
+ {% elif tender.is_sent %}
Envoyé
@@ -33,17 +33,17 @@
{{ tender.title }}
Créé le {{ tender.created_at|date }}
- {% if tender.status == tender.STATUS_VALIDATED %}
+ {% if tender.is_sent %}
- Publié le {{ tender.validated_at|date }}
+ Publié le {{ tender.sent_at|date }}
{% endif %}
- {% if tender.status == tender.STATUS_VALIDATED %}
+ {% if tender.is_sent %}
{% if tender.siae_detail_contact_click_since_last_seen_date_count_annotated %}
{{ tender.siae_detail_contact_click_since_last_seen_date_count_annotated }} nouveau{{ tender.siae_detail_contact_click_since_last_seen_date_count_annotated|pluralize:"x" }} prestataire{{ tender.siae_detail_contact_click_since_last_seen_date_count_annotated|pluralize }} intéressé{{ tender.siae_detail_contact_click_since_last_seen_date_count_annotated|pluralize }}
diff --git a/lemarche/templates/tenders/admin_change_form.html b/lemarche/templates/tenders/admin_change_form.html
index f683d26ab..f8f63ee8e 100644
--- a/lemarche/templates/tenders/admin_change_form.html
+++ b/lemarche/templates/tenders/admin_change_form.html
@@ -38,8 +38,11 @@
{% if original %}
{% if original.validated_at %}
-
Validé et envoyé le {{ original.validated_at }}
-
+
Validé le {{ original.validated_at }}.
+ {% if original.sent_at %}
+
Envoyé le {{ original.sent_at }}.
+
+ {% endif %}
{% else %}
{% endif %}
diff --git a/lemarche/templates/tenders/list.html b/lemarche/templates/tenders/list.html
index 540f7774f..0df3388e5 100644
--- a/lemarche/templates/tenders/list.html
+++ b/lemarche/templates/tenders/list.html
@@ -47,7 +47,7 @@
{{ page_title }}
{% url 'tenders:list' as TENDERS_LIST_URL %}
{% url 'tenders:list' status=tender_constants.STATUS_DRAFT as TENDERS_DRAFT_LIST_URL %}
{% url 'tenders:list' status=tender_constants.STATUS_PUBLISHED as TENDERS_PUBLISHED_LIST_URL %}
- {% url 'tenders:list' status=tender_constants.STATUS_VALIDATED as TENDERS_VALIDATED_LIST_URL %}
+ {% url 'tenders:list' status=tender_constants.STATUS_SENT as TENDERS_SENT_LIST_URL %}
{{ page_title }}
-
Envoyé
@@ -93,7 +93,7 @@ {{ page_title }}
{% if request.get_full_path == TENDERS_PUBLISHED_LIST_URL %}
Vous n'avez aucun besoin en cours de validation pour le moment.
{% endif %}
- {% if request.get_full_path == TENDERS_VALIDATED_LIST_URL %}
+ {% if request.get_full_path == TENDERS_SENT_LIST_URL %}
Vous n'avez aucun besoin d'envoyé pour le moment.
Contacter notre équipe en cas de problème avec un de vos dépôts de besoins en cours de validation.
diff --git a/lemarche/tenders/admin.py b/lemarche/tenders/admin.py
index 0b2027136..039431158 100644
--- a/lemarche/tenders/admin.py
+++ b/lemarche/tenders/admin.py
@@ -95,9 +95,9 @@ class TenderQuestionInline(admin.TabularInline):
extra = 0
-def update_and_send_tender_task(tender: Tender):
+def validate_and_send_tender_task(tender: Tender):
# 1) validate the tender
- tender.set_validated(with_save=True)
+ tender.set_validated_and_sent(with_save=True)
# 2) find the matching Siaes? done in Tender post_save signal
send_confirmation_published_email_to_author(tender, nb_matched_siaes=tender.siaes.count())
# 3) send the tender to all matching Siaes & Partners
@@ -123,7 +123,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
list_display = [
"id",
"status",
- "is_validate",
+ "is_validated_or_sent",
"title",
"user_with_link",
"kind",
@@ -138,6 +138,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
"siae_transactioned",
"created_at",
"validated_at",
+ "sent_at",
]
list_filter = [
@@ -174,6 +175,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
"survey_transactioned_feedback",
"survey_transactioned_answer_date",
"validated_at",
+ "sent_at",
"question_count_with_link",
"siae_count_annotated_with_link",
"siae_email_send_count_annotated_with_link",
@@ -321,6 +323,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
"status",
"published_at",
"validated_at",
+ "sent_at",
)
},
),
@@ -386,7 +389,7 @@ def save_related(self, request, form, formsets, change):
super().save_related(request=request, form=form, formsets=formsets, change=change)
tender: Tender = form.instance
# we can add `and obj.status != obj.STATUS_DRAFT` to disable matching when is draft
- if not tender.is_validated:
+ if not tender.is_validated_or_sent:
tender.set_siae_found_list()
def save_formset(self, request, form, formset, change):
@@ -399,11 +402,11 @@ def save_formset(self, request, form, formset, change):
form.instance.author = request.user
super().save_formset(request, form, formset, change)
- def is_validate(self, tender: Tender):
- return tender.validated_at is not None
+ def is_validated_or_sent(self, tender: Tender):
+ return tender.is_validated_or_sent
- is_validate.boolean = True
- is_validate.short_description = "Validé"
+ is_validated_or_sent.boolean = True
+ is_validated_or_sent.short_description = "Validé / Envoyé"
def user_with_link(self, tender):
url = reverse("admin:users_user_change", args=[tender.author_id])
@@ -487,18 +490,19 @@ def logs_display(self, tender=None):
logs_display.short_description = Tender._meta.get_field("logs").verbose_name
def response_change(self, request, obj: Tender):
+ """
+ Catch submit of custom admin button to Validate or Resend Tender
+ """
if request.POST.get("_validate_tender"):
- update_and_send_tender_task(tender=obj)
+ validate_and_send_tender_task(tender=obj)
self.message_user(request, "Ce dépôt de besoin a été validé et envoyé aux structures")
if settings.BITOUBI_ENV == "prod":
api_hubspot.create_deal_from_tender(tender=obj)
-
return HttpResponseRedirect(".")
elif request.POST.get("_restart_tender"):
restart_send_tender_task(tender=obj)
self.message_user(request, "Ce dépôt de besoin a été renvoyé aux structures")
return HttpResponseRedirect(".")
-
return super().response_change(request, obj)
def extra_data_display(self, instance: Tender = None):
diff --git a/lemarche/tenders/constants.py b/lemarche/tenders/constants.py
index c2ca4a42e..1f74d3f4a 100644
--- a/lemarche/tenders/constants.py
+++ b/lemarche/tenders/constants.py
@@ -99,11 +99,13 @@
STATUS_DRAFT = "DRAFT"
STATUS_PUBLISHED = "PUBLISHED"
STATUS_VALIDATED = "VALIDATED"
+STATUS_SENT = "SENT"
STATUS_CHOICES = (
(STATUS_DRAFT, "Brouillon"),
(STATUS_PUBLISHED, "Publié"),
(STATUS_VALIDATED, "Validé"),
+ (STATUS_SENT, "Envoyé"),
)
diff --git a/lemarche/tenders/factories.py b/lemarche/tenders/factories.py
index 067da52b9..2ffa66732 100644
--- a/lemarche/tenders/factories.py
+++ b/lemarche/tenders/factories.py
@@ -34,7 +34,6 @@ class Meta:
deadline_date = date.today() + timedelta(days=10)
start_working_date = date.today() + timedelta(days=random.randint(12, 90))
author = factory.SubFactory(UserFactory)
- validated_at = timezone.now()
external_link = factory.Sequence("https://{0}example.com".format)
# Contact fields
contact_first_name = factory.Sequence("first_name{0}".format)
@@ -43,7 +42,9 @@ class Meta:
contact_phone = factory.fuzzy.FuzzyText(length=10, chars=string.digits)
# amount = tender_constants.AMOUNT_RANGE_100_150
# marche_benefits = factory.fuzzy.FuzzyChoice([key for (key, _) in constants.MARCHE_BENEFIT_CHOICES])
- status = tender_constants.STATUS_VALIDATED
+ status = tender_constants.STATUS_SENT
+ validated_at = timezone.now()
+ sent_at = timezone.now()
@factory.post_generation
def perimeters(self, create, extracted, **kwargs):
diff --git a/lemarche/tenders/management/commands/send_author_incremental_emails.py b/lemarche/tenders/management/commands/send_author_incremental_emails.py
index 2150d14b8..585e0df1b 100644
--- a/lemarche/tenders/management/commands/send_author_incremental_emails.py
+++ b/lemarche/tenders/management/commands/send_author_incremental_emails.py
@@ -9,7 +9,7 @@
class Command(BaseCommand):
"""
- Daily script to check recently validated Tenders. If incremental, then contact author
+ Daily script to check recently sent Tenders. If incremental, then contact author
When? J+2
Usage:
@@ -25,21 +25,21 @@ def handle(self, dry_run=False, **options):
self.stdout.write("Script to send Tender incremental emails...")
self.stdout.write("-" * 80)
- self.stdout.write("Step 1: Find Tender validated J+2")
+ self.stdout.write("Step 1: Find Tender sent J+2")
two_days_ago = timezone.now() - timedelta(days=2)
three_days_ago = timezone.now() - timedelta(days=3)
- tender_validated_incremental = Tender.objects.validated().is_incremental()
- tender_validated_incremental_2_days = tender_validated_incremental.filter(
- created_at__gte=three_days_ago
- ).filter(created_at__lt=two_days_ago)
- self.stdout.write(f"Found {tender_validated_incremental_2_days.count()} Tenders")
+ tender_sent_incremental = Tender.objects.sent().is_incremental()
+ tender_sent_incremental_2_days = tender_sent_incremental.filter(sent_at__gte=three_days_ago).filter(
+ sent_at__lt=two_days_ago
+ )
+ self.stdout.write(f"Found {tender_sent_incremental_2_days.count()} Tenders")
if not dry_run:
self.stdout.write("-" * 80)
self.stdout.write("Step 2: Send emails")
- for tender in tender_validated_incremental_2_days:
+ for tender in tender_sent_incremental_2_days:
send_author_incremental_2_days_email(tender)
- self.stdout.write(f"Sent {tender_validated_incremental_2_days.count()} J+2 emails")
+ self.stdout.write(f"Sent {tender_sent_incremental_2_days.count()} J+2 emails")
self.stdout.write("-" * 80)
self.stdout.write("Done!")
diff --git a/lemarche/tenders/management/commands/send_author_transactioned_question_emails.py b/lemarche/tenders/management/commands/send_author_transactioned_question_emails.py
index 66eb1516e..780cbfa16 100644
--- a/lemarche/tenders/management/commands/send_author_transactioned_question_emails.py
+++ b/lemarche/tenders/management/commands/send_author_transactioned_question_emails.py
@@ -35,8 +35,10 @@ def handle(self, kind=None, dry_run=False, is_all_tenders=False, **options):
self.stdout.write("-" * 80)
start_date_feature = datetime(2022, 6, 23).date()
# we first filter on validated tenders
- tender_qs = Tender.objects.transaction_survey_email(kind=kind, all=is_all_tenders).filter(
- deadline_date__gte=start_date_feature
+ tender_qs = (
+ Tender.objects.sent()
+ .transaction_survey_email(kind=kind, all=is_all_tenders)
+ .filter(deadline_date__gte=start_date_feature)
)
self.stdout.write(f"Found {tender_qs.count()} tenders")
diff --git a/lemarche/tenders/migrations/0064_tender_status_sent.py b/lemarche/tenders/migrations/0064_tender_status_sent.py
new file mode 100644
index 000000000..5a5d1af41
--- /dev/null
+++ b/lemarche/tenders/migrations/0064_tender_status_sent.py
@@ -0,0 +1,37 @@
+# Generated by Django 4.2.2 on 2023-11-30 22:12
+
+from django.db import migrations, models
+
+
+def populate_tenders_sent_status(apps, schema_editor):
+ Tender = apps.get_model("tenders", "Tender")
+
+ for tender in Tender.objects.filter(validated_at__isnull=False):
+ tender.sent_at = tender.validated_at
+ tender.status = "SENT"
+ tender.save()
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("tenders", "0063_tender_distance_location"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="tender",
+ name="sent_at",
+ field=models.DateTimeField(blank=True, null=True, verbose_name="Date d'envoi"),
+ ),
+ migrations.AlterField(
+ model_name="tender",
+ name="status",
+ field=models.CharField(
+ choices=[("DRAFT", "Brouillon"), ("PUBLISHED", "Publié"), ("VALIDATED", "Validé"), ("SENT", "Envoyé")],
+ default="DRAFT",
+ max_length=10,
+ verbose_name="Statut",
+ ),
+ ),
+ migrations.RunPython(populate_tenders_sent_status),
+ ]
diff --git a/lemarche/tenders/models.py b/lemarche/tenders/models.py
index 6e14c0e0f..ef85e86db 100644
--- a/lemarche/tenders/models.py
+++ b/lemarche/tenders/models.py
@@ -44,6 +44,9 @@ def by_user(self, user):
def validated(self):
return self.filter(validated_at__isnull=False)
+ def sent(self):
+ return self.filter(sent_at__isnull=False)
+
def is_incremental(self):
return self.filter(
scale_marche_useless__in=[
@@ -53,14 +56,14 @@ def is_incremental(self):
)
def is_live(self):
- return self.validated().filter(deadline_date__gte=datetime.today())
+ return self.sent().filter(deadline_date__gte=datetime.today())
def has_amount(self):
return self.filter(Q(amount__isnull=False) | Q(amount_exact__isnull=False))
def transaction_survey_email(self, kind=None, all=False):
seven_days_ago = datetime.today().date() - timedelta(days=7)
- qs = self.validated().filter(survey_transactioned_answer=None)
+ qs = self.sent().filter(survey_transactioned_answer=None)
if kind:
qs = qs.filter(kind=kind)
if all:
@@ -86,11 +89,11 @@ def in_sectors(self, sectors):
def filter_with_siaes(self, siaes):
"""
- Return the list of tenders corresponding to the list of Siaes
+ Return the list of tenders corresponding to the list of
+ - we return only sent tenders
- the tender-siae matching has already been done with filter_with_tender()
- - we return only validated tenders
"""
- return self.filter(tendersiae__siae__in=siaes).validated().distinct()
+ return self.sent().filter(tendersiae__siae__in=siaes).distinct()
def with_deadline_date_is_outdated(self, limit_date=datetime.today()):
return self.annotate(
@@ -370,7 +373,7 @@ class Tender(models.Model):
"Sondage transaction : date de réponse", blank=True, null=True
)
- # validation
+ # validation & send
status = models.CharField(
verbose_name="Statut",
max_length=10,
@@ -378,6 +381,7 @@ class Tender(models.Model):
default=tender_constants.STATUS_DRAFT,
)
validated_at = models.DateTimeField("Date de validation", blank=True, null=True)
+ sent_at = models.DateTimeField("Date d'envoi", blank=True, null=True)
# admin
notes = GenericRelation("notes.Note", related_query_name="tender")
@@ -642,14 +646,32 @@ def is_pending_validation(self) -> bool:
def is_validated(self) -> bool:
return self.validated_at and self.status == tender_constants.STATUS_VALIDATED
- def set_validated(self, with_save=True):
+ @property
+ def is_pending_validation_or_validated(self) -> bool:
+ return self.is_pending_validation or self.is_validated
+
+ @property
+ def is_sent(self) -> bool:
+ return self.sent_at and self.status == tender_constants.STATUS_SENT
+
+ @property
+ def is_validated_or_sent(self) -> bool:
+ return self.is_validated or self.is_sent
+
+ def set_validated_and_sent(self, with_save=True):
self.validated_at = timezone.now()
- self.status = tender_constants.STATUS_VALIDATED
+ self.sent_at = timezone.now()
+ self.status = tender_constants.STATUS_SENT
log_item = {
"action": "validate",
"date": self.validated_at.isoformat(),
}
self.logs.append(log_item)
+ log_item = {
+ "action": "send",
+ "date": self.sent_at.isoformat(),
+ }
+ self.logs.append(log_item)
if with_save:
self.save()
diff --git a/lemarche/tenders/tests.py b/lemarche/tenders/tests.py
index eec3860f5..cb1fbfbe5 100644
--- a/lemarche/tenders/tests.py
+++ b/lemarche/tenders/tests.py
@@ -109,10 +109,12 @@ def test_status(self):
tender_pending_validation = TenderFactory(status=tender_constants.STATUS_PUBLISHED)
tender_validated_half = TenderFactory(status=tender_constants.STATUS_VALIDATED)
tender_validated_full = TenderFactory(status=tender_constants.STATUS_VALIDATED, validated_at=timezone.now())
+ tender_sent = TenderFactory(status=tender_constants.STATUS_SENT, sent_at=timezone.now())
self.assertTrue(tender_draft.is_draft, True)
self.assertTrue(tender_pending_validation.is_pending_validation, True)
self.assertTrue(tender_validated_half.is_validated, False)
self.assertTrue(tender_validated_full.is_validated, True)
+ self.assertTrue(tender_sent.is_sent, True)
def test_amount_display(self):
tender_with_amount = TenderFactory(amount=tender_constants.AMOUNT_RANGE_0_1, accept_share_amount=True)
@@ -195,6 +197,11 @@ def test_validated(self):
TenderFactory(validated_at=None)
self.assertEqual(Tender.objects.validated().count(), 1)
+ def test_sent(self):
+ TenderFactory(sent_at=timezone.now())
+ TenderFactory(sent_at=None)
+ self.assertEqual(Tender.objects.sent().count(), 1)
+
def test_is_live(self):
TenderFactory(deadline_date=timezone.now() + timedelta(days=1))
TenderFactory(deadline_date=timezone.now() - timedelta(days=1))
@@ -324,9 +331,9 @@ def setUpTestData(cls):
TenderQuestionFactory(tender=cls.tender_with_siae_1)
def test_filter_with_siaes(self):
- self.tender_with_siae_2.validated_at = None
+ self.tender_with_siae_2.sent_at = None
self.tender_with_siae_2.save()
- # tender_with_siae_2 is not validated
+ # tender_with_siae_2 is not sent
self.assertEqual(Tender.objects.filter_with_siaes(self.user_siae.siaes.all()).count(), 1)
def test_with_siae_stats(self):
diff --git a/lemarche/utils/mixins.py b/lemarche/utils/mixins.py
index b4a103304..a211673dd 100644
--- a/lemarche/utils/mixins.py
+++ b/lemarche/utils/mixins.py
@@ -154,16 +154,16 @@ def handle_no_permission(self):
return HttpResponseRedirect(reverse_lazy("tenders:list"))
-class TenderAuthorOrAdminRequiredIfNotValidatedMixin(UserPassesTestMixin):
+class TenderAuthorOrAdminRequiredIfNotSentMixin(UserPassesTestMixin):
"""
- If the Tender's status is not "validated", restrict access to the Tender's author (or Admin)
+ If the Tender's status is not "sent", restrict access to the Tender's author (or Admin)
"""
def test_func(self):
# user = self.request.user
tender_slug = self.kwargs.get("slug")
tender = get_object_or_404(Tender.objects.all(), slug=tender_slug)
- if tender.status != tender_constants.STATUS_VALIDATED:
+ if tender.status != tender_constants.STATUS_SENT:
return TenderAuthorOrAdminRequiredMixin.test_func(self)
return True
diff --git a/lemarche/www/dashboard/views.py b/lemarche/www/dashboard/views.py
index cf98254f8..ee54a50d6 100644
--- a/lemarche/www/dashboard/views.py
+++ b/lemarche/www/dashboard/views.py
@@ -70,7 +70,7 @@ def get_context_data(self, **kwargs):
context["last_3_tenders"] = Tender.objects.filter(author=user).order_by_deadline_date()[:3]
context["user_buyer_count"] = User.objects.filter(kind=User.KIND_BUYER).count()
context["siae_count"] = Siae.objects.is_live().count()
- context["tender_count"] = Tender.objects.validated().count() + 30 # historic number (before form)
+ context["tender_count"] = Tender.objects.sent().count() + 30 # historic number (before form)
return context
diff --git a/lemarche/www/dashboard_networks/tests.py b/lemarche/www/dashboard_networks/tests.py
index 7ce800fa1..5cea5074e 100644
--- a/lemarche/www/dashboard_networks/tests.py
+++ b/lemarche/www/dashboard_networks/tests.py
@@ -35,7 +35,7 @@ def setUpTestData(cls):
author=cls.user_buyer,
amount=tender_constants.AMOUNT_RANGE_100_150,
accept_share_amount=False,
- status=tender_constants.STATUS_VALIDATED,
+ status=tender_constants.STATUS_SENT,
validated_at=timezone.now(),
deadline_date=timezone.now() - timedelta(days=5),
)
diff --git a/lemarche/www/dashboard_networks/views.py b/lemarche/www/dashboard_networks/views.py
index 5cbf03120..84bc082ae 100644
--- a/lemarche/www/dashboard_networks/views.py
+++ b/lemarche/www/dashboard_networks/views.py
@@ -115,7 +115,7 @@ def get_object(self):
self.network = Network.objects.prefetch_related("siaes").get(slug=self.kwargs.get("slug"))
self.network_siaes = self.network.siaes.all()
self.tender = get_object_or_404(
- Tender.objects.validated().with_network_siae_stats(self.network_siaes),
+ Tender.objects.sent().with_network_siae_stats(self.network_siaes),
slug=self.kwargs.get("tender_slug"),
)
return self.tender
@@ -142,7 +142,7 @@ def get(self, request, status=None, *args, **kwargs):
if "tender_slug" in self.kwargs:
self.network_siaes = self.network.siaes.all()
self.tender = get_object_or_404(
- Tender.objects.validated().with_network_siae_stats(self.network_siaes),
+ Tender.objects.sent().with_network_siae_stats(self.network_siaes),
slug=self.kwargs.get("tender_slug"),
)
return super().get(request, *args, **kwargs)
diff --git a/lemarche/www/pages/views.py b/lemarche/www/pages/views.py
index 1a8f00793..bd38fe443 100644
--- a/lemarche/www/pages/views.py
+++ b/lemarche/www/pages/views.py
@@ -55,7 +55,7 @@ def get_context_data(self, **kwargs):
pass
context["user_buyer_count"] = User.objects.filter(kind=User.KIND_BUYER).count()
context["siae_count"] = Siae.objects.is_live().count()
- context["tender_count"] = Tender.objects.validated().count() + 30 # historic number (before form)
+ context["tender_count"] = Tender.objects.sent().count() + 30 # historic number (before form)
return context
@@ -370,7 +370,7 @@ def csrf_failure(request, reason=""): # noqa C901
if settings.BITOUBI_ENV == "prod":
notify_admin_tender_created(tender)
- if tender.status == tender_constants.STATUS_DRAFT:
+ if tender.is_draft:
messages.add_message(
request=request,
level=messages.INFO,
diff --git a/lemarche/www/tenders/tasks.py b/lemarche/www/tenders/tasks.py
index 2d51527c6..3748dd473 100644
--- a/lemarche/www/tenders/tasks.py
+++ b/lemarche/www/tenders/tasks.py
@@ -466,7 +466,7 @@ def send_author_incremental_2_days_email(tender: Tender):
variables = {
"TENDER_AUTHOR_FIRST_NAME": tender.author.first_name,
"TENDER_TITLE": tender.title,
- "TENDER_VALIDATE_AT": tender.validated_at.strftime("%d %B %Y"),
+ "TENDER_VALIDATE_AT": tender.sent_at.strftime("%d %B %Y"), # TODO: TENDER_SENT_AT?
"TENDER_KIND": tender.get_kind_display(),
}
@@ -500,7 +500,7 @@ def send_tenders_author_feedback_or_survey(tender: Tender, kind="feedback_30d"):
variables = {
"TENDER_AUTHOR_FIRST_NAME": tender.author.first_name,
"TENDER_TITLE": tender.title,
- "TENDER_VALIDATE_AT": tender.validated_at.strftime("%d %B %Y"),
+ "TENDER_VALIDATE_AT": tender.sent_at.strftime("%d %B %Y"), # TODO: TENDER_SENT_AT?
"TENDER_KIND": tender.get_kind_display(),
}
diff --git a/lemarche/www/tenders/tests.py b/lemarche/www/tenders/tests.py
index 16419cdde..fcf1125ba 100644
--- a/lemarche/www/tenders/tests.py
+++ b/lemarche/www/tenders/tests.py
@@ -471,7 +471,7 @@ def setUpTestData(cls):
cls.user_buyer_1 = UserFactory(kind=User.KIND_BUYER, company_name="Entreprise Buyer")
cls.user_buyer_2 = UserFactory(kind=User.KIND_BUYER)
cls.user_partner = UserFactory(kind=User.KIND_PARTNER)
- cls.tender = TenderFactory(author=cls.user_buyer_1, validated_at=timezone.now(), perimeters=[perimeter])
+ cls.tender = TenderFactory(author=cls.user_buyer_1, perimeters=[perimeter])
cls.tender_2 = TenderFactory(
author=cls.user_buyer_1, deadline_date=timezone.now() - timedelta(days=5), perimeters=[perimeter]
)
@@ -479,7 +479,6 @@ def setUpTestData(cls):
author=cls.user_buyer_1,
amount=tender_constants.AMOUNT_RANGE_100_150,
accept_share_amount=False,
- validated_at=timezone.now(),
deadline_date=timezone.now() - timedelta(days=5),
perimeters=[perimeter],
)
@@ -599,6 +598,8 @@ def setUpTestData(cls):
response_kind=[tender_constants.RESPONSE_KIND_EMAIL],
sectors=[sector_1],
location=grenoble_perimeter,
+ status=tender_constants.STATUS_SENT,
+ sent_at=timezone.now(),
)
cls.tendersiae_1_1 = TenderSiae.objects.create(
tender=cls.tender_1,
@@ -610,9 +611,14 @@ def setUpTestData(cls):
detail_contact_click_date=timezone.now(),
)
TenderQuestionFactory(tender=cls.tender_1)
- cls.tender_2 = TenderFactory(author=cls.user_buyer_1, contact_company_name="Another company")
+ cls.tender_2 = TenderFactory(
+ author=cls.user_buyer_1,
+ contact_company_name="Another company",
+ status=tender_constants.STATUS_SENT,
+ sent_at=timezone.now(),
+ )
- def test_anyone_can_view_validated_tenders(self):
+ def test_anyone_can_view_sent_tenders(self):
# anonymous
url = reverse("tenders:detail", kwargs={"slug": self.tender_1.slug})
response = self.client.get(url)
@@ -625,12 +631,18 @@ def test_anyone_can_view_validated_tenders(self):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
- def test_only_author_or_admin_can_view_non_validated_tender(self):
+ def test_only_author_or_admin_can_view_non_sent_tender(self):
tender_draft = TenderFactory(author=self.user_buyer_1, status=tender_constants.STATUS_DRAFT)
tender_published = TenderFactory(
author=self.user_buyer_1, status=tender_constants.STATUS_PUBLISHED, published_at=timezone.now()
)
- for tender in [tender_draft, tender_published]:
+ tender_validated_but_not_sent = TenderFactory(
+ author=self.user_buyer_1,
+ status=tender_constants.STATUS_VALIDATED,
+ published_at=timezone.now(),
+ validated_at=timezone.now(),
+ )
+ for tender in [tender_draft, tender_published, tender_validated_but_not_sent]:
# anonymous
url = reverse("tenders:detail", kwargs={"slug": tender.slug})
response = self.client.get(url)
diff --git a/lemarche/www/tenders/views.py b/lemarche/www/tenders/views.py
index e226ed650..a078b72da 100644
--- a/lemarche/www/tenders/views.py
+++ b/lemarche/www/tenders/views.py
@@ -21,7 +21,7 @@
from lemarche.utils.mixins import (
SesameTenderAuthorRequiredMixin,
SiaeUserRequiredOrSiaeIdParamMixin,
- TenderAuthorOrAdminRequiredIfNotValidatedMixin,
+ TenderAuthorOrAdminRequiredIfNotSentMixin,
TenderAuthorOrAdminRequiredMixin,
)
from lemarche.www.siaes.forms import SiaeFilterForm
@@ -324,7 +324,7 @@ def get_context_data(self, **kwargs):
return context
-class TenderDetailView(TenderAuthorOrAdminRequiredIfNotValidatedMixin, DetailView):
+class TenderDetailView(TenderAuthorOrAdminRequiredIfNotSentMixin, DetailView):
model = Tender
template_name = "tenders/detail.html"
context_object_name = "tender"