Example #1
0
 def create_reservation(self, profile, resource, start_when, end_when):
     res = Reservation(
                 profile=profile,
                 resource=resource,
                 start_when=start_when,
                 end_when=end_when)
     res.save()
     return res
def test_valid_reservation_duration_with_slot_size(resource_with_opening_hours):
    resource_with_opening_hours.min_period = datetime.timedelta(hours=1)
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=30)
    resource_with_opening_hours.save()

    tz = timezone.get_current_timezone()
    begin = tz.localize(datetime.datetime(2115, 6, 1, 8, 0, 0))
    end = begin + datetime.timedelta(hours=2, minutes=30)

    reservation = Reservation(resource=resource_with_opening_hours, begin=begin, end=end)
    reservation.clean()
Example #3
0
    def check_price(self, request):
        # validate incoming Order and OrderLine data
        write_serializer = PriceEndpointOrderSerializer(data=request.data)
        write_serializer.is_valid(raise_exception=True)

        # build Order and OrderLine objects in memory only
        order_data = write_serializer.validated_data
        order_lines_data = order_data.pop('order_lines')
        begin = order_data.pop('begin')
        end = order_data.pop('end')
        order = Order(**order_data)
        order_lines = [
            OrderLine(order=order, **data) for data in order_lines_data
        ]

        # store the OrderLine objects in the Order object so that we can use
        # those when calculating prices
        order._in_memory_order_lines = order_lines

        # order line price calculations need a dummy reservation from which they
        # get begin and end times from
        reservation = Reservation(begin=begin, end=end)
        order.reservation = reservation

        # serialize the in-memory objects
        read_serializer = PriceEndpointOrderSerializer(order)
        order_data = read_serializer.data
        order_data['order_lines'] = [
            OrderLineSerializer(ol).data for ol in order_lines
        ]
        order_data.update({'begin': begin, 'end': end})

        return Response(order_data, status=200)
def test_invalid_reservation_duration_with_slot_size(resource_with_opening_hours):
    activate('en')

    resource_with_opening_hours.min_period = datetime.timedelta(hours=1)
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=30)
    resource_with_opening_hours.save()

    tz = timezone.get_current_timezone()
    begin = tz.localize(datetime.datetime(2115, 6, 1, 8, 0, 0))
    end = begin + datetime.timedelta(hours=2, minutes=45)

    reservation = Reservation(resource=resource_with_opening_hours, begin=begin, end=end)

    with pytest.raises(ValidationError) as error:
        reservation.clean()
    assert error.value.code == 'invalid_time_slot'
