Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
repos:
- repo: local
hooks:
- id: black
name: apply black
language: system
types: [python]
entry: pipenv run black
- id: ruff
name: ruff
language: system
types: [python]
entry: pipenv run ruff check
args: [--fix]
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ run: ## Run the test server.

install: ## Install the python requirements.
pip install -r requirements.txt

migrate: ## Run the test server.
python manage.py migrate
Empty file.
58 changes: 58 additions & 0 deletions padam_django/apps/shift/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from django.contrib import admin

from padam_django.apps.shift.forms import ScheduleStopForm

from .models import BusShift, BusStop, ScheduleStop


@admin.register(BusShift)
class BusShiftAdmin(admin.ModelAdmin):
# Make field not last stop, first_stop not editable
readonly_fields = ("first_stop", "last_stop")
list_display = (
"bus",
"driver",
"get_stop_count",
"get_validation_stop_information",
"get_shift_start_information",
"get_shift_end_information",
"get_shift_duration_information",
)

@admin.display(description="Stop count")
def get_stop_count(self, obj):
return ScheduleStop.objects.filter(bus_shift=obj.id).count()

@admin.display(description="Stop count validation")
def get_validation_stop_information(self, obj):
stop_count = ScheduleStop.objects.filter(bus_shift=obj.id).count()
if stop_count < 2:
return "Missing bus stops"
return "Valid bus stops count"

@admin.display(description="Shift start")
def get_shift_start_information(self, obj):
return obj.first_stop

@admin.display(description="Shift end")
def get_shift_end_information(self, obj):
return obj.last_stop

@admin.display(description="Total duration (hours)")
def get_shift_duration_information(self, obj):
return obj.shift_duration


@admin.register(BusStop)
class BusStopAdmin(admin.ModelAdmin):
list_display = ("id", "name", "place")


@admin.register(ScheduleStop)
class ScheduleStopAdmin(admin.ModelAdmin):
form = ScheduleStopForm
list_display = (
"bus_shift",
"bus_stop",
"arrival",
)
9 changes: 9 additions & 0 deletions padam_django/apps/shift/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.apps import AppConfig


class ShiftConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "padam_django.apps.shift"

def ready(self):
import padam_django.apps.shift.receivers # noqa
36 changes: 36 additions & 0 deletions padam_django/apps/shift/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from random import randint

import factory
from django.utils import timezone

from padam_django.apps.fleet.factories import BusFactory, DriverFactory
from padam_django.apps.geography.factories import PlaceFactory

from . import models


class BusStopFactory(factory.django.DjangoModelFactory):
name = factory.Sequence(lambda n: "Bus stop %01d" % n)
place = factory.SubFactory(PlaceFactory)

class Meta:
model = models.BusStop


class BusShiftFactory(factory.django.DjangoModelFactory):
bus = factory.SubFactory(BusFactory)
driver = factory.SubFactory(DriverFactory)
first_stop = timezone.now()
last_stop = timezone.now()

class Meta:
model = models.BusShift


class ScheduleStopFactory(factory.django.DjangoModelFactory):
bus_shift = factory.SubFactory(BusShiftFactory)
bus_stop = factory.SubFactory(BusStopFactory)
arrival = timezone.now() + timezone.timedelta(hours=randint(7, 22))

class Meta:
model = models.ScheduleStop
32 changes: 32 additions & 0 deletions padam_django/apps/shift/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django import forms
from django.core.exceptions import ValidationError

from .models import BusShift, ScheduleStop


class ScheduleStopForm(forms.ModelForm):
class Meta:
model = ScheduleStop
fields = "__all__"

def clean(self):
cleaned_data = super().clean()
bus_shift = cleaned_data["bus_shift"]
arrival = cleaned_data["arrival"]

# Check bus
bus_shifts = BusShift.objects.filter(
bus=bus_shift.bus, first_stop__lte=arrival, last_stop__gte=arrival
).count()

if bus_shifts > 0:
raise ValidationError("Bus is not available")

driver_shifts = BusShift.objects.filter(
driver=bus_shift.driver, first_stop__lte=arrival, last_stop__gte=arrival
).count()

if driver_shifts > 0:
raise ValidationError("Driver is not available")

return cleaned_data
100 changes: 100 additions & 0 deletions padam_django/apps/shift/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Generated by Django 3.2.5 on 2024-06-14 07:29

import uuid

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
initial = True

dependencies = [
("geography", "0001_initial"),
("fleet", "0002_auto_20211109_1456"),
]

operations = [
migrations.CreateModel(
name="BusShift",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("first_stop", models.DateTimeField(blank=True, null=True)),
("last_stop", models.DateTimeField(blank=True, null=True)),
(
"bus",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to="fleet.bus"
),
),
(
"driver",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to="fleet.driver"
),
),
],
),
migrations.CreateModel(
name="BusStop",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
(
"name",
models.CharField(
max_length=20, verbose_name="Name of the bus stop"
),
),
(
"place",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="geography.place",
),
),
],
),
migrations.CreateModel(
name="ScheduleStop",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("arrival", models.DateTimeField()),
(
"bus_shift",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to="shift.busshift"
),
),
(
"bus_stop",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to="shift.busstop"
),
),
],
),
]
Empty file.
41 changes: 41 additions & 0 deletions padam_django/apps/shift/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import uuid

from django.db import models


class BusStop(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField("Name of the bus stop", max_length=20)
place = models.ForeignKey("geography.place", on_delete=models.PROTECT)

def __str__(self):
return f"Name: {self.name} (id: {self.pk})"


class BusShift(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
bus = models.ForeignKey("fleet.bus", on_delete=models.PROTECT)
driver = models.ForeignKey("fleet.driver", on_delete=models.PROTECT)
first_stop = models.DateTimeField(
auto_now=False, auto_now_add=False, null=True, blank=True
) # Use this fields as "cache"
last_stop = models.DateTimeField(
auto_now=False, auto_now_add=False, null=True, blank=True
) # Use this fields as "cache"

@property
def shift_duration(self):
return self.last_stop - self.first_stop

def __str__(self):
return f"Bus: {self.bus.licence_plate} driver: {self.driver.user.username} (id: {self.pk})"


class ScheduleStop(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
bus_shift = models.ForeignKey(BusShift, on_delete=models.PROTECT)
bus_stop = models.ForeignKey(BusStop, on_delete=models.PROTECT)
arrival = models.DateTimeField(auto_now=False, auto_now_add=False)

def __str__(self):
return f"Shift: {self.bus_shift} stop: {self.bus_stop.name} (id: {self.pk})"
21 changes: 21 additions & 0 deletions padam_django/apps/shift/receivers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.db.models.signals import post_save
from django.dispatch import receiver

from .models import BusShift, ScheduleStop


@receiver(post_save, sender=ScheduleStop)
def update_bus_shift_start_or_end(sender, instance, **kwargs):
bus_shift = BusShift.objects.get(id=instance.bus_shift.id)

if bus_shift.first_stop is None and bus_shift.last_stop is None:
bus_shift.first_stop = instance.arrival
bus_shift.last_stop = instance.arrival
bus_shift.save()

if instance.arrival < bus_shift.first_stop:
bus_shift.first_stop = instance.arrival
bus_shift.save()
if instance.arrival > bus_shift.last_stop:
bus_shift.last_stop = instance.arrival
bus_shift.save()
Loading