diff --git a/benchcoach/templates/benchcoach/card.html b/benchcoach/templates/benchcoach/card.html
new file mode 100644
index 0000000..e135d70
--- /dev/null
+++ b/benchcoach/templates/benchcoach/card.html
@@ -0,0 +1,280 @@
+{% load static %}
+
+
+ Gamecard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | {{ event.teamsnap_event.csv_event_title }} |
+
+ {% if event.home_team.name == user.profile.teamsnapsettings.managed_team.name %}
+ HOME
+ {% elif event.away_team.name == user.profile.teamsnapsettings.managed_team.name %}
+ AWAY
+ {% else %}
+ {% endif %}
+ |
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+ | 1
+ | 2
+ | 3
+ | 4
+ | 5
+ | 6
+ | 7
+ | X
+ |
+
+
+ {% for positioning in positionings_starting %}
+ {% if positioning.order == 0 %}
+ {% else %}
{% endif %}
+ | {{ positioning.order }} |
+ {{ positioning.player.last_name }} |
+ {{ positioning.player.jersey_number }} |
+ {{ positioning.position|default_if_none:'' }} |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+ {% endfor %}
+
+
+
+
+ {% for line in empty_lines %}
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+ | 1
+ | 2
+ | 3
+ | 4
+ | 5
+ | 6
+ | 7
+ | X
+ |
+
+
+ {% for positioning in positionings %}
+
+ |
+ {{ positioning.player.jersey_number }} |
+ {{ positioning.player.last_name }} |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+ {% endfor %}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/benchcoach/urls.py b/benchcoach/urls.py
index 5af1683..8ba6ed6 100644
--- a/benchcoach/urls.py
+++ b/benchcoach/urls.py
@@ -11,5 +11,7 @@ urlpatterns = [
path('events//lineup', login_required(views.EventDetailView.as_view()), name="event lineup"),
path('players/list/', login_required(views.PlayerListView.as_view()), name="player list"),
path('teams/list/', login_required(views.TeamListView.as_view()), name="team list"),
- path('venues/list/', login_required(views.VenueListView.as_view()), name="venue list")
+ path('venues/list/', login_required(views.VenueListView.as_view()), name="venue list"),
+ path('events//card', login_required(views.lineupcard), name="lineup card"),
+path('events//csv', login_required(views.csv_export), name="lineup csv")
]
\ No newline at end of file
diff --git a/benchcoach/views.py b/benchcoach/views.py
index f235a61..c8fb47b 100644
--- a/benchcoach/views.py
+++ b/benchcoach/views.py
@@ -1,9 +1,10 @@
-from django.shortcuts import render
+from django.shortcuts import render, HttpResponse
from .models import Event, Team, Player, Positioning, Venue
from .forms import PositioningFormSet, TeamsnapEventForm
from django.contrib import messages
from django.db.models import F
from django.views.generic import ListView, DetailView
+import csv
class BenchCoachListView(ListView):
@@ -136,3 +137,102 @@ def lineup_edit(request, event_id, active_tab='details'):
"formset_dhd": formset_dhd,
},
)
+
+def lineupcard(request, event_id):
+ previous_event = Event.objects.filter(id=event_id - 1).first()
+
+ event = Event.objects.get(id=event_id)
+ next_event = Event.objects.get(id=event_id + 1)
+ players = Player.objects.prefetch_related("availability_set", "positioning_set")
+
+ for player in players:
+ Positioning.objects.get_or_create(player_id=player.id, event_id=event_id)
+
+ qs = (
+ event.positioning_set.all()
+ .filter(player__availability__event=event_id, player__teamsnap_member__is_non_player=False)
+ .order_by("-player__availability__available", "player__last_name", "order")
+ .annotate(event_availability=F("player__availability__available"))
+ )
+
+ qs_starting = qs.filter(order__isnull=False).order_by("order")
+
+ details = {
+ "Away Team": event.away_team,
+ "Home Team": event.home_team,
+ "Date": event.start.date(),
+ "Time": event.start.time(),
+ "Venue": event.venue,
+ }
+
+ return render(
+ request,
+ "benchcoach/card.html",
+ {
+ "title": "Lineup",
+ "event": event,
+ "details": details,
+ "previous_event": previous_event,
+ "next_event": next_event,
+ "positionings": qs,
+ "positionings_starting": qs_starting,
+ "empty_lines": range(14)
+ },
+ )
+
+def csv_export(request, event_id):
+ response = HttpResponse(
+ content_type='text/csv',
+ headers={'Content-Disposition': f'attachment; filename=lineup-event-{event_id}.csv'},
+ )
+ previous_event = Event.objects.filter(id=event_id - 1).first()
+
+ event = Event.objects.get(id=event_id)
+ players = Player.objects.prefetch_related("availability_set", "positioning_set")
+
+ for player in players:
+ Positioning.objects.get_or_create(player_id=player.id, event_id=event_id)
+
+ qs = (
+ event.positioning_set.all()
+ .filter(player__availability__event=event_id, player__teamsnap_member__is_non_player=False)
+ .order_by("-player__availability__available", "player__last_name", "order")
+ .annotate(event_availability=F("player__availability__available"))
+ )
+
+ rows = []
+
+ rows.append(event.teamsnap_event.csv_event_title) # 2
+ rows.append(event.venue.name) # 3
+ [rows.append('') for i in range(3)] #4-6
+ p = qs.filter(position='P').first()
+ rows.append(f"{p.player.last_name}, {p.player.first_name}") #7
+ [rows.append('') for i in range(3)] #8-10
+ for pos in ['C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH']: #11-19
+ p = qs.filter(position=pos).first()
+ if p:
+ rows.append(f"{p.player.last_name}, {p.player.first_name}")
+ else:
+ rows.append('')
+ ehs = qs.filter(position='EH')
+ if len(ehs) > 0:
+ p=qs.filter(position='EH')[0]
+ rows.append(f"{p.player.last_name}, {p.player.first_name}") # 20
+ else:
+ rows.append('')
+ if len(ehs) > 1:
+ p=qs.filter(position='EH')[1]
+ rows.append(f"{p.player.last_name}, {p.player.first_name}") # 21
+ else:
+ rows.append('')
+ rows.append('') #22
+ p=qs.filter(position__isnull=False, order=0).first()
+ rows.append(f"{p.player.last_name}, {p.player.first_name}") # 23
+ rows.append('')
+ for p in qs.filter(order__gt=0).order_by('order'):
+ rows.append(f"{p.player.last_name}, {p.player.first_name}")
+
+ writer = csv.writer(response)
+ for row in rows:
+ writer.writerow([row])
+ return response
\ No newline at end of file
diff --git a/benchcoachproject/static/css/paper.css b/benchcoachproject/static/css/paper.css
new file mode 100644
index 0000000..ede1dab
--- /dev/null
+++ b/benchcoachproject/static/css/paper.css
@@ -0,0 +1,38 @@
+@page { margin: 0 }
+body { margin: 0 }
+.sheet {
+ margin: 0;
+ overflow: hidden;
+ position: relative;
+ box-sizing: border-box;
+ page-break-after: always;
+}
+
+/** Paper sizes **/
+body.A3 .sheet { width: 297mm; height: 419mm }
+body.A3.landscape .sheet { width: 420mm; height: 296mm }
+body.A4 .sheet { width: 210mm; height: 296mm }
+body.A4.landscape .sheet { width: 297mm; height: 209mm }
+body.A5 .sheet { width: 148mm; height: 209mm }
+body.A5.landscape .sheet { width: 210mm; height: 147mm }
+body.letter .sheet { width: 216mm; height: 279mm }
+body.letter.landscape .sheet { width: 280mm; height: 215mm }
+body.legal .sheet { width: 216mm; height: 356mm }
+body.legal.landscape .sheet { width: 357mm; height: 215mm }
+
+/** Padding area **/
+.sheet.padding-10mm { padding: 10mm }
+.sheet.padding-15mm { padding: 15mm }
+.sheet.padding-20mm { padding: 20mm }
+.sheet.padding-25mm { padding: 25mm }
+
+/** Fix for Chrome issue #273306 **/
+@media print {
+ body.A3.landscape { width: 420mm }
+ body.A3, body.A4.landscape { width: 297mm }
+ body.A4, body.A5.landscape { width: 210mm }
+ body.A5 { width: 148mm }
+ body.letter, body.legal { width: 216mm }
+ body.letter.landscape { width: 280mm }
+ body.legal.landscape { width: 357mm }
+}
diff --git a/benchcoachproject/static/css/paper.min.css b/benchcoachproject/static/css/paper.min.css
new file mode 100644
index 0000000..265a771
--- /dev/null
+++ b/benchcoachproject/static/css/paper.min.css
@@ -0,0 +1 @@
+@page{margin:0}body{margin:0}.sheet{margin:0;overflow:hidden;position:relative;box-sizing:border-box;page-break-after:always}body.A3 .sheet{width:297mm;height:419mm}body.A3.landscape .sheet{width:420mm;height:296mm}body.A4 .sheet{width:210mm;height:296mm}body.A4.landscape .sheet{width:297mm;height:209mm}body.A5 .sheet{width:148mm;height:209mm}body.A5.landscape .sheet{width:210mm;height:147mm}body.letter .sheet{width:216mm;height:279mm}body.letter.landscape .sheet{width:280mm;height:215mm}body.legal .sheet{width:216mm;height:356mm}body.legal.landscape .sheet{width:357mm;height:215mm}.sheet.padding-10mm{padding:10mm}.sheet.padding-15mm{padding:15mm}.sheet.padding-20mm{padding:20mm}.sheet.padding-25mm{padding:25mm}@media screen{body{background:#e0e0e0}.sheet{background:#fff;box-shadow:0 .5mm 2mm rgba(0,0,0,.3);margin:5mm auto}}@media print{body.A3.landscape{width:420mm}body.A3,body.A4.landscape{width:297mm}body.A4,body.A5.landscape{width:210mm}body.A5{width:148mm}body.legal,body.letter{width:216mm}body.letter.landscape{width:280mm}body.legal.landscape{width:357mm}}
\ No newline at end of file
diff --git a/benchcoachproject/static/fonts/Inconsolata.ttf b/benchcoachproject/static/fonts/Inconsolata.ttf
new file mode 100644
index 0000000..20251d9
Binary files /dev/null and b/benchcoachproject/static/fonts/Inconsolata.ttf differ
diff --git a/benchcoachproject/static/fonts/OpenSans-Italic.ttf b/benchcoachproject/static/fonts/OpenSans-Italic.ttf
new file mode 100644
index 0000000..0fea34b
Binary files /dev/null and b/benchcoachproject/static/fonts/OpenSans-Italic.ttf differ
diff --git a/benchcoachproject/static/fonts/OpenSans.ttf b/benchcoachproject/static/fonts/OpenSans.ttf
new file mode 100644
index 0000000..51dd3c3
Binary files /dev/null and b/benchcoachproject/static/fonts/OpenSans.ttf differ