Skip to content

Commit

Permalink
[Dépôt de besoin] Nouveau status "SENT" (#997)
Browse files Browse the repository at this point in the history
* New Tender.status option SENT

* Add to admin

* On tender validate, also set sent_at

* New Tender.sent() qs

* Fix tests & rebase
  • Loading branch information
raphodn authored Dec 6, 2023
1 parent 83a5fb3 commit c457fb2
Show file tree
Hide file tree
Showing 22 changed files with 160 additions and 70 deletions.
4 changes: 2 additions & 2 deletions lemarche/templates/tenders/_card_list_item.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
{% if tender.deadline_date_is_outdated_annotated %}
<span class="badge badge-xs badge-base badge-pill badge-pilotage float-right">Clôturé</span>
{% endif %}
{% if tender.status == tender.STATUS_DRAFT %}
{% if tender.is_draft %}
<span class="badge badge-xs badge-base badge-pill badge-outline-warning float-right">
<i class="ri-draft-fill"></i>Brouillon
</span>
{% elif tender.status == tender.STATUS_PUBLISHED %}
{% elif tender.is_pending_validation_or_validated %}
<span class="badge badge-xs badge-base badge-pill badge-outline-info float-right">
<i class="ri-loader-fill"></i>En cours de validation
</span>
Expand Down
4 changes: 2 additions & 2 deletions lemarche/templates/tenders/_detail_admin_extra_info.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ <h2 class="h3">Informations Admin</h2>
Publié le {{ tender.published_at|date }}
</li>
<li class="mb-2">
{% if tender.is_validated %}
Validé le {{ tender.validated_at|date }}
{% if tender.is_sent %}
Validé le {{ tender.sent_at|date }}
{% else %}
Statut : {{ tender.get_status_display }}
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion lemarche/templates/tenders/_detail_side_infos_author.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</div>
</div>
{% endif %}
{% if tender.is_validated %}
{% if tender.is_sent %}
<div class="alert alert-success fade show" role="status">
<div class="row">
<div class="col-auto pr-0">
Expand Down
12 changes: 6 additions & 6 deletions lemarche/templates/tenders/_list_item_buyer.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
{% if tender.deadline_date_is_outdated_annotated %}
<span class="badge badge-sm badge-base badge-pill badge-pilotage">Clôturé</span>
{% endif %}
{% if tender.status == tender.STATUS_DRAFT %}
{% if tender.is_draft %}
<span class="badge badge-sm badge-base badge-pill badge-outline-warning float-right">
<i class="ri-draft-fill"></i>Brouillon
</span>
{% elif tender.status == tender.STATUS_PUBLISHED %}
{% elif tender.is_pending_validation_or_validated %}
<span class="badge badge-sm badge-base badge-pill badge-outline-info float-right">
<i class="ri-loader-fill"></i>En cours de validation
</span>
{% elif tender.status == tender.STATUS_VALIDATED %}
{% elif tender.is_sent %}
<span class="badge badge-sm badge-base badge-pill badge-outline-success float-right">
<i class="ri-mail-send-line"></i>Envoyé
</span>
Expand All @@ -33,17 +33,17 @@ <h2 class="py-2">{{ tender.title }}</h2>
<i class="ri-time-line"></i>
Créé le {{ tender.created_at|date }}
</div>
{% if tender.status == tender.STATUS_VALIDATED %}
{% if tender.is_sent %}
<div class="col-md-4">
<i class="ri-time-line"></i>
Publié le {{ tender.validated_at|date }}
Publié le {{ tender.sent_at|date }}
</div>
{% endif %}
</div>
</div>
<div class="col-md-4 text-center my-auto">
<hr class="d-md-none" />
{% if tender.status == tender.STATUS_VALIDATED %}
{% if tender.is_sent %}
{% if tender.siae_detail_contact_click_since_last_seen_date_count_annotated %}
<span class="badge badge-base badge-pill badge-pilotage">
<i class="ri-thumb-up-line ri-xl"></i>&nbsp;{{ 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 }}
Expand Down
7 changes: 5 additions & 2 deletions lemarche/templates/tenders/admin_change_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
{% if original %}
<div class="submit-row">
{% if original.validated_at %}
<i>Validé et envoyé le {{ original.validated_at }}</i><br>
<button type="submit" name="_restart_tender" value="1" class="button">Renvoyer aux structures</button>
<i>Validé le {{ original.validated_at }}.&nbsp;</i>
{% if original.sent_at %}
<i>Envoyé le {{ original.sent_at }}.</i><br>
<button type="submit" name="_restart_tender" value="1" class="button">Renvoyer aux structures</button>
{% endif %}
{% else %}
<button type="submit" name="_validate_tender" value="1" class="button">Valider (sauvegarder) et envoyer aux structures</button>
{% endif %}
Expand Down
8 changes: 4 additions & 4 deletions lemarche/templates/tenders/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ <h1>{{ page_title }}</h1>
{% 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 %}

<li class="nav-item">
<a role="button" hx-push-url="true" hx-get="{{ TENDERS_LIST_URL }}"
Expand All @@ -71,8 +71,8 @@ <h1>{{ page_title }}</h1>
</a>
</li>
<li class="nav-item">
<a role="button" hx-push-url="true" hx-get="{{ TENDERS_VALIDATED_LIST_URL }}"
class="nav-link{% if request.get_full_path == TENDERS_VALIDATED_LIST_URL %} active{% endif %}"
<a role="button" hx-push-url="true" hx-get="{{ TENDERS_SENT_LIST_URL }}"
class="nav-link{% if request.get_full_path == TENDERS_SENT_LIST_URL %} active{% endif %}"
hx-target="#tendersList" hx-swap="outerHTML">
Envoyé
</a>
Expand All @@ -93,7 +93,7 @@ <h1>{{ page_title }}</h1>
{% 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.
<br />
Contacter notre équipe en cas de problème avec un de vos dépôts de besoins en cours de validation.
Expand Down
26 changes: 15 additions & 11 deletions lemarche/tenders/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -123,7 +123,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
list_display = [
"id",
"status",
"is_validate",
"is_validated_or_sent",
"title",
"user_with_link",
"kind",
Expand All @@ -138,6 +138,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
"siae_transactioned",
"created_at",
"validated_at",
"sent_at",
]

list_filter = [
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -321,6 +323,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
"status",
"published_at",
"validated_at",
"sent_at",
)
},
),
Expand Down Expand Up @@ -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):
Expand All @@ -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])
Expand Down Expand Up @@ -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):
Expand Down
2 changes: 2 additions & 0 deletions lemarche/tenders/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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é"),
)


Expand Down
5 changes: 3 additions & 2 deletions lemarche/tenders/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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!")
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
37 changes: 37 additions & 0 deletions lemarche/tenders/migrations/0064_tender_status_sent.py
Original file line number Diff line number Diff line change
@@ -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),
]
Loading

0 comments on commit c457fb2

Please sign in to comment.