diff --git a/padam_django/apps/geography/admin.py b/padam_django/apps/geography/admin.py index e0334458..83e618e7 100644 --- a/padam_django/apps/geography/admin.py +++ b/padam_django/apps/geography/admin.py @@ -6,3 +6,18 @@ @admin.register(models.Place) class PlaceAdmin(admin.ModelAdmin): pass + +@admin.register(models.BusStop) +class BusStopAdmin(admin.ModelAdmin): + pass + + +class BusShiftStopInline(admin.TabularInline): + model = models.BusShiftStop + fields = ['bus_stop', 'order', 'scheduled_time'] + + +@admin.register(models.BusShift) +class BusShiftAdmin(admin.ModelAdmin): + list_display = ['id', 'bus', 'driver', 'departure_time', 'arrival_time', 'duration'] + inlines = [BusShiftStopInline] \ No newline at end of file diff --git a/padam_django/apps/geography/migrations/0002_busstop.py b/padam_django/apps/geography/migrations/0002_busstop.py new file mode 100644 index 00000000..8e0ef1ba --- /dev/null +++ b/padam_django/apps/geography/migrations/0002_busstop.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.16 on 2026-01-08 18:33 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('geography', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='BusStop', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, verbose_name='Name of the bus stop')), + ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='geography.place')), + ], + ), + ] diff --git a/padam_django/apps/geography/migrations/0003_busshift_busshiftstop_busshift_stops.py b/padam_django/apps/geography/migrations/0003_busshift_busshiftstop_busshift_stops.py new file mode 100644 index 00000000..6b449cb5 --- /dev/null +++ b/padam_django/apps/geography/migrations/0003_busshift_busshiftstop_busshift_stops.py @@ -0,0 +1,42 @@ +# Generated by Django 4.2.16 on 2026-01-08 19:06 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('fleet', '0002_auto_20211109_1456'), + ('geography', '0002_busstop'), + ] + + 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.CASCADE, related_name='shifts', to='fleet.bus')), + ('driver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shifts', to='fleet.driver')), + ], + ), + migrations.CreateModel( + name='BusShiftStop', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order', models.PositiveIntegerField(verbose_name='Stop order in the shift')), + ('scheduled_time', models.DateTimeField(verbose_name='Scheduled time at this stop')), + ('bus_shift', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='geography.busshift')), + ('bus_stop', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='geography.busstop')), + ], + options={ + 'ordering': ['order'], + 'unique_together': {('bus_shift', 'order'), ('bus_shift', 'bus_stop')}, + }, + ), + migrations.AddField( + model_name='busshift', + name='stops', + field=models.ManyToManyField(related_name='shifts', through='geography.BusShiftStop', to='geography.busstop'), + ), + ] diff --git a/padam_django/apps/geography/models.py b/padam_django/apps/geography/models.py index e566ee2b..9363f83d 100644 --- a/padam_django/apps/geography/models.py +++ b/padam_django/apps/geography/models.py @@ -13,3 +13,55 @@ class Meta: def __str__(self): return f"Place: {self.name} (id: {self.pk})" + + +class BusStop(models.Model): + name = models.CharField("Name of the bus stop", max_length=50) + place = models.ForeignKey(Place, on_delete=models.CASCADE) + + def __str__(self): + return f"Bus stop: {self.name} (id: {self.pk})" + + +class BusShift(models.Model): + """Represents a bus shift (trajet de bus)""" + bus = models.ForeignKey('fleet.Bus', on_delete=models.CASCADE, related_name='shifts') + driver = models.ForeignKey('fleet.Driver', on_delete=models.CASCADE, related_name='shifts') + stops = models.ManyToManyField(BusStop, through='BusShiftStop', related_name='shifts') + + def __str__(self): + return f"Shift {self.pk}: Bus {self.bus.licence_plate} - Driver {self.driver.user.username}" + + @property + def departure_time(self): + """Returns the time of the first stop""" + first_stop = self.busshiftstop_set.first() + return first_stop.scheduled_time if first_stop else None + + @property + def arrival_time(self): + """Returns the time of the last stop""" + last_stop = self.busshiftstop_set.last() + return last_stop.scheduled_time if last_stop else None + + @property + def duration(self): + """Returns the total duration of the shift""" + if self.departure_time and self.arrival_time: + return self.arrival_time - self.departure_time + return None + + +class BusShiftStop(models.Model): + """Represents a stop during a bus shift with order and time""" + bus_shift = models.ForeignKey(BusShift, on_delete=models.CASCADE) + bus_stop = models.ForeignKey(BusStop, on_delete=models.CASCADE) + order = models.PositiveIntegerField("Stop order in the shift") + scheduled_time = models.DateTimeField("Scheduled time at this stop") + + class Meta: + ordering = ['order'] + unique_together = (('bus_shift', 'order'), ('bus_shift', 'bus_stop')) + + def __str__(self): + return f"Shift {self.bus_shift.pk} - Stop {self.order}: {self.bus_stop.name} at {self.scheduled_time}" \ No newline at end of file