New check-in features (#3022)

This commit is contained in:
Raphael Michel
2023-02-09 09:46:46 +01:00
committed by GitHub
parent 7b0d07065f
commit 6902725f3c
69 changed files with 1606 additions and 183 deletions
+1 -1
View File
@@ -340,7 +340,7 @@ class BadgeExporter(BaseExporter):
if form_data.get('include_pending'):
qs = qs.filter(order__status__in=[Order.STATUS_PAID, Order.STATUS_PENDING])
else:
qs = qs.filter(order__status__in=[Order.STATUS_PAID])
qs = qs.filter(Q(order__status=Order.STATUS_PAID) | Q(order__status=Order.STATUS_PENDING, order__valid_if_pending=True))
if form_data.get('date_from'):
dt = make_aware(datetime.combine(
+28 -7
View File
@@ -216,10 +216,13 @@ class CheckInListMixin(BaseExporter):
)
if form_data.get('attention_only'):
qs = qs.filter(Q(item__checkin_attention=True) | Q(order__checkin_attention=True))
qs = qs.filter(Q(item__checkin_attention=True) | Q(order__checkin_attention=True) | Q(variation__checkin_attention=True))
if not cl.include_pending:
qs = qs.filter(order__status=Order.STATUS_PAID)
qs = qs.filter(
Q(order__status=Order.STATUS_PAID) |
Q(order__status=Order.STATUS_PENDING, order__valid_if_pending=True)
)
else:
qs = qs.filter(order__status__in=(Order.STATUS_PAID, Order.STATUS_PENDING))
@@ -363,12 +366,15 @@ class PDFCheckinList(ReportlabExportMixin, CheckInListMixin, BaseExporter):
)
if op.seat:
item += '<br/>' + str(op.seat)
name = bleach.clean(str(name), tags=['br']).strip().replace('<br>', '<br/>')
if op.blocked:
name = '<font face="OpenSansBd">[' + _('Blocked') + ']</font> ' + name
row = [
'!!' if op.item.checkin_attention or op.order.checkin_attention else '',
CBFlowable(bool(op.last_checked_in)),
'!!' if op.require_checkin_attention else '',
CBFlowable(bool(op.last_checked_in)) if not op.blocked else '',
'' if op.order.status != Order.STATUS_PAID else '',
op.order.code,
Paragraph(bleach.clean(str(name), tags=['br']).strip().replace('<br>', '<br/>'), self.get_style()),
Paragraph(name, self.get_style()),
Paragraph(bleach.clean(str(item), tags=['br']).strip().replace('<br>', '<br/>'), self.get_style()),
]
acache = {}
@@ -401,6 +407,12 @@ class PDFCheckinList(ReportlabExportMixin, CheckInListMixin, BaseExporter):
('TEXTCOLOR', (2, len(tdata)), (2, len(tdata)), '#ffffff'),
('ALIGN', (2, len(tdata)), (2, len(tdata)), 'CENTER'),
]
if op.blocked:
tstyledata += [
('BACKGROUND', (1, len(tdata)), (1, len(tdata)), '#990000'),
('TEXTCOLOR', (1, len(tdata)), (1, len(tdata)), '#ffffff'),
('ALIGN', (1, len(tdata)), (1, len(tdata)), 'CENTER'),
]
tdata.append(row)
table = Table(tdata, colWidths=colwidths, repeatRows=1)
@@ -440,7 +452,10 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
_('Product'), _('Price'), _('Checked in'), _('Checked out'), _('Automatically checked in')
]
if not cl.include_pending:
qs = qs.filter(order__status=Order.STATUS_PAID)
qs = qs.filter(
Q(order__status=Order.STATUS_PAID) |
Q(order__status=Order.STATUS_PENDING, order__valid_if_pending=True)
)
else:
qs = qs.filter(order__status__in=(Order.STATUS_PAID, Order.STATUS_PENDING))
headers.append(_('Paid'))
@@ -470,6 +485,9 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
headers.append(_('Seat zone'))
headers.append(_('Seat row'))
headers.append(_('Seat number'))
headers.append(_('Blocked'))
headers.append(_('Valid from'))
headers.append(_('Valid until'))
headers += [
_('Address'),
_('ZIP code'),
@@ -565,7 +583,7 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
row.append(op.voucher.code if op.voucher else "")
row.append(op.order.datetime.astimezone(self.event.timezone).strftime('%Y-%m-%d'))
row.append(op.order.datetime.astimezone(self.event.timezone).strftime('%H:%M:%S'))
row.append(_('Yes') if op.order.checkin_attention or op.item.checkin_attention else _('No'))
row.append(_('Yes') if op.require_checkin_attention else _('No'))
row.append(op.order.comment or "")
if op.seat:
@@ -580,6 +598,9 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
row += ['', '', '', '', '']
row += [
_('Yes') if op.blocked else '',
date_format(op.valid_from, 'SHORT_DATETIME_FORMAT') if op.valid_from else '',
date_format(op.valid_until, 'SHORT_DATETIME_FORMAT') if op.valid_until else '',
op.street or '',
op.zipcode or '',
op.city or '',
+4 -2
View File
@@ -243,7 +243,8 @@ class OrderMailForm(BaseMailForm):
self.fields['recipients'].choices = recp_choices
choices = [(e, l) for e, l in Order.STATUS_CHOICE if e != 'n']
choices.insert(0, ('na', _('payment pending (except unapproved)')))
choices.insert(0, ('valid_if_pending', _('payment pending but already confirmed')))
choices.insert(0, ('na', _('payment pending (except unapproved or already confirmed)')))
choices.insert(0, ('pa', _('approval pending')))
if not event.settings.get('payment_term_expire_automatically', as_type=bool):
choices.append(
@@ -257,10 +258,11 @@ class OrderMailForm(BaseMailForm):
choices=choices
)
if not self.initial.get('sendto'):
self.initial['sendto'] = ['p', 'na']
self.initial['sendto'] = ['p', 'na', 'valid_if_pending']
elif 'n' in self.initial['sendto']:
self.initial['sendto'].append('pa')
self.initial['sendto'].append('na')
self.initial['sendto'].append('valid_if_pending')
self.fields['items'].queryset = event.items.all()
if not self.initial.get('items'):
+9 -3
View File
@@ -22,7 +22,7 @@
from datetime import datetime, time, timedelta
from django.db import models
from django.db.models import Exists, OuterRef
from django.db.models import Exists, OuterRef, Q
from django.utils import timezone
from django.utils.formats import date_format
from django.utils.timezone import make_aware
@@ -118,7 +118,13 @@ class ScheduledMail(models.Model):
Exists(OrderPosition.objects.filter(order=OuterRef('pk'), item_id__in=limit_products))
)
status = [Order.STATUS_PENDING, Order.STATUS_PAID] if self.rule.include_pending else [Order.STATUS_PAID]
if self.rule.include_pending:
status_q = Q(status__in=[Order.STATUS_PAID, Order.STATUS_PENDING])
else:
status_q = Q(
Q(status=Order.STATUS_PAID) |
Q(status=Order.STATUS_PENDING, valid_if_pending=True)
)
if self.last_successful_order_id:
orders = orders.filter(
@@ -126,7 +132,7 @@ class ScheduledMail(models.Model):
)
orders = orders.filter(
status__in=status,
status_q,
require_approval=False,
).order_by('pk').select_related('invoice_address').prefetch_related('positions')
+5 -2
View File
@@ -264,7 +264,8 @@ class OrderSendView(BaseSenderView):
if 'status' not in _cache_store:
status = dict(Order.STATUS_CHOICE)
status['overdue'] = _('pending with payment overdue')
status['na'] = _('payment pending (except unapproved)')
status['valid_if_pending'] = _('payment pending but already confirmed')
status['na'] = _('payment pending (except unapproved or already confirmed)')
status['pa'] = _('approval pending')
status['r'] = status['c']
_cache_store['status'] = status
@@ -346,7 +347,9 @@ class OrderSendView(BaseSenderView):
if 'pa' in form.cleaned_data['sendto']:
statusq |= Q(status=Order.STATUS_PENDING, require_approval=True)
if 'na' in form.cleaned_data['sendto']:
statusq |= Q(status=Order.STATUS_PENDING, require_approval=False)
statusq |= Q(status=Order.STATUS_PENDING, require_approval=False, valid_if_pending=False)
if 'valid_if_pending' in form.cleaned_data['sendto']:
statusq |= Q(status=Order.STATUS_PENDING, require_approval=False, valid_if_pending=True)
orders = qs.filter(statusq)
opq = OrderPosition.objects.filter(
@@ -127,7 +127,7 @@ class AllTicketsPDF(BaseExporter):
if form_data.get('include_pending'):
qs = qs.filter(order__status__in=[Order.STATUS_PAID, Order.STATUS_PENDING])
else:
qs = qs.filter(order__status__in=[Order.STATUS_PAID])
qs = qs.filter(Q(order__status=Order.STATUS_PAID) | Q(order__status=Order.STATUS_PENDING, order__valid_if_pending=True))
if form_data.get('date_range'):
dt_start, dt_end = resolve_timeframe_to_datetime_start_inclusive_end_exclusive(now(), form_data['date_range'], self.timezone)
@@ -58,6 +58,8 @@ window.vapp = new Vue({
'result.unpaid': gettext('Ticket not paid'),
'result.rules': gettext('Entry not allowed'),
'result.revoked': gettext('Ticket code revoked/changed'),
'result.blocked': gettext('Ticket blocked'),
'result.invalid_time': gettext('Ticket not valid at this time'),
'result.canceled': gettext('Order canceled'),
'result.ambiguous': gettext('Ticket code is ambiguous on list'),
'status.checkin': gettext('Checked-in Tickets'),