Last active
April 29, 2020 17:13
-
-
Save pmburu/05fa49c1fa55596e8a807674d50b9576 to your computer and use it in GitHub Desktop.
Revisions
-
pmburu revised this gist
Apr 29, 2020 . 1 changed file with 48 additions and 19 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ from django.urls import reverse from django.db import models from django.utils import timezone from django.core.exceptions import ValidationError # import datetime as dt # from django.db.models.signals import pre_save, post_save, post_delete import datetime @@ -111,27 +111,56 @@ def calc_booking_total(self): else: self.booking_total = 0.00 def check_time_overlap(self, fixed_start, fixed_end, new_start, new_end): time_overlap = False if new_start == fixed_end or new_end == fixed_start: # edge case time_overlap = False elif (new_start >= fixed_start and new_start <= fixed_end) or \ (new_end >= fixed_start and new_end <= fixed_end): \ # innner limits time_overlap = True elif new_start <= fixed_start and new_end >= fixed_end: \ # outter limits time_overlap = True return time_overlap def assign_driver_to_booking(self): if self.finishing_at <= self.booking_time: raise ValidationError( 'Finishing times must be after booking times' ) bookings = Booking.objects.filter( booking_date=self.booking_date, driver_id=self.driver ) # drivers = Booking.objects.filter(driver_id=self.driver) if bookings.exists(): for booking in bookings: """ Check whether date and time overlaps """ if self.check_time_overlap( booking.booking_time, booking.finishing_at, self.booking_time, self.finishing_at ): # if booking.driver is None: # """ If time overlaps, check whether there is \ # a driver assigned to that booking. If there is none, \ # assign one.""" # Booking.objects\ # .filter(id=booking.id)\ # .update(driver=booking.driver) # return booking.driver # else: """ If all drivers are allocated, raise an error \ message. """ raise ValidationError( 'All our drivers are booked at: ' + str(booking.booking_date) + ', ' + str( booking.booking_time) + '-' + str(booking.finishing_at)) def save(self, *args, **kwargs): self.calc_booking_total() self.calc_finishing_at() self.assign_driver_to_booking() super(Booking, self).save(*args, **kwargs) -
pmburu revised this gist
Apr 29, 2020 . 1 changed file with 19 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,19 @@ { "id": 27, "package": "Premium", "vehicle_type": "SUV", "client_name": "Test Client", "client_phone": "0722345678", "booking_location": "-538978, 56251817", "booking_address": "ABC Place, Hse 41", "booking_date": "2020-05-28", "booking_time": "12:00:00", "booking_status": "PENDING", "booked_at": "2020-04-29T15:17:23.660080", "finishing_at": "13:00:00", "booking_total": "3700.00", "driver": null, "client": 3, "service": 8, "extra_service": 3 } -
pmburu revised this gist
Apr 29, 2020 . 1 changed file with 13 additions and 10 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -95,13 +95,22 @@ def __str__(self): return f'{self.booking_status} order containing: \ {len(self.service.all())} service' def calc_finishing_at(self): duration = datetime.timedelta(hours=1) booking_time = self.booking_time self.finishing_at = (datetime.datetime.combine( datetime.date(1, 1, 1), booking_time) + duration).time() return self.finishing_at def calc_booking_total(self): if self.extra_service and self.service: self.booking_total = self.service.package_cost + \ self.extra_service.service_cost elif self.service: self.booking_total = self.service.package_cost else: self.booking_total = 0.00 def assign_driver_to_booking(self): """ Update booking status to \ add driver automatically to booking """ @@ -122,13 +131,7 @@ def assign_driver_to_booking(self): # return assign_booking def save(self, *args, **kwargs): self.calc_booking_total() self.calc_finishing_at() # self.assign_driver_to_booking() super(Booking, self).save(*args, **kwargs) -
pmburu created this gist
Apr 29, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,134 @@ from django.urls import reverse from django.db import models from django.utils import timezone # from datetime import datetime, timedelta # import datetime as dt # from django.db.models.signals import pre_save, post_save, post_delete import datetime from wash_authentication.models import Client, Driver # SERVICES # _________________________________________________________________________# class VehicleType(models.Model): """ Represents vehicle categories """ name = models.CharField(max_length=30, help_text='E.g. SUV') parent = models.ForeignKey('VehicleType', on_delete=models.CASCADE, null=True, blank=True) created = models.DateTimeField(default=timezone.now) updated = models.DateTimeField(blank=True, null=True) def __str__(self): return self.name class PackageDetails(models.Model): """ Represents vehcile details """ vehicle_category = models.ForeignKey( VehicleType, on_delete=models.CASCADE, related_name='wash_package', ) package_name = models.CharField(max_length=30, help_text='E.g. Deluxe') package_description = models.TextField(null=True, blank=True) package_cost = models.DecimalField(max_digits=10, decimal_places=2) created = models.DateTimeField(default=timezone.now) updated = models.DateTimeField(blank=True, null=True) def __str__(self): return self.package_name def get_absolute_url(self): return reverse("product_detail", kwargs={"pk": self.pk}) def get_price(self): return self.package_cost class ExtraService(models.Model): """ Represents extra services details """ service_name = models.CharField(max_length=30, help_text='E.g. Engine Wash') service_cost = models.DecimalField(max_digits=10, decimal_places=2) # BOOKINGS # _________________________________________________________________________# class BookingState(models.TextChoices): PENDING = 'PENDING', 'Pending' CONFIRMED = 'CONFIRMED', 'Confirmed' ON_THE_WAY = 'ON_THE_WAY', 'On The Way' IN_PROGRESS = 'IN_PROGRESS', 'In Progress' COMPLETE = 'COMPLETE', 'Complete' class Booking(models.Model): driver = models.OneToOneField(Driver, on_delete=models.CASCADE, null=True, blank=True) client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='customer') booking_location = models.CharField(max_length=250, blank=True, null=True) booking_address = models.CharField(max_length=100, blank=True, null=True) booking_date = models.DateField() booking_time = models.TimeField() service = models.ForeignKey(PackageDetails, on_delete=models.CASCADE, related_name='packages') extra_service = models.ForeignKey(ExtraService, on_delete=models.CASCADE, related_name='extra_services', null=True, blank=True) booking_status = models.CharField( max_length=15, choices=BookingState.choices, default=BookingState.PENDING ) booked_at = models.DateTimeField(default=timezone.now) finishing_at = models.TimeField() booking_total = models.DecimalField(decimal_places=2, max_digits=10) def __str__(self): return f'{self.booking_status} order containing: \ {len(self.service.all())} service' def get_finishing_at(self): duration = datetime.timedelta(hours=1) booking_time = self.booking_time self.finishing_at = (datetime.datetime.combine( datetime.date(1, 1, 1), booking_time) + duration).time() return self.finishing_at def assign_driver_to_booking(self): """ Update booking status to \ add driver automatically to booking """ if not isinstance( (self.booking_time, self.finishing_at), self.booking_date ): # if not (self.booking_time, self.finishing_at) in self.booking_date: """ Checking whether the driver is working \ or has a booking on that day and time""" if not self.driver: Booking.objects\ .select_related(self.driver.id)\ .filter(id=self.id)\ .add(driver=self.driver) # return assign_booking return self.driver # return assign_booking def save(self, *args, **kwargs): if self.extra_service and self.service: self.booking_total = self.service.package_cost + \ self.extra_service.service_cost elif self.service: self.booking_total = self.service.package_cost else: self.booking_total = 0.00 self.get_finishing_at() self.assign_driver_to_booking() super(Booking, self).save(*args, **kwargs) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,97 @@ from rest_framework import serializers from .models import ( Booking, PackageDetails, VehicleType, ExtraService ) from wash_authentication.models import ( Client, Driver ) class PackageSerializer(serializers.ModelSerializer): package_id = serializers.IntegerField(source='id') class Meta: model = PackageDetails fields = ( 'package_id', 'package_name', 'package_description', 'package_cost', ) class VehicleTypeSerializer(serializers.ModelSerializer): wash_package = PackageSerializer(many=True, read_only=True) class Meta: model = VehicleType fields = ( 'id', 'name', 'wash_package' ) class ExtraServiceSerializer(serializers.ModelSerializer): extra_service_id = serializers.IntegerField(source='id') class Meta: model = ExtraService fields = ( 'extra_service_id', 'service_name', 'service_cost', ) # BOOKING SERIALIZER # ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––# class BookingClientSerializer(serializers.ModelSerializer): class Meta: model = Client fields = ("id", "name", "phone") class BookingDriverSerializer(serializers.ModelSerializer): class Meta: model = Driver fields = ("id", "name", "phone") class BookingSerializer(serializers.ModelSerializer): package = serializers.SerializerMethodField() vehicle_type = serializers.SerializerMethodField() client_name = serializers.SerializerMethodField() client_phone = serializers.SerializerMethodField() class Meta: model = Booking fields = '__all__' # exclude = ('client',) read_only_fields = ( 'booking_total', 'booking_status', 'booked_at', 'finishing_at', 'client' ) def get_package(self, obj): return obj.service.package_name def get_vehicle_type(self, obj): return obj.service.vehicle_category.name def get_client_name(self, obj): return obj.client.name def get_client_phone(self, obj): return str(obj.client.phone) def create(self, validated_data): validated_data['client'] = self.context['request'].user booking = Booking.objects.create(**validated_data) return booking This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,144 @@ import json from django.utils import timezone from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from rest_framework.decorators import api_view from rest_framework import viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.decorators import permission_classes # from django_filters.rest_framework import DjangoFilterBackend from .serializers import ( PackageSerializer, VehicleTypeSerializer, ExtraServiceSerializer, BookingSerializer ) from .models import ( PackageDetails, VehicleType, ExtraService, Booking, BookingState ) # PACKAGE & SERVICE VIEWS # ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––# class PackageViewSet(viewsets.ModelViewSet): serializer_class = PackageSerializer permission_classes = (IsAuthenticated,) def get_queryset(self): return PackageDetails.objects.filter( pk=self.kwargs['pk']) class VehicleTypeViewSet(viewsets.ModelViewSet): queryset = VehicleType.objects.all() serializer_class = VehicleTypeSerializer permission_classes = (IsAuthenticated,) class ExtraServiceViewSet(viewsets.ModelViewSet): queryset = ExtraService.objects.all() serializer_class = ExtraServiceSerializer permission_classes = (IsAuthenticated,) # BOOKING & CART VIEWS # ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––# class BookingViewSet(viewsets.ModelViewSet): serializer_class = BookingSerializer # permission_classes = (IsAuthenticated,) queryset = ( Booking.objects .select_related('client') .prefetch_related('service') ) # filter_backends = (DjangoFilterBackend,) # filterset_fields = ('booking_status', 'client__name',) def dispatch(self, *args, **kwargs): response = super().dispatch(*args, **kwargs) return response @api_view(['GET']) @permission_classes((IsAuthenticated, )) def driver_get_ready_bookings(request): bookings = BookingSerializer( Booking.objects.filter(booking_status=BookingState.PENDING, driver=None).order_by("-id"), many=True ).data return JsonResponse({"driver_bookings": bookings}) @csrf_exempt # POST # params: access_token, order_id def driver_pick_booking(request): if request.method == "POST": # Get driver driver = request.user.driver # Check that driver only has one order if Booking.objects.filter(driver=driver).exclude( booking_status=BookingState.ON_THE_WAY ): return JsonResponse({ "status": "failed", "error": "You can only cater for one booking at a time." }) try: booking = Booking.objects.get( id=request.POST["booking_id"], driver=None, booking_status=BookingState.IN_PROGRESS ) booking.driver = driver booking.booking_status = BookingState.ON_THE_WAY booking.pickedup_at = timezone.now() booking.save() return JsonResponse({"status": "success"}) except Booking.DoesNotExist: return JsonResponse({ "status": "failed", "error": "This order has been picked up by another driver." }) return JsonResponse({}) # GET params: access_token @api_view(['GET']) @permission_classes((IsAuthenticated, )) def driver_get_latest_booking(request): # Get driver driver = request.user.driver booking = BookingSerializer( Booking.objects.filter(driver=driver).order_by("booked_at").last() ).data return JsonResponse({"next_jobs": booking}) # POST params: access_token, order_id @csrf_exempt def driver_complete_booking(request): # Get driver driver = request.user.driver booking = Booking.objects.get(id=request.POST["booking_id"], driver=driver) booking.status = BookingState.COMPLETE booking.save() return JsonResponse({"status": "success"})