start card and csv views

This commit is contained in:
2021-12-31 14:47:50 -06:00
parent b0316e2188
commit f880d7fb13
8 changed files with 423 additions and 2 deletions

View File

@@ -0,0 +1,280 @@
{% load static %}
<head>
<meta charset="utf-8">
<title>Gamecard</title>
<link rel="stylesheet" href="{% static "css/base.css"%}">
<link rel="stylesheet" href="{% static "css/paper.css"%}">
<style> @page { size: letter }
</style>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inconsolata">
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Open+Sans">
<style>
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
@font-face {
font-family: 'Open Sans';
src: url("{% static 'fonts/OpenSans.ttf' %}") format("truetype-variations");
font-weight: 1 999;
font-stretch: 0% 100%
}
@font-face {
font-family: 'Inconsolata';
src: url("{% static 'fonts/Inconsolata.ttf' %}") format("truetype-variations");
font-weight: 1 999;
font-stretch: 0% 100%
}
.whole-card {
margin:0;
padding:0;
height: 12.5cm;
width: 17.5cm;
outline: .8px dashed lightgray;
margin: auto;
display: flex;
}
.half-card {
margin: auto;
padding: .1in;
height: 100%;
width: 50%;
}
card-left {
float: left;
margin: auto;
}
card-right {
float: right;
}
.content {
height: 100%;
width: 100%;
{#outline: solid grey;#}
}
table {
font-family: "Open Sans";
border-collapse: collapse;
empty-cells: show;
font-size:11px;
table-layout: fixed;
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
width: 100%;
border: 1px solid #000;
}
th, td {
/* box-sizing: content-box; */
border: 0.5px solid black;
height: 17px;
text-overflow: ellipsis;
overflow-x: hidden;
padding: 0px;
padding-left: 2px;
padding-right: 2px;
}
.gametitle {
text-transform: uppercase;
font-stretch: condensed;
text-align: center;
font-weight: bold;
}
.homeaway {
text-transform: uppercase;
font-stretch: extra-expanded;
text-align: center;
font-weight: 900;
font-size: 12px;
}
.numbercell {
font-family: "Inconsolata";
text-align: center;
font-size: 10px;
}
.statscell {
font-family: "Inconsolata";
text-align: center;
font-stretch: extra-condensed;
font-size: 9px;
width: 60px;
}
tr:nth-child(even) {background-color: #f2f2f2;}
th{
background: black;
color: white;
border: none;
}
.customcol{
width: 120px;
text-transform: uppercase;
font-stretch: condensed;
}
.condensedNameCell{
width: 70px;
text-transform: uppercase;
font-stretch: condensed;
}
.square {
height: 14px;
width: 14px;
}
.available{
background-color: #B7E1CD;
}
.notavailable{
background-color: #F4C7C3;
}
.maybeavailable{
background-color: #B7E1CD;
}
.starting{
font-weight: bold;
}
</style>
</head>
<body class="letter">
<section class="sheet padding-10mm">
<div class="whole-card">
<div id="NW" class="half-card red">
<div class="content card-left">
<table>
<thead>
<tr>
<th colspan="9" class="gametitle">{{ event.teamsnap_event.csv_event_title }}</th>
<th colspan="3" class="homeaway">
{% 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 %}
</th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<th class="numbercell"></td>
<th class="customcol"></td>
<th class="numbercell"></td>
<th class="numbercell"></td>
<th class="numbercell">1</td>
<th class="numbercell">2</td>
<th class="numbercell">3</td>
<th class="numbercell">4</td>
<th class="numbercell">5</td>
<th class="numbercell">6</td>
<th class="numbercell">7</td>
<th class="numbercell">X</td>
</tr>
</thead>
<tbody>
{% for positioning in positionings_starting %}
{% if positioning.order == 0 %}<tr style="border: 1px solid;">
{% else %}<tr>{% endif %}
<td class="numbercell">{{ positioning.order }}</td>
<td class="customcol">{{ positioning.player.last_name }}</td>
<td class="numbercell">{{ positioning.player.jersey_number }}</td>
<td class="numbercell">{{ positioning.position|default_if_none:'' }}</td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
</tr>
{% endfor %}
</tbody>
</table>
<table>
<tbody>
{% for line in empty_lines %}
<tr>
<td class="numbercell"></td>
<td class="customcol"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="half-card">
<div class="content card-right">
<table>
<thead>
<tr>
<th class="numbercell"></td>
<th class="numbercell"></td>
<th class="customcol"></td>
<th class="numbercell"></td>
<th class="numbercell">1</td>
<th class="numbercell">2</td>
<th class="numbercell">3</td>
<th class="numbercell">4</td>
<th class="numbercell">5</td>
<th class="numbercell">6</td>
<th class="numbercell">7</td>
<th class="numbercell">X</td>
</tr>
</thead>
<tbody>
{% for positioning in positionings %}
<tr>
<td class="numbercell"></td>
<td class="numbercell">{{ positioning.player.jersey_number }}</td>
<td class="customcol{% if positioning.event_availability == 2 %} available{% endif %}{% if positioning.event_availability == 0 %} notavailable{% endif %}{% if positioning.order or positioning.position %} starting{% endif %}">{{ positioning.player.last_name }}</td>
<td class="numbercell"><i class="bi bi-check-lg"></i></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
</body>

View File

@@ -11,5 +11,7 @@ urlpatterns = [
path('events/<int:pk>/lineup', login_required(views.EventDetailView.as_view()), name="event lineup"), path('events/<int:pk>/lineup', login_required(views.EventDetailView.as_view()), name="event lineup"),
path('players/list/', login_required(views.PlayerListView.as_view()), name="player list"), 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('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/<int:event_id>/card', login_required(views.lineupcard), name="lineup card"),
path('events/<int:event_id>/csv', login_required(views.csv_export), name="lineup csv")
] ]

View File

@@ -1,9 +1,10 @@
from django.shortcuts import render from django.shortcuts import render, HttpResponse
from .models import Event, Team, Player, Positioning, Venue from .models import Event, Team, Player, Positioning, Venue
from .forms import PositioningFormSet, TeamsnapEventForm from .forms import PositioningFormSet, TeamsnapEventForm
from django.contrib import messages from django.contrib import messages
from django.db.models import F from django.db.models import F
from django.views.generic import ListView, DetailView from django.views.generic import ListView, DetailView
import csv
class BenchCoachListView(ListView): class BenchCoachListView(ListView):
@@ -136,3 +137,102 @@ def lineup_edit(request, event_id, active_tab='details'):
"formset_dhd": formset_dhd, "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

View File

@@ -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 }
}

View File

@@ -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}}

Binary file not shown.

Binary file not shown.

Binary file not shown.