Skip to content

Commit

Permalink
✨(dashboard) add signals on delivery point creation
Browse files Browse the repository at this point in the history
Implemented a signal to automatically create a Consent object when a new DeliveryPoint is saved.
Added corresponding tests to ensure functionality and updated related Pipfile dependencies.
Centralized consent end date logic in a new app settings file (CONSENT_END_DATE) and updated all related signals, factories, and tests to use it.
Updated documentation and code comments to reflect these changes.
  • Loading branch information
ssorin committed Dec 19, 2024
1 parent 759a639 commit 10be51b
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 137 deletions.
3 changes: 3 additions & 0 deletions src/dashboard/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ and this project adheres to
- add consent form to manage consents of one or many entities
- integration of custom 403, 404 and 500 pages
- sentry integration
- added a signal on the creation of a delivery point. This signal allows the creation
of the consent corresponding to the delivery point


[unreleased]: https://github.com/MTES-MCT/qualicharge/compare/main...bootstrap-dashboard-project

4 changes: 4 additions & 0 deletions src/dashboard/apps/consent/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ class ConsentConfig(AppConfig):
name = "apps.consent"
label = "qcd_consent"
verbose_name = _("Consent")

def ready(self):
"""Register signals."""
from .signals import handle_new_delivery_point # noqa: F401
5 changes: 2 additions & 3 deletions src/dashboard/apps/consent/factories.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Dashboard consent factories."""

from datetime import timedelta

import factory
from django.utils import timezone
from factory import fuzzy
Expand All @@ -10,6 +8,7 @@
from apps.core.factories import DeliveryPointFactory

from .models import Consent
from .settings import CONSENT_END_DATE


class ConsentFactory(factory.django.DjangoModelFactory):
Expand All @@ -18,7 +17,7 @@ class ConsentFactory(factory.django.DjangoModelFactory):
delivery_point = factory.SubFactory(DeliveryPointFactory)
created_by = factory.SubFactory(UserFactory)
start = fuzzy.FuzzyDateTime(timezone.now())
end = factory.LazyAttribute(lambda o: o.start + timedelta(days=90))
end = CONSENT_END_DATE

class Meta: # noqa: D106
model = Consent
29 changes: 20 additions & 9 deletions src/dashboard/apps/consent/fixtures/consent.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
"""Dashboard consent dev fixture."""

from datetime import timedelta

from django.utils import timezone

from apps.auth.factories import UserFactory
from apps.consent import VALIDATED
from apps.consent.factories import ConsentFactory
from apps.core.factories import DeliveryPointFactory, EntityFactory
from apps.core.models import DeliveryPoint
Expand Down Expand Up @@ -29,12 +34,18 @@ def seed_consent():
entity4 = EntityFactory(users=(user5,))

# create delivery points
for _ in range(1, 4):
DeliveryPointFactory(entity=entity1)
DeliveryPointFactory(entity=entity2)
DeliveryPointFactory(entity=entity3)
DeliveryPointFactory(entity=entity4)

# create awaiting consents
for delivery_point in DeliveryPoint.objects.all():
ConsentFactory(delivery_point=delivery_point, created_by=user1)
size = 4
DeliveryPointFactory.create_batch(size, entity=entity1)
DeliveryPointFactory.create_batch(size, entity=entity2)
DeliveryPointFactory.create_batch(size, entity=entity3)
DeliveryPointFactory.create_batch(size, entity=entity4)

# create past consents with validated status
for dl in DeliveryPoint.objects.filter(entity=entity1):
ConsentFactory(
delivery_point=dl,
created_by=user1,
status=VALIDATED,
start=timezone.now() - timedelta(days=300),
end=timezone.now() - timedelta(days=270),
)
2 changes: 1 addition & 1 deletion src/dashboard/apps/consent/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class Consent(DashboardBase):
end = models.DateTimeField(_("end date"))
revoked_at = models.DateTimeField(_("revoked at"), null=True, blank=True)

active_objects = ConsentManager()
objects = models.Manager()
active_objects = ConsentManager()

class Meta: # noqa: D106
ordering = ["delivery_point"]
Expand Down
14 changes: 14 additions & 0 deletions src/dashboard/apps/consent/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Dashboard consent app settings."""

from django.conf import settings

from .utils import get_end_date

