Skip to content

Commit

Permalink
fix signup check bug with incorrect full detection
Browse files Browse the repository at this point in the history
  • Loading branch information
felixrindt committed Sep 10, 2024
1 parent 4f4900b commit 8e21457
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 45 deletions.
14 changes: 10 additions & 4 deletions ephios/plugins/baseshiftstructures/structure/qualification_mix.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

from ephios.core.models import AbstractParticipation, Qualification
from ephios.core.services.matching import Position, match_participants_to_positions, skill_level
from ephios.core.signup.flow.participant_validation import ParticipantUnfitError
from ephios.core.signup.flow.participant_validation import (
ParticipantUnfitError,
SignupDisallowedError,
)
from ephios.core.signup.participants import PlaceholderParticipant
from ephios.plugins.baseshiftstructures.structure.group_common import (
AbstractGroupBasedStructureConfigurationForm,
Expand Down Expand Up @@ -78,7 +81,10 @@ def check_qualifications(self, shift, participant, strict_mode=True):
)
if len(matching_with.pairings) > len(matching_without.pairings):
return
raise ParticipantUnfitError(_("You are not qualified."))

if (free := shift.get_signup_stats().free) and free > 0:
raise ParticipantUnfitError(_("You are not qualified."))
raise SignupDisallowedError(_("The maximum number of participants is reached."))

def get_checkers(self):
return super().get_checkers() + [
Expand Down Expand Up @@ -129,9 +135,9 @@ def _could_sign_up_for_requirement(self, qualifications):
None,
None,
)
self.check_qualifications(self.shift, extra_participant)
self.check_qualifications(self.shift, extra_participant, strict_mode=True)
return True
except ParticipantUnfitError:
except SignupDisallowedError:
return False

def get_shift_state_context_data(self, request, **kwargs):
Expand Down
105 changes: 67 additions & 38 deletions ephios/plugins/complexsignup/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
from ephios.core.models import AbstractParticipation
from ephios.core.services.matching import Matching, Position, match_participants_to_positions
from ephios.core.signup.disposition import BaseDispositionParticipationForm
from ephios.core.signup.flow.participant_validation import ParticipantUnfitError
from ephios.core.signup.flow.participant_validation import (
ParticipantUnfitError,
SignupDisallowedError,
)
from ephios.core.signup.forms import BaseSignupForm, SignupConfigurationForm
from ephios.core.signup.participants import AbstractParticipant
from ephios.core.signup.stats import SignupStats
Expand Down Expand Up @@ -271,7 +274,9 @@ def check_qualifications(self, shift, participant, strict_mode=True):
)
if len(matching_with.pairings) > len(matching_without.pairings):
return
raise ParticipantUnfitError(_("You are not qualified."))
if (free := shift.get_signup_stats().free) and free > 0:
raise ParticipantUnfitError(_("You are not qualified."))
raise SignupDisallowedError(_("The maximum number of participants is reached."))

def get_checkers(self):
return super().get_checkers() + [
Expand Down Expand Up @@ -404,42 +409,66 @@ def _build_atomic_block_structure(
structure["positions"].append(p)
structure["participations"].append(participation)

# build derivative positions for designated participants and "allow_more" participants
for _ in range(
max(
int(block.allow_more)
* (len(participations) + 1), # 1 extra in case of signup matching check
# if more designated participants than we have positions we need to add placeholder anyway
len(designated_for) - len(block.positions.all()),
)
):
count_id = next(opt_counter[f"{block_position.id}-opt"])
opt_match_id = f"{match_id}-{count_id}"
p = Position(
id=opt_match_id,
required_qualifications=required_here | set(block_position.qualifications.all()),
preferred_by=preferred_by,
designated_for=designated_for,
aux_score=0,
required=False, # allow_more -> always optional
label=label,
)
participation = matching.participation_for_position(opt_match_id) if matching else None
structure["signup_stats"] += SignupStats.ZERO.replace(
min_count=0,
max_count=None, # allow_more -> always free
missing=0,
free=None,
requested_count=bool(
participation and participation.state == AbstractParticipation.States.REQUESTED
),
confirmed_count=bool(
participation and participation.state == AbstractParticipation.States.CONFIRMED
),
)
all_positions.append(p)
structure["positions"].append(p)
structure["participations"].append(participation)
# build derivative positions for "allow_more" participants
allow_more_count = int(block.allow_more) * (
len(participations) + 1
) # 1 extra in case of signup matching check
for _ in range(allow_more_count):
opt_match_id = f"{path}{block.uuid}-opt-{next(opt_counter[str(block.id)])}"
p = Position(
id=opt_match_id,
required_qualifications=required_here,
preferred_by=preferred_by,
designated_for=designated_for,
aux_score=0,
required=False, # allow_more -> always optional
label=block.name,
)
participation = matching.participation_for_position(opt_match_id) if matching else None
structure["signup_stats"] += SignupStats.ZERO.replace(
min_count=0,
max_count=None, # allow_more -> always free
missing=0,
free=None,
requested_count=bool(
participation and participation.state == AbstractParticipation.States.REQUESTED
),
confirmed_count=bool(
participation and participation.state == AbstractParticipation.States.CONFIRMED
),
)
all_positions.append(p)
structure["positions"].append(p)
structure["participations"].append(participation)

for _ in range(max(0, len(designated_for) - len(block.positions.all()) - allow_more_count)):
# if more designated participants than we have positions, we need to add placeholder anyway
opt_match_id = f"{path}{block.uuid}-opt-{next(opt_counter[str(block.id)])}"
p = Position(
id=opt_match_id,
required_qualifications=required_here,
preferred_by=preferred_by,
designated_for=designated_for,
aux_score=0,
required=False, # designated -> always optional
label=block.name,
)
participation = matching.participation_for_position(opt_match_id) if matching else None
structure["signup_stats"] += SignupStats.ZERO.replace(
min_count=0,
max_count=0, # designated overflow -> runs over max
missing=0,
free=0,
requested_count=bool(
participation and participation.state == AbstractParticipation.States.REQUESTED
),
confirmed_count=bool(
participation and participation.state == AbstractParticipation.States.CONFIRMED
),
)
all_positions.append(p)
structure["positions"].append(p)
structure["participations"].append(participation)


def convert_blocks_to_positions(starting_blocks, participations, matching=None):
Expand Down
6 changes: 3 additions & 3 deletions ephios/plugins/complexsignup/templatetags/complex_extra.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from django import template

from ephios.core.signup.flow.participant_validation import ParticipantUnfitError
from ephios.core.signup.flow.participant_validation import SignupDisallowedError
from ephios.core.signup.participants import PlaceholderParticipant
from ephios.core.signup.stats import SignupStats
from ephios.plugins.baseshiftstructures.structure.group_common import format_min_max_count
Expand Down Expand Up @@ -45,7 +45,7 @@ def has_complex_free(atomic_block_structure, shift):
None,
None,
)
shift.structure.check_qualifications(shift, extra_participant)
shift.structure.check_qualifications(shift, extra_participant, strict_mode=True)
return True
except ParticipantUnfitError:
except SignupDisallowedError:
return False

0 comments on commit 8e21457

Please sign in to comment.