diff --git a/src/teams/models.py b/src/teams/models.py
index 6e0862f4..3366926f 100644
--- a/src/teams/models.py
+++ b/src/teams/models.py
@@ -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?",
+ )
diff --git a/src/teams/templates/team_shift_list.html b/src/teams/templates/team_shift_list.html
index 360e66a9..e8bbf025 100644
--- a/src/teams/templates/team_shift_list.html
+++ b/src/teams/templates/team_shift_list.html
@@ -50,7 +50,7 @@ Shifts | {{ block.super }}
{{ shift.people_required }}
{% 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 %} (for sale!){% 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 %}">
Unassign me
- {% elif shift.people_required > shift.team_members.count %}
+
+ Sell shift
+
+ {% elif shift.people_required > shift.team_members.filter(for_sale=False).count %}
Assign me
diff --git a/src/teams/templates/team_user_shifts.html b/src/teams/templates/team_user_shifts.html
index 745fd2bb..e3311b90 100644
--- a/src/teams/templates/team_user_shifts.html
+++ b/src/teams/templates/team_user_shifts.html
@@ -34,6 +34,10 @@ Your shifts | {{ block.super }}
|
{{ shift.shift_range.upper|date:'H:i' }}
|
+
+
+ Sell shift
|
@@ -45,4 +49,4 @@ Your shifts | {{ block.super }}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/src/teams/urls.py b/src/teams/urls.py
index 92ef4e03..33bdc7c7 100644
--- a/src/teams/urls.py
+++ b/src/teams/urls.py
@@ -179,6 +179,11 @@ urlpatterns = [
MemberDropsShift.as_view(),
name="shift_member_drop",
),
+ path(
+ "sell",
+ MemberSellsShift.as_view(),
+ name="shift_member_sell",
+ ),
]
),
),
diff --git a/src/teams/views/shifts.py b/src/teams/views/shifts.py
index eaa44fc8..72d0ede9 100644
--- a/src/teams/views/shifts.py
+++ b/src/teams/views/shifts.py
@@ -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"
|