All files / server/src/features/assignment/utils getAssignmentBonus.ts

100% Statements 23/23
100% Branches 17/17
100% Functions 9/9
100% Lines 23/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93                  50x                     927x 983x       927x 1357x   85004x   17197x                   1357x     600x 600x   3707x   600x               1357x 29x   1334x         927x   927x               927x 1328x   582x             927x   927x       927x    
import dayjs from "dayjs";
import { partition } from "remeda";
import { config } from "shared/config";
import { DIRECT_SIGNUP_PRIORITY } from "shared/constants/signups";
import { EventLogAction } from "shared/types/models/eventLog";
import { ProgramItem } from "shared/types/models/programItem";
import { User } from "shared/types/models/user";
import { DirectSignupsForProgramItem } from "server/features/direct-signup/directSignupTypes";
 
export const getAssignmentBonus = (
  attendeeGroup: User[],
  lotteryParticipantDirectSignups: readonly DirectSignupsForProgramItem[],
  lotterySignupProgramItems: readonly ProgramItem[],
  assignmentTime: string,
): number => {
  /** First time bonus */
 
  // A re-run must not count its own results as "previous" (which would strip the bonus and
  // change outcomes): ignore lottery wins (priority > 0) and NEW_ASSIGNMENT events at the
  // current assignmentTime, but keep genuine first-come-first-served direct sign-ups
  const isCurrentAssignment = (startTime: string): boolean =>
    dayjs(startTime).isSame(dayjs(assignmentTime), "minute");
 
  // Get group members with previous direct sign-ups or NEW_ASSIGNMENT event log items
  const [groupMembersWithDirectSignups, groupMembersWithoutDirectSignups] =
    partition(attendeeGroup, (groupMember) => {
      const previousDirectSignup = lotteryParticipantDirectSignups.find(
        (programItem) => {
          return programItem.userSignups.find(
            (userSignup) =>
              userSignup.username === groupMember.username &&
              // Exclude this lottery's own win (priority > 0) at the current time, but keep
              // first-come-first-served (priority 0) sign-ups counting as "previous"
              !(
                isCurrentAssignment(userSignup.signedToStartTime) &&
                userSignup.priority !== DIRECT_SIGNUP_PRIORITY
              ),
          );
        },
      );
      const newAssignmentEvent = groupMember.eventLogItems.find(
        (eventLogItem) => {
          const previousAssignment =
            eventLogItem.action === EventLogAction.NEW_ASSIGNMENT;
          const programItemExists = lotterySignupProgramItems.some(
            (programItem) =>
              programItem.programItemId === eventLogItem.programItemId,
          );
          return (
            previousAssignment &&
            programItemExists &&
            !isCurrentAssignment(eventLogItem.programItemStartTime)
          );
        },
      );
 
      if (previousDirectSignup ?? newAssignmentEvent) {
        return true;
      }
      return false;
    });
 
  // Give first time bonus to the whole group if half of the group members don't have previous direct sign-ups
  const averagePreviousDirectSignups =
    groupMembersWithDirectSignups.length / attendeeGroup.length;
  const firstTimeBonus =
    averagePreviousDirectSignups <= 0.5 ? config.server().firstSignupBonus : 0;
 
  /** Additional first time bonus */
 
  // Get group members with previous NO_ASSIGNMENT event log items and without direct sign-ups.
  // Ignore a NO_ASSIGNMENT from the current assignmentTime — on a re-run it's this run's own
  // earlier result, so counting it would make the re-run boost run-1 failures
  const groupMembersWithPreviousFailedLotterySignup =
    groupMembersWithoutDirectSignups.filter((groupMember) => {
      return groupMember.eventLogItems.find(
        (eventLogItem) =>
          eventLogItem.action === EventLogAction.NO_ASSIGNMENT &&
          !isCurrentAssignment(eventLogItem.programItemStartTime),
      );
    });
 
  // Give additional first time bonus to the whole group if half of the group members have previous failed lottery sign-ups
  const averageFailedLotterySignups =
    groupMembersWithPreviousFailedLotterySignup.length / attendeeGroup.length;
  const additionalFirstTimeBonus =
    averageFailedLotterySignups >= 0.5
      ? config.server().additionalFirstSignupBonus
      : 0;
 
  return firstTimeBonus + additionalFirstTimeBonus;
};