def post(self, request): stylist: Stylist = self.request.user.stylist try: appointment: Appointment = stylist.appointments.get( uuid=request.data['appointment_uuid']) except Appointment.DoesNotExist: raise ValidationError({ 'non_field_errors': [{ 'code': ErrorMessages.ERR_INVALID_APPOINTMENT_UUID }] }) serializer = AppointmentPreviewRequestSerializer(data=request.data, context={ 'stylist': stylist, 'appointment': appointment, 'force_start': True }) serializer.is_valid(raise_exception=True) client_uuid = serializer.validated_data.pop('client_uuid', None) client: Optional[Client] = None if client_uuid: client = stylist.get_preferred_clients().get(uuid=client_uuid) preview_request = AppointmentPreviewRequest( **serializer.validated_data) response_serializer = AppointmentPreviewResponseSerializer( build_appointment_preview_dict(stylist=stylist, client=client, preview_request=preview_request)) return Response(response_serializer.data)
def test_with_existing_client(self): stylist: Stylist = G(Stylist) service: StylistService = G(StylistService, stylist=stylist, regular_price=20) client: Client = G(Client) preview_request = AppointmentPreviewRequest( services=[{ 'service_uuid': service.uuid }], datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC), has_tax_included=False, has_card_fee_included=False, ) preview_dict = build_appointment_preview_dict( stylist=stylist, client=client, preview_request=preview_request) assert (preview_dict.conflicts_with.count() == 0) # we can't compare QuerySets, so will just replace the field preview_dict = preview_dict._replace(conflicts_with=None) assert (preview_dict == AppointmentPreviewResponse( grand_total=19, total_client_price_before_tax=19, total_tax=calculate_tax(Decimal(19), tax_rate=stylist.tax_rate), total_card_fee=calculate_card_fee(Decimal(19), card_fee=stylist.card_fee), duration=stylist.service_time_gap, conflicts_with=None, has_tax_included=False, has_card_fee_included=False, total_discount_percentage=5, total_discount_amount=1, services=[ AppointmentServicePreview( service_name=service.name, service_uuid=service.uuid, client_price=19, regular_price=service.regular_price, duration=service.duration, is_original=True, uuid=None, ), ], stylist=stylist, datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC), status=AppointmentStatus.NEW, tax_percentage=float(stylist.tax_rate) * 100, card_fee_percentage=float(stylist.card_fee) * 100, ))
def test_bad_appointment_uuid(self): stylist = G(Stylist) appointment = G(Appointment, datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC)) preview_request = AppointmentPreviewRequest( services=[], datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC), has_tax_included=False, has_card_fee_included=False, appointment_uuid=appointment.uuid) with pytest.raises(Http404): build_appointment_preview_dict(stylist=stylist, client=None, preview_request=preview_request)
def post(self, request): client: Client = self.request.user.client serializer = AppointmentPreviewRequestSerializer( data=request.data, context=self.get_serializer_context()) serializer.is_valid(raise_exception=True) stylist: Stylist = get_object_or_404( Stylist, deactivated_at=None, uuid=serializer.validated_data.pop('stylist_uuid')) preview_request = AppointmentPreviewRequest( **serializer.validated_data) response_serializer = AppointmentPreviewResponseSerializer( build_appointment_preview_dict(stylist=stylist, client=client, preview_request=preview_request), context=self.get_serializer_context()) return Response(response_serializer.data)
def test_without_services(self): stylist: Stylist = G(Stylist) preview_request = AppointmentPreviewRequest( services=[], datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC), has_tax_included=False, has_card_fee_included=False, ) preview_dict = build_appointment_preview_dict( stylist=stylist, client=None, preview_request=preview_request) assert (preview_dict.conflicts_with.count() == 0) # we can't compare QuerySets, so will just replace the field preview_dict = preview_dict._replace(conflicts_with=None) assert (preview_dict == AppointmentPreviewResponse( grand_total=0, total_client_price_before_tax=0, total_tax=0, total_card_fee=0, duration=stylist.service_time_gap, conflicts_with=None, has_tax_included=False, has_card_fee_included=False, services=[], stylist=stylist, datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC), status=AppointmentStatus.NEW, total_discount_percentage=0, total_discount_amount=0, tax_percentage=float(stylist.tax_rate) * 100, card_fee_percentage=float(stylist.card_fee) * 100, ))
def test_with_existing_appointment_with_new_services(self): stylist: Stylist = G(Stylist) existing_service: StylistService = G( StylistService, stylist=stylist, regular_price=20, ) service: StylistService = G(StylistService, stylist=stylist, regular_price=50) service2: StylistService = G(StylistService, stylist=stylist, regular_price=50) appointment: Appointment = G(Appointment, stylist=stylist, datetime_start_at=datetime.datetime( 2018, 1, 1, 0, 0, tzinfo=pytz.UTC), total_discount_percentage=50, discount_type=DiscountType.WEEKDAY) appointment_service: AppointmentService = G( AppointmentService, appointment=appointment, service_uuid=existing_service.uuid, is_original=True, service_name=existing_service.name, regular_price=20, calculated_price=10, client_price=10, applied_discount=DiscountType.WEEKDAY, discount_percentage=50) preview_request = AppointmentPreviewRequest( services=[ { 'service_uuid': service.uuid }, { 'service_uuid': service2.uuid, 'client_price': 5 }, { 'service_uuid': existing_service.uuid }, ], datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC), has_tax_included=False, has_card_fee_included=False, appointment_uuid=appointment.uuid) preview_dict = build_appointment_preview_dict( stylist=stylist, client=None, preview_request=preview_request) assert (preview_dict.conflicts_with.count() == 0) # we can't compare QuerySets, so will just replace the field preview_dict = preview_dict._replace(conflicts_with=None) assert (preview_dict == AppointmentPreviewResponse( grand_total=38, total_client_price_before_tax=38, total_tax=calculate_tax(Decimal(38), tax_rate=stylist.tax_rate), total_card_fee=calculate_card_fee(Decimal(38), card_fee=stylist.card_fee), duration=stylist.service_time_gap, conflicts_with=None, has_tax_included=False, has_card_fee_included=False, services=[ AppointmentServicePreview( service_name=service.name, service_uuid=service.uuid, client_price=25, regular_price=50, duration=service.duration, is_original=False, uuid=None, ), AppointmentServicePreview( service_name=service2.name, service_uuid=service2.uuid, client_price= 3, # 50% discount should have been applied + round_half_up to $3 regular_price=50, duration=service.duration, is_original=False, uuid=None, ), AppointmentServicePreview( service_name=existing_service.name, service_uuid=existing_service.uuid, client_price=10, regular_price=20, duration=existing_service.duration, is_original=True, uuid=appointment_service.uuid, ), ], stylist=stylist, datetime_start_at=datetime.datetime(2018, 1, 1, 0, 0, tzinfo=pytz.UTC), status=appointment.status, total_discount_percentage=50, total_discount_amount=82, tax_percentage=float(stylist.tax_rate) * 100, card_fee_percentage=float(stylist.card_fee) * 100, ))