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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ ENV/
# Editors stuff
.idea
.vscode

# Local stuff
.python-version
8 changes: 0 additions & 8 deletions .idea/.gitignore

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/inspectionProfiles/Project_Default.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/inspectionProfiles/profiles_settings.xml

This file was deleted.

4 changes: 0 additions & 4 deletions .idea/misc.xml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/modules.xml

This file was deleted.

23 changes: 0 additions & 23 deletions .idea/padam-django-tech-test.iml

This file was deleted.

12 changes: 6 additions & 6 deletions padam_django/apps/common/management/commands/create_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@


class Command(BaseCommand):

help = 'Create test data'
help = "Create test data"

def handle(self, *args, **options):
management.call_command('create_users', number=5)
management.call_command('create_drivers', number=5)
management.call_command('create_buses', number=10)
management.call_command('create_places', number=30)
management.call_command("create_users", number=5)
management.call_command("create_drivers", number=5)
management.call_command("create_buses", number=10)
management.call_command("create_places", number=30)
management.call_command("create_bus_stops", number=40)
13 changes: 0 additions & 13 deletions padam_django/apps/fleet/admin.py

This file was deleted.

1 change: 1 addition & 0 deletions padam_django/apps/fleet/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .panels import *
38 changes: 38 additions & 0 deletions padam_django/apps/fleet/admin/formsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from django import forms
from django.core.exceptions import ValidationError


class ScheduledStopInlineFormSet(forms.models.BaseInlineFormSet):
def clean(self):
super().clean()

# Validate non-overlapping shift schedule for current instance driver and bus
times = [
form.cleaned_data["time"]
for form in self.forms
if form.cleaned_data.get("time", None)
]

if times and len(times) >= 2:
departure = min(times)
arrival = max(times)

if (
self.instance.driver
and self.instance.driver.shifts.exclude(pk=self.instance.pk)
.overlapping(departure, arrival)
.exists()
):
raise ValidationError(
"The selected driver already has a shift overlapping this one"
)

if (
self.instance.bus
and self.instance.bus.shifts.exclude(pk=self.instance.pk)
.overlapping(departure, arrival)
.exists()
):
raise ValidationError(
"The selected bus already has a shift overlapping this one"
)
14 changes: 14 additions & 0 deletions padam_django/apps/fleet/admin/inlines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.contrib import admin

from padam_django.apps.fleet import models
from padam_django.apps.fleet.admin.formsets import ScheduledStopInlineFormSet


class ScheduledStopInlineAdmin(admin.TabularInline):
formset = ScheduledStopInlineFormSet
model = models.BusShiftScheduledStop
min_num = 2

def get_formset(self, request, obj=None, **kwargs):
kwargs.update(validate_min=True)
return super().get_formset(request, obj, **kwargs)
21 changes: 21 additions & 0 deletions padam_django/apps/fleet/admin/panels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.contrib import admin

from padam_django.apps.fleet import models
from padam_django.apps.fleet.admin.inlines import ScheduledStopInlineAdmin


@admin.register(models.Bus)
class BusAdmin(admin.ModelAdmin):
pass


@admin.register(models.Driver)
class DriverAdmin(admin.ModelAdmin):
pass


@admin.register(models.BusShift)
class BusShiftAdmin(admin.ModelAdmin):
list_display = ("pk", "bus", "driver", "departure", "arrival")
fields = ("bus", "driver")
inlines = (ScheduledStopInlineAdmin,)
12 changes: 10 additions & 2 deletions padam_django/apps/fleet/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from . import models


fake = Faker(['fr'])
fake = Faker(["fr"])


class DriverFactory(factory.django.DjangoModelFactory):
user = factory.SubFactory('padam_django.apps.users.factories.UserFactory')
user = factory.SubFactory("padam_django.apps.users.factories.UserFactory")

class Meta:
model = models.Driver
Expand All @@ -19,3 +19,11 @@ class BusFactory(factory.django.DjangoModelFactory):

class Meta:
model = models.Bus


class BusStopFactory(factory.django.DjangoModelFactory):
name = factory.LazyFunction(fake.address)
place = factory.SubFactory("padam_django.apps.geography.factories.PlaceFactory")

class Meta:
model = models.BusStop
12 changes: 12 additions & 0 deletions padam_django/apps/fleet/management/commands/create_bus_stops.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from padam_django.apps.common.management.base import CreateDataBaseCommand

from padam_django.apps.fleet.factories import BusStopFactory


class Command(CreateDataBaseCommand):
help = "Create few bus stops"

def handle(self, *args, **options):
super().handle(*args, **options)
self.stdout.write(f"Creating {self.number} bus stops ...")
BusStopFactory.create_batch(size=self.number)
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Generated by Django 3.2.5 on 2024-09-24 13:04

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


class Migration(migrations.Migration):
dependencies = [
("geography", "0001_initial"),
("fleet", "0002_auto_20211109_1456"),
]

operations = [
migrations.CreateModel(
name="BusShift",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"bus",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="shifts",
related_query_name="shift",
to="fleet.bus",
),
),
(
"driver",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="shifts",
related_query_name="shift",
to="fleet.driver",
),
),
],
options={
"verbose_name": "Bus shift",
"verbose_name_plural": "Bus shifts",
},
),
migrations.CreateModel(
name="BusStop",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"name",
models.CharField(
max_length=200, verbose_name="Name of the bus stop"
),
),
(
"place",
models.OneToOneField(
on_delete=django.db.models.deletion.PROTECT,
related_name="bus_stop",
to="geography.place",
),
),
],
options={
"verbose_name": "Bus stop",
"verbose_name_plural": "Bus stops",
},
),
migrations.CreateModel(
name="BusShiftScheduledStop",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"time",
models.TimeField(verbose_name="Time of passage through the stop"),
),
(
"shift",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="scheduled_stops",
related_query_name="scheduled_stop",
to="fleet.busshift",
),
),
(
"stop",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="fleet.busstop"
),
),
],
options={
"ordering": ("time",),
},
),
migrations.AddField(
model_name="busshift",
name="stops",
field=models.ManyToManyField(
related_name="shifts",
related_query_name="shift",
through="fleet.BusShiftScheduledStop",
to="fleet.BusStop",
),
),
migrations.AddConstraint(
model_name="busshiftscheduledstop",
constraint=models.UniqueConstraint(
fields=("stop", "shift"), name="unique_for_stop_shift"
),
),
migrations.AddConstraint(
model_name="busshiftscheduledstop",
constraint=models.UniqueConstraint(
fields=("shift", "time"), name="unique_for_shift_time"
),
),
]
Loading