# `CONSENT_END_DATE` determines the default end date for the period consents
# (`datetime` format).
# This value is calculated dynamically via `apps.consent.utils.get_end_date()`
# By default `apps.consent.utils.get_end_date()` return the last day of current year.
# You can specify the number of days to add to the current date to calculate the end
# date.
# ie: `get_end_date(90)` will return the current date + 90 days.
CONSENT_END_DATE = getattr(settings, "CONSENT_END_DATE", get_end_date())
24 changes: 24 additions & 0 deletions src/dashboard/apps/consent/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Dashboard consent app signals."""

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import timezone

from apps.core.models import DeliveryPoint

from .models import Consent
from .settings import CONSENT_END_DATE


@receiver(post_save, sender=DeliveryPoint)
def handle_new_delivery_point(sender, instance, created, **kwargs):
"""Signal triggered after a new DeliveryPoint is saved.
Create a new Consent object for the delivery point.
"""
if created:
Consent.objects.create(
delivery_point=instance,
start=timezone.now(),
end=CONSENT_END_DATE,
)
35 changes: 16 additions & 19 deletions src/dashboard/apps/consent/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
"""Dashboard consent models tests."""

from datetime import timedelta

import pytest
from django.utils import formats

from apps.auth.factories import UserFactory
from apps.consent import AWAITING, REVOKED, VALIDATED
from apps.consent.factories import ConsentFactory
from apps.consent.models import Consent
from apps.consent.settings import CONSENT_END_DATE
from apps.core.factories import DeliveryPointFactory


@pytest.mark.django_db
def test_create_consent():
"""Tests the creation of a consent."""
user1 = UserFactory()
assert Consent.objects.count() == 0

# create one `delivery_point` and consequently one `consent`
delivery_point = DeliveryPointFactory()

consent = ConsentFactory(
delivery_point=delivery_point,
created_by=user1,
)
assert Consent.objects.count() == 1

# get the created consent
consent = Consent.objects.get(delivery_point=delivery_point)

assert consent.delivery_point == delivery_point
assert consent.created_by == user1
assert consent.created_by == delivery_point.entity.users.first()
assert consent.status == AWAITING
assert consent.revoked_at is None
assert consent.start is not None
assert consent.end is not None

# test consent.end is 90 days later than the consent.start
end_date = consent.start + timedelta(days=90)
end_date = CONSENT_END_DATE
consent_start = formats.date_format(end_date, "Y/m/d")
consent_end = formats.date_format(consent.end, "Y/m/d")
assert consent_start == consent_end
Expand All @@ -43,21 +43,18 @@ def test_create_consent():
@pytest.mark.django_db
def test_update_consent_status():
"""Tests updating a consent status."""
user1 = UserFactory()
# create one `delivery_point` and consequently one `consent`
delivery_point = DeliveryPointFactory()

consent = ConsentFactory(
delivery_point=delivery_point,
created_by=user1,
)

new_updated_at = consent.updated_at
# get the created consent
consent = Consent.objects.get(delivery_point=delivery_point)
consent_updated_at = consent.updated_at

# update status to VALIDATED
consent.status = VALIDATED
consent.save()
assert consent.status == VALIDATED
assert consent.updated_at > new_updated_at
assert consent.updated_at > consent_updated_at
assert consent.revoked_at is None
new_updated_at = consent.updated_at

Expand Down
23 changes: 23 additions & 0 deletions src/dashboard/apps/consent/tests/test_signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Dashboard consent signals tests."""

import pytest

from apps.consent.models import Consent
from apps.consent.settings import CONSENT_END_DATE
from apps.core.factories import DeliveryPointFactory


@pytest.mark.django_db
def test_signal_triggered_on_delivery_point_creation():
"""Tests if the signal is triggered when creating a DeliveryPoint."""
assert Consent.objects.count() == 0

# Create new delivery point
delivery_point = DeliveryPointFactory()

# check if consent was created with signals after delivery_point creation.
assert Consent.objects.count() == 1

consent = Consent.objects.first()
assert consent.delivery_point == delivery_point
assert consent.end == CONSENT_END_DATE
33 changes: 33 additions & 0 deletions src/dashboard/apps/consent/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Dashboard consent utils tests."""

from datetime import datetime, timedelta, timezone

import pytest

from apps.consent.utils import get_end_date


@pytest.mark.django_db
def test_get_end_date_with_days():
"""Test `get_end_date` function when days argument is provided."""
days = 10
end_date = get_end_date(days=days).replace(microsecond=0)
expected_date = datetime.now().replace(tzinfo=timezone.utc) + timedelta(days=days)
assert end_date == expected_date.replace(microsecond=0)


@pytest.mark.django_db
def test_get_end_date_without_days():
"""Test `get_end_date` function when days argument is not provided."""
end_date = get_end_date().replace(microsecond=0)
current_year = datetime.now().year
expected_date = datetime(
year=current_year,
month=12,
day=31,
hour=23,
minute=59,
second=59,
tzinfo=timezone.utc,
)
assert end_date == expected_date.replace(microsecond=0)
Loading

0 comments on commit 10be51b

Please sign in to comment.