shift-selling #1

Open
reynir wants to merge 4 commits from shift-selling into master
8 changed files with 56 additions and 16 deletions

View file

@ -13,7 +13,6 @@ from info.views import CampInfoView
from people.views import PeopleView
from sponsors.views import SponsorsView
from villages.views import (
VillageCreateView,
VillageDeleteView,
VillageDetailView,
VillageListView,
@ -118,11 +117,6 @@ urlpatterns = [
include(
[
path("", VillageListView.as_view(), name="village_list"),
path(
"create/",
VillageCreateView.as_view(),
name="village_create",
),
path(
"<slug:slug>/delete/",
VillageDeleteView.as_view(),

View file

@ -401,7 +401,7 @@ class TeamShift(CampRelatedModel):
shift_range = DateTimeRangeField()
team_members = models.ManyToManyField(TeamMember, blank=True)
team_members = models.ManyToManyField(TeamMember, blank=True, through=TeamShiftAssignment)
people_required = models.IntegerField(default=1)
@ -420,3 +420,21 @@ class TeamShift(CampRelatedModel):
@property
def users(self):
return [member.user for member in self.team_members.all()]
class TeamShiftAssignment(CampRelatedModel):
team_shift = models.ForeignKey(
"teams.TeamShift",
on_delete=models.CASCADE,
help_text="The shift",
)
team_member = models.ForeignKey(
"teams.TeamMember",
on_delete=models.CASCADE,
help_text="The team member on shift",
)
for_sale = models.BooleanField(
default=False,
help_text="Is the shift assignment for sale?",
)

View file

@ -50,7 +50,7 @@ Shifts | {{ block.super }}
{{ shift.people_required }}
<td>
{% for member in shift.team_members.all %}
{{ member.user.profile.get_public_credit_name }}{% if not forloop.last %},{% endif %}
{{ member.user.profile.get_public_credit_name }}{% if member.for_sale %} <em>(for sale!)</em>{% endif %}{% if not forloop.last %},{% endif %}
{% empty %}
None!
{% endfor %}
@ -71,7 +71,11 @@ Shifts | {{ block.super }}
href="{% url 'teams:shift_member_drop' camp_slug=camp.slug team_slug=team.slug pk=shift.pk %}">
<i class="fas fa-thumbs-down"></i> Unassign me
</a>
{% elif shift.people_required > shift.team_members.count %}
<a class="btn btn-warning"
href="{% url 'teams:shift_member_sell' camp_slug=camp.slug team_slug=team.slug pk=shift.pk %}">
<i class="fas fa-thumbs-down"></i> Sell shift
</a>
{% elif shift.people_required > shift.team_members.filter(for_sale=False).count %}
<a class="btn btn-success"
href="{% url 'teams:shift_member_take' camp_slug=camp.slug team_slug=team.slug pk=shift.pk %}">
<i class="fas fa-thumbs-up"></i> Assign me

View file

@ -34,6 +34,10 @@ Your shifts | {{ block.super }}
<td>
{{ shift.shift_range.upper|date:'H:i' }}
</td>
<td>
<a class="btn btn-warning"
href="{% url 'teams:shift_member_sell' camp_slug=camp.slug team_slug=shift.team.slug pk=shift.pk %}">
<i class="fas fa-thumbs-down"></i> Sell shift
<td>
<a class="btn btn-danger"
href="{% url 'teams:shift_member_drop' camp_slug=camp.slug team_slug=shift.team.slug pk=shift.pk %}">
@ -45,4 +49,4 @@ Your shifts | {{ block.super }}
</tbody>
</table>
{% endblock %}
{% endblock %}

View file

@ -179,6 +179,11 @@ urlpatterns = [
MemberDropsShift.as_view(),
name="shift_member_drop",
),
path(
"sell",
MemberSellsShift.as_view(),
name="shift_member_sell",
),
]
),
),

View file

@ -274,6 +274,9 @@ class MemberTakesShift(LoginRequiredMixin, CampViewMixin, View):
request, template.render(Context({"shifts": overlapping_shifts}))
)
else:
# Remove at most one shift assignment for sale
for shift_assignment in shift.team_members.filter(for_sale=True)[:1]:
shift_assignment.delete()
shift.team_members.add(team_member)
kwargs.pop("pk")
@ -297,6 +300,23 @@ class MemberDropsShift(LoginRequiredMixin, CampViewMixin, View):
return HttpResponseRedirect(reverse("teams:shifts", kwargs=kwargs))
class MemberSellsShift(LoginRequiredMixin, CampViewMixin, View):
http_methods = ["get"]
def get(self, request, **kwargs):
shift = TeamShift.objects.get(id=kwargs["pk"])
team = Team.objects.get(camp=self.camp, slug=kwargs["team_slug"])
team_member = TeamMember.objects.get(team=team, user=request.user)
shift_assignment = shift.team_members.get(team_member = team_member.pk)
shift_assignment.for_sale = True
shift_assignment.save()
kwargs.pop("pk")
return HttpResponseRedirect(reverse("teams:shifts", kwargs=kwargs))
class UserShifts(CampViewMixin, TemplateView):
template_name = "team_user_shifts.html"

View file

@ -16,10 +16,6 @@ Villages | {{ block.super }}
tent, chairs and tables in the shop!
</p>
{% if user.is_authenticated and not camp.read_only %}
<a href="{% url 'village_create' camp_slug=camp.slug %}" class="btn btn-primary">Create a new {{ camp.title }} village</a>
{% endif %}
<hr />
{% if villages %}
<table class="table table-hover table-condensed table-striped">

View file

@ -1,7 +1,6 @@
from django.urls import path
from .views import (
VillageCreateView,
VillageDeleteView,
VillageDetailView,
VillageListView,
@ -12,7 +11,7 @@ app_name = "villages"
urlpatterns = [
path("", VillageListView.as_view(), name="list"),
path("create/", VillageCreateView.as_view(), name="create"),
# path("create/", VillageCreateView.as_view(), name="create"),
path("<slug:slug>/delete/", VillageDeleteView.as_view(), name="delete"),
path("<slug:slug>/edit/", VillageUpdateView.as_view(), name="update"),
path("<slug:slug>/", VillageDetailView.as_view(), name="detail"),