from datetime import datetime, timedelta, timezone from decimal import Decimal from django.contrib.auth.models import User, Group from django.shortcuts import get_object_or_404 from rest_framework import serializers from caremyway.api.models import UserInfo, Client, Provider, WorkType, Manage, Price, Shift class UserInfoSerializer(serializers.ModelSerializer): class Meta: model = UserInfo fields = ('dob', 'address1', 'address2', 'city', 'province', 'postal_code', 'phone_number') def create(self, validated_data): validated_data['user'] = self.context['request'].user return serializers.ModelSerializer.create(self, validated_data) class WorkTypeSerializer(serializers.ModelSerializer): class Meta: model = WorkType fields = ('uuid', 'color', 'label', 'deleted') read_only_fields = ('deleted',) def create(self, validated_data): validated_data['client'] = self.context['request'].user.client return serializers.ModelSerializer.create(self, validated_data) def update(self, instance, validated_data): if 'label' in validated_data: raise serializers.ValidationError("Cannot update field.") return super().update(instance, validated_data) class PriceSerializer(serializers.ModelSerializer): get_employee_uuid = serializers.UUIDField(write_only=True) get_work_type_uuid = serializers.UUIDField(write_only=True) work_type = WorkTypeSerializer(read_only=True) class Meta: model = Price fields = ('uuid', 'get_employee_uuid', 'get_work_type_uuid', 'work_type', 'amount', 'deleted') read_only_fields = ('deleted',) depth = 1 def create(self, validated_data): user = self.context['request'].user if not Client.objects.filter(user=user).exists(): raise serializers.ValidationError("User is not a client.") client = user.client manage_objs = Manage.objects.filter(deleted=False).filter(client=client) employee_uuid = validated_data.pop('get_employee_uuid') employee = get_object_or_404(manage_objs, uuid=employee_uuid) worktype_objs = WorkType.objects.filter(deleted=False).filter(client=client) work_type_uuid = validated_data.pop('get_work_type_uuid') work_type = get_object_or_404(worktype_objs, uuid=work_type_uuid) if not employee.approved: raise serializers.ValidationError("Employee hasn't approved employment yet.") if Price.objects.filter(deleted=False) \ .filter(work_type=work_type) \ .filter(management=employee).exists(): raise serializers.ValidationError("Price for this work already defined.") validated_data['management'] = employee validated_data['work_type'] = work_type return serializers.ModelSerializer.create(self, validated_data) class EmployeeUserSerializer(serializers.ModelSerializer): userinfo = UserInfoSerializer(read_only=True) class Meta: model = User fields = ('is_active', 'first_name', 'last_name', 'email', 'userinfo') depth = 1 class EmployeeSerializer(serializers.ModelSerializer): provider_email = serializers.EmailField(write_only=True) provider = serializers.SerializerMethodField() prices = PriceSerializer(many=True, read_only=True) class Meta: model = Manage fields = ('uuid', 'provider', 'provider_email', 'note', 'approved', 'prices', 'deleted') read_only_fields = ('approved', 'deleted') def get_provider(self, obj): if obj.approved == True: user = User.objects.get(provider=obj.provider) return EmployeeUserSerializer(user).data else: return obj.provider.user.email def create(self, validated_data): user = self.context['request'].user if not Client.objects.filter(user=user).exists(): raise serializers.ValidationError("User is not a client.") client = user.client provider_email = validated_data.pop('provider_email') provider = get_object_or_404(Provider, user__email=provider_email) if Manage.objects.filter(deleted=False) \ .filter(provider=provider) \ .filter(client=client).exists(): raise serializers.ValidationError("Employee already added.") validated_data['client'] = client validated_data['provider'] = provider return serializers.ModelSerializer.create(self, validated_data) class ClientSerializer(serializers.ModelSerializer): work_types = WorkTypeSerializer(many=True, read_only=True) employees = EmployeeSerializer(many=True, read_only=True) class Meta: model = Client fields = ('business_number', 'alt_name', 'alt_address1', 'alt_address2', 'alt_city', 'alt_province', 'alt_phone_number', 'work_types', 'employees') def create(self, validated_data): user = self.context['request'].user if Provider.objects.filter(user=user).exists(): raise serializers.ValidationError("User is already a Provider.") validated_data['user'] = user return serializers.ModelSerializer.create(self, validated_data) class EmployerUserSerializer(serializers.ModelSerializer): userinfo = UserInfoSerializer(read_only=True) class Meta: model = User fields = ('is_active', 'first_name', 'last_name', 'email', 'userinfo') depth = 1 class EmployerSerializer(serializers.ModelSerializer): client = serializers.SerializerMethodField() prices = PriceSerializer(many=True, read_only=True) class Meta: model = Manage fields = ('uuid', 'client', 'note', 'approved', 'prices', 'deleted') read_only_fields = ('note', 'deleted') def get_client(self, obj): if obj.approved == True: user = User.objects.get(client=obj.client) return EmployerUserSerializer(user).data else: return obj.client.user.first_name + ' ' + obj.client.user.last_name class ProviderSerializer(serializers.ModelSerializer): employers = EmployerSerializer(many=True, read_only=True) class Meta: model = Provider fields = ('sin', 'cert_title1', 'cert_date1', 'cert_institution1', 'cert_title2', 'cert_date2', 'cert_institution2', 'cert_title3', 'cert_date3', 'cert_institution3', 'emerg_contact_name', 'emerg_contact_number', 'crim_record_check_date', 'employers') def create(self, validated_data): user = self.context['request'].user if Client.objects.filter(user=user).exists(): raise serializers.ValidationError("User is already a Client.") validated_data['user'] = user return serializers.ModelSerializer.create(self, validated_data) class UserSerializer(serializers.ModelSerializer): userinfo = UserInfoSerializer(read_only=True) client = ClientSerializer(read_only=True) provider = ProviderSerializer(read_only=True) class Meta: model = User fields = ('username', 'is_active', 'first_name', 'last_name', 'email', 'userinfo', 'client', 'provider') depth = 1 class ShiftSerializer(serializers.ModelSerializer): price = serializers.SerializerMethodField() amount = serializers.SerializerMethodField() def get_price(self, obj): return obj.price.uuid def get_amount(self, obj): if obj.approved_end: shift_length = obj.approved_end - obj.approved_start return Decimal(shift_length.total_seconds()) / 3600 * obj.set_price else: return None class CShiftSerializer(ShiftSerializer): get_price_uuid = serializers.UUIDField(write_only=True) class Meta: model = Shift fields = ('uuid', 'chart', 'get_price_uuid', 'price', 'set_price', 'set_start', 'set_end', 'actual_start', 'actual_end', 'approved_start', 'approved_end', 'approved_date', 'amount', 'description', 'provider_approved', 'deleted') read_only_fields = ('chart', 'price', 'set_price', 'actual_start', 'actual_end', 'approved_date', 'provider_approved', 'deleted') def create(self, validated_data): user = self.context['request'].user if not Client.objects.filter(user=user).exists(): raise serializers.ValidationError("User is not a client.") client = user.client price_objs = Price.objects.filter(deleted=False).filter(management__client=client) price_uuid = validated_data.pop('get_price_uuid') price = get_object_or_404(price_objs, uuid=price_uuid) if price.management.deleted: raise serializers.ValidationError("Employment relationship was deleted.") if price.work_type.deleted: raise serializers.ValidationError("Type of work was deleted.") if not price.management.approved: raise serializers.ValidationError("Employee hasn't approved employment yet.") now = datetime.now(timezone.utc) set_start = validated_data['set_start'] set_end = validated_data['set_end'] approved_start = validated_data['approved_start'] approved_end = validated_data['approved_end'] if approved_start or approved_end: raise serializers.ValidationError("Can't set approved time on creation.") if not set_start or not set_end: raise serializers.ValidationError("Must include shift start and end times.") if set_start > set_end: raise serializers.ValidationError("Shift ends before it starts.") if set_start > set_end - timedelta(hours=1): raise serializers.ValidationError("Shift is less than one hour long.") if set_start < now or set_end < now: raise serializers.ValidationError("Shift is in the past.") # TODO: Make sure provider isn't double-booked????? validated_data['price'] = price return serializers.ModelSerializer.create(self, validated_data) def update(self, instance, validated_data): set_start = validated_data['set_start'] set_end = validated_data['set_end'] approved_start = validated_data['approved_start'] approved_end = validated_data['approved_end'] if set_start and set_end: if instance.actual_start: raise serializers.ValidationError("Can't update after checkin.") now = datetime.now(timezone.utc) if set_start > set_end: raise serializers.ValidationError("Shift ends before it starts.") if set_start > set_end - timedelta(hours=1): raise serializers.ValidationError("Shift is less than one hour long.") if set_start < now or set_end < now: raise serializers.ValidationError("Shift is in the past.") # Reset provider approval on update instance.provider_approved = None instance.set_start = set_start instance.set_end = set_end elif approved_start and approved_end: if not instance.actual_start: raise serializers.ValidationError("Can't approve / edit time until after checkin.") if approved_start > approved_end: raise serializers.ValidationError("Shift ends before it starts.") if approved_start > approved_end - timedelta(hours=1): raise serializers.ValidationError("Shift is less than one hour long.") instance.approved_start = approved_start instance.approved_end = approved_end instance.approved_date = approved_start.date() else: raise serializers.ValidationError("Missing field.") instance.save() return instance class PShiftSerializer(ShiftSerializer): action = serializers.ChoiceField(write_only=True, allow_blank=True, choices=['checkin', 'checkout']) class Meta: model = Shift fields = ('uuid', 'action', 'chart', 'price', 'set_price', 'set_start', 'set_end', 'actual_start', 'actual_end', 'approved_start', 'approved_end', 'approved_date', 'amount', 'description', 'provider_approved', 'deleted') read_only_fields = ('uuid', 'price', 'set_price', 'set_start', 'set_end', 'actual_start', 'actual_end', 'approved_start', 'approved_end', 'approved_date', 'description', 'deleted') def update(self, instance, validated_data): provider_approved = validated_data['provider_approved'] action = validated_data['action'] chart = validated_data['chart'] if provider_approved == True: if instance.deleted: raise serializers.ValidationError("Shift was deleted.") instance.provider_approved = True elif provider_approved == False: if instance.actual_start: raise serializers.ValidationError("Can't disapprove after check in.") instance.provider_approved = False if action == 'checkin': if instance.deleted: raise serializers.ValidationError("Shift was deleted.") if not instance.provider_approved: raise serializers.ValidationError("Shift hasn't been approved by the provider..") if instance.actual_start: raise serializers.ValidationError("Already checked in.") if chart: raise serializers.ValidationError("Can only provide chart on checkout.") instance.actual_start = datetime.now(timezone.utc) instance.set_price = instance.price.amount elif action == 'checkout': if not instance.actual_start: raise serializers.ValidationError("Need to check in first.") if instance.actual_end: raise serializers.ValidationError("Already checked out.") if not chart: raise serializers.ValidationError("No chart info provided.") instance.actual_end = datetime.now(timezone.utc) instance.chart = chart instance.save() return instance class TimeSheetSerializer(serializers.Serializer): class ShiftSerializer(serializers.Serializer): date = serializers.DateField() start = serializers.DateTimeField() end = serializers.DateTimeField() hours = serializers.DecimalField(max_digits=8, decimal_places=2) rate = serializers.DecimalField(max_digits=8, decimal_places=2) amount = serializers.DecimalField(max_digits=8, decimal_places=2) work = serializers.CharField() management = serializers.CharField() client = serializers.CharField() provider = serializers.CharField() payday = serializers.DateField() paystart = serializers.DateField() payend = serializers.DateField() shifts = ShiftSerializer(many=True) class RecordSheetSerializer(serializers.Serializer): class RecordSerializer(serializers.Serializer): payday = serializers.DateField() reg_pay = serializers.DecimalField(max_digits=10, decimal_places=2) vac_pay = serializers.DecimalField(max_digits=10, decimal_places=2) earnings = serializers.DecimalField(max_digits=10, decimal_places=2) cpp_ytd = serializers.DecimalField(max_digits=10, decimal_places=2) cpp = serializers.DecimalField(max_digits=10, decimal_places=2) ei_ytd = serializers.DecimalField(max_digits=10, decimal_places=2) ei = serializers.DecimalField(max_digits=10, decimal_places=2) taxable_income = serializers.DecimalField(max_digits=10, decimal_places=2) fed_tax = serializers.DecimalField(max_digits=10, decimal_places=2) fed_tax_payable = serializers.DecimalField(max_digits=10, decimal_places=2) prov_tax = serializers.DecimalField(max_digits=10, decimal_places=2) prov_tax_deduction = serializers.DecimalField(max_digits=10, decimal_places=2) income_tax = serializers.DecimalField(max_digits=10, decimal_places=2) total_deductions = serializers.DecimalField(max_digits=10, decimal_places=2) net_pay = serializers.DecimalField(max_digits=10, decimal_places=2) management = serializers.CharField() client = serializers.CharField() provider = serializers.CharField() phone_number = serializers.CharField() sin = serializers.CharField() record = RecordSerializer(many=True) class PayStubSerializer(serializers.Serializer): management = serializers.CharField() client = serializers.CharField() provider = serializers.CharField() payday = serializers.DateField() reg_pay = serializers.DecimalField(max_digits=10, decimal_places=2) vac_pay = serializers.DecimalField(max_digits=10, decimal_places=2) earnings = serializers.DecimalField(max_digits=10, decimal_places=2) cpp = serializers.DecimalField(max_digits=10, decimal_places=2) ei = serializers.DecimalField(max_digits=10, decimal_places=2) income_tax = serializers.DecimalField(max_digits=10, decimal_places=2) total_deductions = serializers.DecimalField(max_digits=10, decimal_places=2) net_pay = serializers.DecimalField(max_digits=10, decimal_places=2)