forked from CGM_Public/pretix_original
Fix handling of auto-checkout around DST switch
This commit is contained in:
@@ -32,11 +32,12 @@
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta
|
||||
from functools import partial, reduce
|
||||
|
||||
import dateutil
|
||||
import dateutil.parser
|
||||
import pytz
|
||||
from django.core.files import File
|
||||
from django.db import transaction
|
||||
from django.db.models import (
|
||||
@@ -46,7 +47,7 @@ from django.db.models import (
|
||||
from django.db.models.functions import Coalesce, TruncDate
|
||||
from django.dispatch import receiver
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now, override
|
||||
from django.utils.timezone import make_aware, now, override
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scope, scopes_disabled
|
||||
|
||||
@@ -523,5 +524,15 @@ def process_exit_all(sender, **kwargs):
|
||||
position=p, list=cl, auto_checked_in=True, type=Checkin.TYPE_EXIT, datetime=cl.exit_all_at
|
||||
)
|
||||
checkin_created.send(cl.event, checkin=ci)
|
||||
cl.exit_all_at = cl.exit_all_at + timedelta(days=1)
|
||||
d = cl.exit_all_at.astimezone(cl.event.timezone)
|
||||
if cl.event.settings.get(f'autocheckin_dst_hack_{cl.pk}'): # move time back if yesterday was DST switch
|
||||
d -= timedelta(hours=1)
|
||||
cl.event.settings.delete(f'autocheckin_dst_hack_{cl.pk}')
|
||||
try:
|
||||
cl.exit_all_at = make_aware(datetime.combine(d.date() + timedelta(days=1), d.time()), cl.event.timezone)
|
||||
except pytz.exceptions.NonExistentTimeError:
|
||||
cl.event.settings.set(f'autocheckin_dst_hack_{cl.pk}', True)
|
||||
d += timedelta(hours=1)
|
||||
cl.exit_all_at = make_aware(datetime.combine(d.date() + timedelta(days=1), d.time()), cl.event.timezone)
|
||||
# AmbiguousTimeError shouldn't be possible since d.time() includes fold=0
|
||||
cl.save(update_fields=['exit_all_at'])
|
||||
|
||||
@@ -687,3 +687,40 @@ def test_auto_check_out_only_if_checked_in(event, position, clist):
|
||||
with freeze_time("2020-01-03 03:05:00+01:00"):
|
||||
process_exit_all(sender=None)
|
||||
assert position.checkins.count() == 2
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_auto_check_out_dst(event, position, clist):
|
||||
event.settings.timezone = 'Europe/Berlin'
|
||||
|
||||
# Survive across a shift that doesn't affect the time in question
|
||||
clist.exit_all_at = event.timezone.localize(datetime(2021, 3, 28, 1, 0))
|
||||
clist.save()
|
||||
with freeze_time(clist.exit_all_at + timedelta(minutes=5)):
|
||||
process_exit_all(sender=None)
|
||||
clist.refresh_from_db()
|
||||
assert clist.exit_all_at.astimezone(event.timezone) == event.timezone.localize(datetime(2021, 3, 29, 1, 0))
|
||||
|
||||
# Survive across a shift that makes the time in question ambigous
|
||||
clist.exit_all_at = event.timezone.localize(datetime(2021, 10, 28, 2, 30))
|
||||
clist.save()
|
||||
with freeze_time(clist.exit_all_at + timedelta(minutes=5)):
|
||||
process_exit_all(sender=None)
|
||||
clist.refresh_from_db()
|
||||
assert clist.exit_all_at.astimezone(event.timezone) == event.timezone.localize(datetime(2021, 10, 29, 2, 30))
|
||||
|
||||
# Doesn't survive across a shift that makes the time in question non-existant
|
||||
clist.exit_all_at = event.timezone.localize(datetime(2021, 3, 27, 2, 30))
|
||||
clist.save()
|
||||
with freeze_time(clist.exit_all_at + timedelta(minutes=5)):
|
||||
process_exit_all(sender=None)
|
||||
clist.refresh_from_db()
|
||||
assert clist.exit_all_at.astimezone(event.timezone) == event.timezone.localize(datetime(2021, 3, 28, 2, 30))
|
||||
with freeze_time(clist.exit_all_at + timedelta(minutes=5)):
|
||||
process_exit_all(sender=None)
|
||||
clist.refresh_from_db()
|
||||
assert clist.exit_all_at.astimezone(event.timezone) == event.timezone.localize(datetime(2021, 3, 29, 2, 30))
|
||||
with freeze_time(clist.exit_all_at + timedelta(minutes=5)):
|
||||
process_exit_all(sender=None)
|
||||
clist.refresh_from_db()
|
||||
assert clist.exit_all_at.astimezone(event.timezone) == event.timezone.localize(datetime(2021, 3, 30, 2, 30))
|
||||
|
||||
Reference in New Issue
Block a user