Example #5
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user

        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied()

        if data['end'] < timezone.now():
            raise ValidationError(_('You cannot make a reservation in the past'))

        # normal users cannot make reservations for other people
        if not resource.is_admin(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation, request_user, data=data)

        if 'comments' in data:
            if not resource.is_admin(request_user):
                raise ValidationError(dict(comments=_('Only allowed to be set by staff members')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None:
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        data.pop('staff_event', None)
        instance = Reservation(**data)
        instance.clean(original_reservation=reservation)

        return data
def test_admin_may_bypass_min_period(resource_with_opening_hours, user):
    """
    Admin users should be able to bypass min_period,
    and their minimum reservation time should be limited by slot_size
    """
    activate('en')

    # min_period is bypassed respecting slot_size restriction
    resource_with_opening_hours.min_period = datetime.timedelta(hours=1)
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=30)
    resource_with_opening_hours.save()

    tz = timezone.get_current_timezone()
    begin = tz.localize(datetime.datetime(2115, 6, 1, 8, 0, 0))
    end = begin + datetime.timedelta(hours=0, minutes=30)

    UnitAuthorization.objects.create(
        subject=resource_with_opening_hours.unit,
        level=UnitAuthorizationLevel.admin,
        authorized=user,
    )

    reservation = Reservation(resource=resource_with_opening_hours, begin=begin, end=end, user=user)
    reservation.clean()

    # min_period is bypassed and slot_size restriction is violated
    resource_with_opening_hours.slot_size = datetime.timedelta(minutes=25)
    resource_with_opening_hours.save()

    with pytest.raises(ValidationError) as error:
        reservation.clean()
    assert error.value.code == 'invalid_time_slot'
Example #7
0
    def create_respa_outlook_reservation(self, appointment, reservation,
                                         email):
        if not appointment:
            return
        if not reservation:
            if not email:
                return
            reservation = Reservation(resource=self.resource,
                                      begin=appointment.start,
                                      end=appointment.end,
                                      reserver_email_address=email,
                                      state=Reservation.CONFIRMED)
            reservation.clean()
            reservation.save()
            ret = send_respa_mail(email_address=email,
                                  subject="Reservation created",
                                  body="Reservation via outlook created")
            print(ret[0], ret[1])

        RespaOutlookReservation(
            name='%s (%s)' %
            (reservation.reserver_email_address, self.resource.name),
            exchange_id=appointment.id,
            exchange_changekey=appointment.changekey,
            reservation=reservation).save()
Example #8
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user

        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied()

        if data['end'] < timezone.now():
            raise ValidationError(
                _('You cannot make a reservation in the past'))

        if not resource.is_admin(request_user):
            reservable_before = resource.get_reservable_before()
            if reservable_before and data['begin'] >= reservable_before:
                raise ValidationError(
                    _('The resource is reservable only before %(datetime)s' %
                      {'datetime': reservable_before}))

        # normal users cannot make reservations for other people
        if not resource.is_admin(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation,
                                             request_user,
                                             data=data)

        if 'comments' in data:
            if not resource.is_admin(request_user):
                raise ValidationError(
                    dict(
                        comments=_('Only allowed to be set by staff members')))

        if 'access_code' in data:
            if data['access_code'] == None:
                data['access_code'] = ''

            access_code_enabled = resource.is_access_code_enabled()

            if not access_code_enabled and data['access_code']:
                raise ValidationError(
                    dict(access_code=_(
                        'This field cannot have a value with this resource')))

            if access_code_enabled and reservation and data[
                    'access_code'] != reservation.access_code:
                raise ValidationError(
                    dict(access_code=_('This field cannot be changed')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None:
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        data.pop('staff_event', None)
        instance = Reservation(**data)
        try:
            instance.clean(original_reservation=reservation)
        except DjangoValidationError as exc:

            # Convert Django ValidationError to DRF ValidationError so that in the response
            # field specific error messages are added in the field instead of in non_field_messages.
            if not hasattr(exc, 'error_dict'):
                raise ValidationError(exc)
            error_dict = {}
            for key, value in exc.error_dict.items():
                error_dict[key] = [error.message for error in value]
            raise ValidationError(error_dict)

        return data
    def test_reservation(self):
        r1a = Resource.objects.get(id='r1a')
        r1b = Resource.objects.get(id='r1b')

        tz = timezone.get_current_timezone()
        begin = tz.localize(datetime.datetime(2116, 6, 1, 8, 0, 0))
        end = begin + datetime.timedelta(hours=2)

        reservation = Reservation.objects.create(resource=r1a, begin=begin, end=end)
        reservation.clean()

        # Attempt overlapping reservation
        with self.assertRaises(ValidationError):
            reservation = Reservation(resource=r1a, begin=begin, end=end)
            reservation.clean()

        valid_begin = begin + datetime.timedelta(hours=3)
        valid_end = end + datetime.timedelta(hours=3)

        # Attempt incorrectly aligned begin time
        with self.assertRaises(ValidationError):
            reservation = Reservation(resource=r1a, begin=valid_begin + datetime.timedelta(minutes=1), end=valid_end)
            reservation.clean()

        # Attempt incorrectly aligned end time
        with self.assertRaises(ValidationError):
            reservation = Reservation(resource=r1a, begin=valid_begin, end=valid_end + datetime.timedelta(minutes=1))
            reservation.clean()

        # Attempt reservation that starts before the resource opens
        # Should not raise an exception as this check isn't included in model clean
        reservation = Reservation(
            resource=r1a,
            begin=begin - datetime.timedelta(hours=1),
            end=begin
        )
        reservation.clean()

        begin = tz.localize(datetime.datetime(2116, 6, 1, 16, 0, 0))
        end = begin + datetime.timedelta(hours=2)

        # Make a reservation that ends when the resource closes
        reservation = Reservation(resource=r1a, begin=begin, end=end)
        reservation.clean()

        # Attempt reservation that ends after the resource closes
        # Should not raise an exception as this check isn't included in model clean
        reservation = Reservation(resource=r1a, begin=begin, end=end + datetime.timedelta(hours=1))
        reservation.clean()
Example #10
0
 def create_item(self, item):
     reservation = Reservation()
     reservation.resource_id = self.__resource_id
     reservation.reserver_email_address = item.reserver_email_address
     reservation.reserver_phone_number = item.reserver_phone_number
     reservation.reserver_name = item.reserver_name
     reservation.begin = item.begin
     reservation.end = item.end
     reservation._from_o365_sync = True
     reservation.set_state(Reservation.CONFIRMED, None)
     reservation.save()
     return reservation.id, reservation_change_key(item)
Example #11
0
    def create(self, request):
        stack = request.data.pop('reservation_stack')
        if 'resource' in stack[0]:
            stack[0].pop('resource')
        if len(stack) > 100:
            return JsonResponse(
                {
                    'status':
                    'false',
                    'recurring_validation_error':
                    _('Reservation failed. Too many reservations at once.'),
                },
                status=400)
        data = {**request.data}
        data.update({'user': request.user})
        resource_id = data.get('resource')
        try:
            for key in stack:
                begin = key.get('begin')
                end = key.get('end')
                if begin is None or end is None:
                    return JsonResponse(
                        {
                            'status':
                            'false',
                            'recurring_validation_error':
                            _('Reservation failed. Begin or end time is missing.'
                              )
                        },
                        status=400)
            reservations = []
            for key in stack:
                begin = parse_datetime(key.get('begin'))
                end = parse_datetime(key.get('end'))
                try:
                    resource = Resource.objects.get(id=resource_id)
                except:
                    raise
                data['resource'] = resource
                res = Reservation(**data)
                res.begin = begin
                res.end = end
                if resource.validate_reservation_period(res, res.user):
                    return JsonResponse(
                        {
                            'status':
                            'false',
                            'recurring_validation_error':
                            _('Reservation failed. Make sure reservation period is correct.'
                              )
                        },
                        status=400)
                if resource.validate_max_reservations_per_user(res.user):
                    return JsonResponse(
                        {
                            'status':
                            'false',
                            'recurring_validation_error':
                            _('Reservation failed. Too many reservations at once.'
                              )
                        },
                        status=400)
                if resource.check_reservation_collision(begin, end, res):
                    return JsonResponse(
                        {
                            'status':
                            'false',
                            'recurring_validation_error':
                            _('Reservation failed. Overlap with existing reservations.'
                              )
                        },
                        status=400)
                reservations.append(res)
            reservation_dates_context = {'dates': []}
            """
            {% if bulk_email_context is defined %}
                {% for date in bulk_email_context['dates'] %}
                    Alku: {{ date.get('begin') }}
                    Loppu {{ date.get('end') }}
                {% endfor %}
            {% endif %}
            """
            for res in reservations:
                res.state = 'confirmed'
                if resource.validate_reservation_period(res, res.user):
                    return JsonResponse(
                        {
                            'status':
                            'false',
                            'recurring_validation_error':
                            _('Reservation failed. Make sure reservation period is correct.'
                              )
                        },
                        status=400)
                if resource.validate_max_reservations_per_user(res.user):
                    return JsonResponse(
                        {
                            'status':
                            'false',
                            'recurring_validation_error':
                            _('Reservation failed. Too many reservations at once.'
                              )
                        },
                        status=400)
                if resource.check_reservation_collision(begin, end, res):
                    return JsonResponse(
                        {
                            'status':
                            'false',
                            'recurring_validation_error':
                            _('Reservation failed. Overlap with existing reservations.'
                              )
                        },
                        status=400)
                res.save()
                reservation_dates_context['dates'].append({
                    'begin':
                    dateparser(reservations[0].begin, res.begin),
                    'end':
                    dateparser(reservations[0].end, res.end)
                })

            reservation_dates_context.update({
                'first_reservation': {
                    'begin':
                    dateparser(reservations[0].begin, reservations[0].begin),
                    'end':
                    dateparser(reservations[0].end, reservations[0].end)
                }
            })
            reservation_dates_context.update({
                'last_reservation': {
                    'begin':
                    dateparser(reservations[0].begin,
                               reservations[len(reservations) - 1].begin),
                    'end':
                    dateparser(reservations[0].end,
                               reservations[len(reservations) - 1].end)
                }
            })
            res = reservations[0]
            url = ''.join([
                request.is_secure() and 'https' or 'http',
                get_current_site(request).domain, '/v1/', 'reservation/',
                str(res.id), '/'
            ])
            ical_file = build_reservations_ical_file(reservations)
            attachment = ('reservation.ics', ical_file, 'text/calendar')
            res.send_reservation_mail(
                NotificationType.RESERVATION_BULK_CREATED,
                action_by_official=res.user.is_staff,
                attachments=[attachment],
                extra_context=reservation_dates_context)
            return JsonResponse(data={
                **ReservationSerializer(context={
                    'request':
                    self.request if self.request else request
                }).to_representation(res)
            },
                                status=200)
        except Exception as ex:
            return JsonResponse(
                {
                    'status':
                    'false',
                    'recurring_validation_error':
                    'Reservation failed. Try again later.'
                },
                status=500)
Example #12
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user
        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource
            data.update({'resource': resource})

        if not data.get('begin', None):
            data.update({'begin': reservation.begin})

        if not data.get('end', None):
            data.update({'end': reservation.end})

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied(
                _('You are not allowed to make reservations in this resource.')
            )

        if data['end'] < timezone.now():
            raise ValidationError(
                _('You cannot make a reservation in the past'))

        if resource.min_age and is_underage(request_user, resource.min_age):
            raise PermissionDenied(
                _('You have to be over %s years old to reserve this resource' %
                  (resource.min_age)))

        if resource.max_age and is_overage(request_user, resource.max_age):
            raise PermissionDenied(
                _('You have to be under %s years old to reserve this resource'
                  % (resource.max_age)))

        is_resource_admin = resource.is_admin(request_user)
        is_resource_manager = resource.is_manager(request_user)

        if not isinstance(request_user, AnonymousUser):
            if request_user.preferred_language is None:
                request_user.preferred_language = settings.LANGUAGES[0][0]
                request_user.save()

        if not resource.can_ignore_opening_hours(request_user):
            reservable_before = resource.get_reservable_before()
            if reservable_before and data['begin'] >= reservable_before:
                raise ValidationError(
                    _('The resource is reservable only before %(datetime)s' %
                      {'datetime': reservable_before}))
            reservable_after = resource.get_reservable_after()
            if reservable_after and data['begin'] < reservable_after:
                raise ValidationError(
                    _('The resource is reservable only after %(datetime)s' %
                      {'datetime': reservable_after}))

        # Check given home municipality is included in resource's home municipality set
        if 'home_municipality' in data:
            included = resource.get_included_home_municipality_names()
            found = False

            for municipality in included:
                if data['home_municipality'].id == municipality['id']:
                    found = True
                    break

            if not found:
                raise ValidationError(
                    _('Home municipality has to be one of the included home municipality options'
                      ))

        # normal users cannot make reservations for other people
        if not resource.can_create_reservations_for_other_users(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation,
                                             request_user,
                                             data=data)
        reserver_phone_number = data.get('reserver_phone_number', '')
        if reserver_phone_number.startswith('+'):
            if not region_code_for_country_code(
                    phonenumbers.parse(reserver_phone_number).country_code):
                raise ValidationError(
                    dict(reserver_phone_number=_('Invalid country code')))

        if data.get('staff_event', False):
            if not resource.can_create_staff_event(request_user):
                raise ValidationError(
                    dict(staff_event=_(
                        'Only allowed to be set by resource managers')))

        if 'type' in data:
            if (data['type'] != Reservation.TYPE_NORMAL
                    and not resource.can_create_special_type_reservation(
                        request_user)):
                raise ValidationError({
                    'type':
                    _('You are not allowed to make a reservation of this type')
                })

        if 'comments' in data:
            if not resource.can_comment_reservations(request_user):
                raise ValidationError(
                    dict(
                        comments=_('Only allowed to be set by staff members')))

        if 'access_code' in data:
            if data['access_code'] is None:
                data['access_code'] = ''

            access_code_enabled = resource.is_access_code_enabled()

            if not access_code_enabled and data['access_code']:
                raise ValidationError(
                    dict(access_code=_(
                        'This field cannot have a value with this resource')))

            if access_code_enabled and reservation and data[
                    'access_code'] != reservation.access_code:
                raise ValidationError(
                    dict(access_code=_('This field cannot be changed')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None and not isinstance(request_user, AnonymousUser):
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        instance = Reservation(**data)
        try:
            instance.clean(original_reservation=reservation, user=request_user)
        except DjangoValidationError as exc:
            # Convert Django ValidationError to DRF ValidationError so that in the response
            # field specific error messages are added in the field instead of in non_field_messages.
            if not hasattr(exc, 'error_dict'):
                raise ValidationError(exc)
            error_dict = {}
            for key, value in exc.error_dict.items():
                error_dict[key] = [error.message for error in value]
            raise ValidationError(error_dict)
        return data
Example #13
0
def save_reservation(
    data,
    hvara_reservations,
    user_objects_by_email,
    missing_users,
    catering_provider,
):
    if not data['resource']['object']:
        return

    origin_id = 'hvara:%s' % data['VarausId']
    res = hvara_reservations.get(origin_id)
    try:
        res = Reservation.objects.get(origin_id=origin_id)
    except Reservation.DoesNotExist:
        res = Reservation(origin_id=origin_id)

    res.begin = local_tz.localize(
        datetime.strptime(data['AlkuAika'], "%Y-%m-%dT%H:%M:%S"))
    res.end = local_tz.localize(
        datetime.strptime(data['LoppuAika'], "%Y-%m-%dT%H:%M:%S"))
    res.event_subject = data['Tilaisuus'].strip()
    res.host_name = data['Isanta'].strip()
    res.created_at = local_tz.localize(
        datetime.strptime(data['Perustettu'], "%Y-%m-%dT%H:%M:%S"))
    res.modified_at = local_tz.localize(
        datetime.strptime(data['Muutettu'], "%Y-%m-%dT%H:%M:%S"))
    res.number_of_participants = int(data['OsallistujaLkm'])
    if res.number_of_participants < 0:
        res.number_of_participants = None
    res.event_description = data['Selite'] or ''
    if data['VarusteluSelite'] or data['equipment']:
        s = 'Varustelu:\n'
        items = []
        if data['equipment']:
            items.append('\n'.join(['- ' + x for x in data['equipment']]))
        if data['VarusteluSelite']:
            items.append(data['VarusteluSelite'])
        s += '\n\n'.join(items)
        if res.event_description and not res.event_description.endswith('\n'):
            s = '\n' + s
        res.event_description += s
    res.participants = '\n'.join(data['attendees'])
    if data['OsallistujaSelite']:
        if res.participants:
            res.participants += '\n\n'
        res.participants += data['OsallistujaSelite']
    res.comments = 'Siirretty vanhasta huonevarausjärjestelmästä'
    res.resource = data['resource']['object']

    user = data['user']
    if user is not None:
        res.reserver_name = user['Nimi']
        email = user['Mail'].strip().lower()
        res.reserver_email_address = email
        res.reserver_phone_number = user['Puhelin']

        if email not in user_objects_by_email:
            try:
                u_obj = User.objects.get(email=email)
            except User.DoesNotExist:
                print("%s does not exist" % email)
                u_obj = None
            user_objects_by_email[email] = u_obj

        res.user = user_objects_by_email[email]
        if not res.user:
            missing_users.setdefault(email, 0)
            missing_users[email] += 1
    else:
        res.reserver_name = ''
        res.reserver_email_address = ''
        res.reserver_phone_number = ''
        res.user = None

    res._skip_notifications = True
    print(res)
    res.save()

    if data['catering'] or data['TarjoiluSelite']:
        order = CateringOrder(reservation=res, provider=catering_provider)
        invoicing_data = [data.get(f) for f in PAYER_FIELDS]
        order.invoicing_data = '\n'.join(
            [val.strip() for val in invoicing_data if val])
        message_data = []
        if data['catering']:
            message_data.append('\n'.join(data['catering']))
        if data['TarjoiluSelite']:
            message_data.append(data['TarjoiluSelite'].strip())
        order.message = '\n\n'.join(message_data)
        order.save()
Example #14
0
def save_reservation(
        data, hvara_reservations,
        user_objects_by_email, missing_users,
        catering_provider,
):
    if not data['resource']['object']:
        return

    origin_id = 'hvara:%s' % data['VarausId']
    res = hvara_reservations.get(origin_id)
    try:
        res = Reservation.objects.get(origin_id=origin_id)
    except Reservation.DoesNotExist:
        res = Reservation(origin_id=origin_id)

    res.begin = local_tz.localize(datetime.strptime(data['AlkuAika'], "%Y-%m-%dT%H:%M:%S"))
    res.end = local_tz.localize(datetime.strptime(data['LoppuAika'], "%Y-%m-%dT%H:%M:%S"))
    res.event_subject = data['Tilaisuus'].strip()
    res.host_name = data['Isanta'].strip()
    res.created_at = local_tz.localize(datetime.strptime(data['Perustettu'], "%Y-%m-%dT%H:%M:%S"))
    res.modified_at = local_tz.localize(datetime.strptime(data['Muutettu'], "%Y-%m-%dT%H:%M:%S"))
    res.number_of_participants = int(data['OsallistujaLkm'])
    if res.number_of_participants < 0:
        res.number_of_participants = None
    res.event_description = data['Selite'] or ''
    if data['VarusteluSelite'] or data['equipment']:
        s = 'Varustelu:\n'
        items = []
        if data['equipment']:
            items.append('\n'.join(['- ' + x for x in data['equipment']]))
        if data['VarusteluSelite']:
            items.append(data['VarusteluSelite'])
        s += '\n\n'.join(items)
        if res.event_description and not res.event_description.endswith('\n'):
            s = '\n' + s
        res.event_description += s
    res.participants = '\n'.join(data['attendees'])
    if data['OsallistujaSelite']:
        if res.participants:
            res.participants += '\n\n'
        res.participants += data['OsallistujaSelite']
    res.comments = 'Siirretty vanhasta huonevarausjärjestelmästä'
    res.resource = data['resource']['object']

    user = data['user']
    if user is not None:
        res.reserver_name = user['Nimi']
        email = user['Mail'].strip().lower()
        res.reserver_email_address = email
        res.reserver_phone_number = user['Puhelin']

        if email not in user_objects_by_email:
            try:
                u_obj = User.objects.get(email=email)
            except User.DoesNotExist:
                print("%s does not exist" % email)
                u_obj = None
            user_objects_by_email[email] = u_obj

        res.user = user_objects_by_email[email]
        if not res.user:
            missing_users.setdefault(email, 0)
            missing_users[email] += 1
    else:
        res.reserver_name = ''
        res.reserver_email_address = ''
        res.reserver_phone_number = ''
        res.user = None

    res._skip_notifications = True
    print(res)
    res.save()

    if data['catering'] or data['TarjoiluSelite']:
        order = CateringOrder(reservation=res, provider=catering_provider)
        invoicing_data = [data.get(f) for f in PAYER_FIELDS]
        order.invoicing_data = '\n'.join([val.strip() for val in invoicing_data if val])
        message_data = []
        if data['catering']:
            message_data.append('\n'.join(data['catering']))
        if data['TarjoiluSelite']:
            message_data.append(data['TarjoiluSelite'].strip())
        order.message = '\n\n'.join(message_data)
        order.save()
Example #15
0
    def validate(self, data):
        reservation = self.instance
        request_user = self.context['request'].user

        # this check is probably only needed for PATCH
        try:
            resource = data['resource']
        except KeyError:
            resource = reservation.resource

        if not resource.can_make_reservations(request_user):
            raise PermissionDenied()

        if data['end'] < timezone.now():
            raise ValidationError(_('You cannot make a reservation in the past'))

        if not resource.is_admin(request_user):
            reservable_before = resource.get_reservable_before()
            if reservable_before and data['begin'] >= reservable_before:
                raise ValidationError(_('The resource is reservable only before %(datetime)s' %
                                        {'datetime': reservable_before}))

        # normal users cannot make reservations for other people
        if not resource.is_admin(request_user):
            data.pop('user', None)

        # Check user specific reservation restrictions relating to given period.
        resource.validate_reservation_period(reservation, request_user, data=data)

        if 'comments' in data:
            if not resource.is_admin(request_user):
                raise ValidationError(dict(comments=_('Only allowed to be set by staff members')))

        if 'access_code' in data:
            if data['access_code'] == None:
                data['access_code'] = ''

            access_code_enabled = resource.is_access_code_enabled()

            if not access_code_enabled and data['access_code']:
                raise ValidationError(dict(access_code=_('This field cannot have a value with this resource')))

            if access_code_enabled and reservation and data['access_code'] != reservation.access_code:
                raise ValidationError(dict(access_code=_('This field cannot be changed')))

        # Mark begin of a critical section. Subsequent calls with this same resource will block here until the first
        # request is finished. This is needed so that the validations and possible reservation saving are
        # executed in one block and concurrent requests cannot be validated incorrectly.
        Resource.objects.select_for_update().get(pk=resource.pk)

        # Check maximum number of active reservations per user per resource.
        # Only new reservations are taken into account ie. a normal user can modify an existing reservation
        # even if it exceeds the limit. (one that was created via admin ui for example).
        if reservation is None:
            resource.validate_max_reservations_per_user(request_user)

        # Run model clean
        data.pop('staff_event', None)
        instance = Reservation(**data)
        try:
            instance.clean(original_reservation=reservation)
        except DjangoValidationError as exc:

            # Convert Django ValidationError to DRF ValidationError so that in the response
            # field specific error messages are added in the field instead of in non_field_messages.
            if not hasattr(exc, 'error_dict'):
                raise ValidationError(exc)
            error_dict = {}
            for key, value in exc.error_dict.items():
                error_dict[key] = [error.message for error in value]
            raise ValidationError(error_dict)

        return data