repa main, repa device view, repa device and cafe assignments
This commit is contained in:
parent
f91ae88592
commit
a7501ec565
9 changed files with 299 additions and 28 deletions
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 4.2 on 2023-06-18 07:46
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('repapp', '0010_customuser_notifications'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='reparateur',
|
||||
name='cafe',
|
||||
field=models.ManyToManyField(to='repapp.cafe'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='guest',
|
||||
field=models.ForeignKey(choices=[(-1, 'abgelehnt'), (0, 'neu'), (1, 'in Orga Rückfrage'), (2, 'in Orga Rückfrage beantwortet'), (3, 'in der Warteliste')], null=True, on_delete=django.db.models.deletion.CASCADE, to='repapp.guest', verbose_name='Gast'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 4.2 on 2023-06-18 13:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('repapp', '0011_reparateur_cafe_alter_device_guest'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='reparateur',
|
||||
name='cafe',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cafe',
|
||||
name='reparateur',
|
||||
field=models.ManyToManyField(to='repapp.reparateur'),
|
||||
),
|
||||
]
|
||||
18
rc_hip/repapp/migrations/0013_device_reparateur.py
Normal file
18
rc_hip/repapp/migrations/0013_device_reparateur.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.2 on 2023-06-18 14:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('repapp', '0012_remove_reparateur_cafe_cafe_reparateur'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='reparateur',
|
||||
field=models.ManyToManyField(to='repapp.reparateur'),
|
||||
),
|
||||
]
|
||||
|
|
@ -30,6 +30,21 @@ class CustomUser(AbstractUser):
|
|||
return f'{self.email}'
|
||||
|
||||
|
||||
class Reparateur(models.Model):
|
||||
"""
|
||||
A Reparateur is a member of the Repair-Café who supports guests with fixing their devices.
|
||||
"""
|
||||
name = models.CharField(max_length=200, verbose_name=_("Name"))
|
||||
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Reparateur')
|
||||
verbose_name_plural = _('Reparateure')
|
||||
|
||||
def __str__(self):
|
||||
return f'Reparateur {self.name} (eMail: {self.mail})'
|
||||
|
||||
|
||||
class Cafe(models.Model):
|
||||
"""
|
||||
A Cafe is a "Repair-Café event.
|
||||
|
|
@ -39,6 +54,7 @@ class Cafe(models.Model):
|
|||
address = models.CharField(
|
||||
max_length=200, verbose_name=_("Adresse"))
|
||||
event_date = models.DateField(verbose_name=_("Datum"))
|
||||
reparateur = models.ManyToManyField(Reparateur)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Repair-Café')
|
||||
|
|
@ -48,22 +64,6 @@ class Cafe(models.Model):
|
|||
return f'Repair-Café am {self.event_date} (Ort: {self.location})'
|
||||
|
||||
|
||||
class Reparateur(models.Model):
|
||||
"""
|
||||
A Reparateur is a member of the Repair-Café who supports guests with fixing their devices.
|
||||
"""
|
||||
name = models.CharField(max_length=200, verbose_name=_("Name"))
|
||||
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
|
||||
cafe = models.ManyToManyField(Cafe)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Reparateur')
|
||||
verbose_name_plural = _('Reparateure')
|
||||
|
||||
def __str__(self):
|
||||
return f'Reparateur {self.name} (eMail: {self.mail})'
|
||||
|
||||
|
||||
class Organisator(models.Model):
|
||||
"""
|
||||
A Organisator is a member of the Repair-Café who arranges repair appointments with guests.
|
||||
|
|
@ -108,12 +108,16 @@ class Device(models.Model):
|
|||
STATUS_ORGA_QUESTION = 1
|
||||
STATUS_ORGA_QUESTION_ANSWERED = 2
|
||||
STATUS_WAITING_LIST = 3
|
||||
STATUS_REPA_QUESTION = 4
|
||||
STATUS_REPA_QUESTION_ANSWERED = 5
|
||||
STATUS = (
|
||||
(STATUS_REJECTED, 'abgelehnt'),
|
||||
(STATUS_NEW, 'neu'),
|
||||
(STATUS_ORGA_QUESTION, 'in Orga Rückfrage'),
|
||||
(STATUS_ORGA_QUESTION_ANSWERED, 'in Orga Rückfrage beantwortet'),
|
||||
(STATUS_WAITING_LIST, 'in der Warteliste'),
|
||||
(STATUS_REPA_QUESTION, 'in Repa Rückfrage'),
|
||||
(STATUS_REPA_QUESTION_ANSWERED, 'in Repa Rückfrage beantwortet'),
|
||||
)
|
||||
|
||||
identifier = models.CharField(max_length=200, verbose_name=_("ID"))
|
||||
|
|
@ -134,6 +138,7 @@ class Device(models.Model):
|
|||
Guest, on_delete=models.CASCADE, null=True, verbose_name=_("Gast"), choices=STATUS)
|
||||
cafe = models.ForeignKey(
|
||||
Cafe, on_delete=models.CASCADE, null=False, verbose_name=_("Repair-Café"))
|
||||
reparateur = models.ManyToManyField(Reparateur)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Gerät')
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@
|
|||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
max-width:1920px;>
|
||||
max-width:1920px;
|
||||
margin-bottom:10px">
|
||||
<div class="col-md-5 p-lg-5 mx-auto my-5">
|
||||
<h1 class="display-4 font-weight-normal"
|
||||
style="font-size: 60px;
|
||||
|
|
|
|||
|
|
@ -26,9 +26,19 @@
|
|||
<tr>
|
||||
<td>{{ cafe.event_date|date:"l" }}, {{ cafe.event_date|date }}</td>
|
||||
<td>{{ cafe.location }}</td>
|
||||
<td>Nein</td>
|
||||
<td>
|
||||
<a href="" class="btn btn-primary">teilnehmen</a>
|
||||
{% if cafe.accepted %}
|
||||
Ja
|
||||
{% else %}
|
||||
Nein
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if cafe.accepted %}
|
||||
<a href="{% url 'repa_cafe_decline' cafe.pk %}" class="btn btn-primary">absagen</a>
|
||||
{% else %}
|
||||
<a href="{% url 'repa_cafe_accept' cafe.pk %}" class="btn btn-primary">teilnehmen</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
|
|
@ -47,6 +57,7 @@
|
|||
<th scope="col">Hersteller & Modell/Typ</th>
|
||||
<th scope="col">Repair-Café</th>
|
||||
<th scope="col">Ort</th>
|
||||
<th scope="col">mir zugeordnet?</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -58,7 +69,14 @@
|
|||
<td>{{ device.cafe.event_date|date:"l" }}, {{ device.cafe.event_date|date }}</td>
|
||||
<td>{{ device.cafe.location }}</td>
|
||||
<td>
|
||||
<a href="" class="btn btn-primary">Details</a>
|
||||
{% if device.assigned %}
|
||||
Ja
|
||||
{% else %}
|
||||
Nein
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'repa_view_device' device.pk %}" class="btn btn-primary">Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
|
|
|
|||
75
rc_hip/repapp/templates/repapp/repa/view_device.html
Normal file
75
rc_hip/repapp/templates/repapp/repa/view_device.html
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{% extends "repapp/base.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% block title %}
|
||||
- Gerät
|
||||
{% endblock title %}
|
||||
{% block page_title %}
|
||||
Gerät
|
||||
{% endblock page_title %}
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{% url 'repa' %}" class="btn btn-primary">Zurück</a>
|
||||
{% if assigned %}
|
||||
<a href="{% url 'repa_device_unassign' device.pk %}"
|
||||
class="btn btn-primary">Gerät ablehnen</a>
|
||||
<a href="{% url 'device_question' device.pk %}" class="btn btn-primary">Rückfrage</a>
|
||||
{% else %}
|
||||
<a href="{% url 'repa_device_assign' device.pk %}"
|
||||
class="btn btn-primary">Gerät mir zuordnen</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
<hr class="mt-0 mb-4">
|
||||
<h1 class="mt-2">Gerät</h1>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Art des Geräts</th>
|
||||
<td>{{ device.device }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Hersteller & Modell/Typ</th>
|
||||
<td>{{ device.manufacturer }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Fehlerbeschreibung</th>
|
||||
<td>{{ device.error }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Folgetermin</th>
|
||||
<td>
|
||||
{% if device.follow_up %}
|
||||
Ja
|
||||
{% else %}
|
||||
Nein
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Foto vom Gerät</th>
|
||||
<td>
|
||||
{% if device.device_picture %}
|
||||
<img alt="Foto vom Gerät"
|
||||
height="100%"
|
||||
width="50%"
|
||||
src="/media/{{ device.device_picture }}" />
|
||||
{% else %}
|
||||
kein Bild
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Foto vom Typenschild</th>
|
||||
<td>
|
||||
{% if device.device_picture %}
|
||||
<img alt="Foto vom Typenschild"
|
||||
height="100%"
|
||||
width="50%"
|
||||
src="/media/{{ device.type_plate_picture }}" />
|
||||
{% else %}
|
||||
kein Bild
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock content %}
|
||||
|
|
@ -44,6 +44,15 @@ urlpatterns = [
|
|||
path("member/question/",
|
||||
views.questions, name="device_questions"),
|
||||
path("repa/", views.repa, name="repa"),
|
||||
path("repa/<int:cafe>/accept", views.repa_cafe_accept, name="repa_cafe_accept"),
|
||||
path("repa/<int:cafe>/decline",
|
||||
views.repa_cafe_decline, name="repa_cafe_decline"),
|
||||
path("repa/<int:device>/",
|
||||
views.repa_view_device, name="repa_view_device"),
|
||||
path("repa/<int:device>/assign",
|
||||
views.repa_device_assign, name="repa_device_assign"),
|
||||
path("repa/<int:device>/unassign",
|
||||
views.repa_device_unassign, name="repa_device_unassign"),
|
||||
path("cafe/", views.CafeView.as_view(), name="cafe"),
|
||||
path("cafe/create", views.CafeCreateView.as_view(), name="create_cafe"),
|
||||
path("cafe/<int:pk>/edit", views.CafeUpdateView.as_view(), name="edit_cafe"),
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ class QuestionDeviceFormView(LoginRequiredMixin, UserPassesTestMixin, generic.ed
|
|||
login_url = reverse_lazy('member')
|
||||
|
||||
def test_func(self):
|
||||
return is_organisator(self.request.user)
|
||||
return is_member(self.request.user)
|
||||
|
||||
def form_valid(self, form):
|
||||
device = self.kwargs['device']
|
||||
|
|
@ -628,23 +628,31 @@ class QuestionDeviceFormView(LoginRequiredMixin, UserPassesTestMixin, generic.ed
|
|||
message = form.cleaned_data['message']
|
||||
mail = self.request.user.email
|
||||
organisator = Organisator.objects.filter(mail=mail).first()
|
||||
reparateur = Reparateur.objects.filter(mail=mail).first()
|
||||
if organisator:
|
||||
question = Question(
|
||||
question=message,
|
||||
organisator=organisator,
|
||||
device=device
|
||||
)
|
||||
|
||||
send_device_question_mail(question, self.request)
|
||||
device.status = Device.STATUS_ORGA_QUESTION
|
||||
elif reparateur:
|
||||
question = Question(
|
||||
question=message,
|
||||
reparateur=reparateur,
|
||||
device=device
|
||||
)
|
||||
|
||||
device.status = Device.STATUS_REPA_QUESTION
|
||||
else:
|
||||
raise PermissionDenied('Not valid member found!')
|
||||
question.save()
|
||||
|
||||
send_device_question_mail(question, self.request)
|
||||
|
||||
device.status = Device.STATUS_ORGA_QUESTION
|
||||
device.save()
|
||||
|
||||
return HttpResponseRedirect(
|
||||
reverse_lazy('orga')
|
||||
reverse_lazy('member')
|
||||
)
|
||||
|
||||
def get_initial(self, **kwargs):
|
||||
|
|
@ -782,8 +790,21 @@ def repa(request):
|
|||
logger.warning('The user %s is no reparateur!', str(request.user))
|
||||
raise PermissionDenied('Not reparateur!')
|
||||
|
||||
cafes = Cafe.objects.filter(event_date__gte=datetime.date.today())
|
||||
devices = Device.objects.filter(status=Device.STATUS_WAITING_LIST)
|
||||
devices = []
|
||||
for device in Device.objects.filter(status__gte=Device.STATUS_WAITING_LIST):
|
||||
if device.reparateur.filter(mail=request.user.email).count() > 0:
|
||||
device.assigned = True
|
||||
else:
|
||||
device.assigned = False
|
||||
devices.append(device)
|
||||
|
||||
cafes = []
|
||||
for cafe in Cafe.objects.filter(event_date__gte=datetime.date.today()):
|
||||
if cafe.reparateur.filter(mail=request.user.email).count() > 0:
|
||||
cafe.accepted = True
|
||||
else:
|
||||
cafe.accepted = False
|
||||
cafes.append(cafe)
|
||||
|
||||
return render(
|
||||
request,
|
||||
|
|
@ -977,3 +998,81 @@ class MemberSettingsFormView(LoginRequiredMixin, UserPassesTestMixin, generic.ed
|
|||
|
||||
def test_func(self):
|
||||
return is_member(self.request.user)
|
||||
|
||||
|
||||
@login_required(login_url=reverse_lazy('member'))
|
||||
def repa_cafe_accept(request, cafe):
|
||||
if not is_reparateur(request.user):
|
||||
raise PermissionDenied('Not a reparateur!')
|
||||
|
||||
cafe = get_object_or_404(Cafe, pk=cafe)
|
||||
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
|
||||
cafe.reparateur.add(reparateur)
|
||||
cafe.save()
|
||||
|
||||
return HttpResponseRedirect(reverse_lazy('repa'))
|
||||
|
||||
|
||||
@login_required(login_url=reverse_lazy('member'))
|
||||
def repa_cafe_decline(request, cafe):
|
||||
if not is_reparateur(request.user):
|
||||
raise PermissionDenied('Not a reparateur!')
|
||||
|
||||
cafe = get_object_or_404(Cafe, pk=cafe)
|
||||
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
|
||||
cafe.reparateur.remove(reparateur)
|
||||
cafe.save()
|
||||
|
||||
return HttpResponseRedirect(reverse_lazy('repa'))
|
||||
|
||||
|
||||
@login_required(login_url=reverse_lazy('member'))
|
||||
def repa_view_device(request, device):
|
||||
"""
|
||||
View device details.
|
||||
"""
|
||||
# TODO: test
|
||||
if not is_reparateur(request.user):
|
||||
raise PermissionDenied('Not reparateur!')
|
||||
|
||||
device = get_object_or_404(Device, pk=device)
|
||||
assigned = device.reparateur.filter(mail=request.user.email).count() > 0
|
||||
|
||||
return render(
|
||||
request,
|
||||
"repapp/repa/view_device.html",
|
||||
{
|
||||
'device': device,
|
||||
'assigned': assigned,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@login_required(login_url=reverse_lazy('member'))
|
||||
def repa_device_assign(request, device):
|
||||
if not is_reparateur(request.user):
|
||||
raise PermissionDenied('Not a reparateur!')
|
||||
|
||||
device = get_object_or_404(Device, pk=device)
|
||||
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
|
||||
device.reparateur.add(reparateur)
|
||||
device.save()
|
||||
|
||||
return HttpResponseRedirect(reverse_lazy('repa_view_device', kwargs={
|
||||
'device': device.id
|
||||
}))
|
||||
|
||||
|
||||
@login_required(login_url=reverse_lazy('member'))
|
||||
def repa_device_unassign(request, device):
|
||||
if not is_reparateur(request.user):
|
||||
raise PermissionDenied('Not a reparateur!')
|
||||
|
||||
device = get_object_or_404(Device, pk=device)
|
||||
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
|
||||
device.reparateur.remove(reparateur)
|
||||
device.save()
|
||||
|
||||
return HttpResponseRedirect(reverse_lazy('repa_view_device', kwargs={
|
||||
'device': device.id
|
||||
}))
|
||||
|
|
|
|||
Reference in a new issue