public SucceededPickupBid(PickupBid pickupBid, int slotNumber, string outcome, SystemWideValues systemWideValues, LocalDate currentDate) { PickupBid = pickupBid; SlotNumber = slotNumber; Outcome = outcome; ProjectedPointsAtTimeOfBid = PickupBid.Publisher.GetProjectedFantasyPoints(pickupBid.LeagueYear, systemWideValues, currentDate); }
public DropResult CanConditionallyDropGame(PickupBid request, LeagueYear leagueYear, Publisher publisher, Instant?nextBidTime) { List <ClaimError> dropErrors = new List <ClaimError>(); var basicErrors = GetBasicErrors(leagueYear.League, publisher); dropErrors.AddRange(basicErrors); var currentDate = _clock.GetToday(); var dateOfPotentialAcquisition = currentDate; if (nextBidTime.HasValue) { dateOfPotentialAcquisition = nextBidTime.Value.ToEasternDate(); } if (request.ConditionalDropPublisherGame?.MasterGame is null) { throw new Exception($"Invalid conditional drop for bid: {request.BidID}"); } var masterGameErrors = GetGenericSlotMasterGameErrors(leagueYear, request.ConditionalDropPublisherGame.MasterGame.MasterGame, leagueYear.Year, true, currentDate, dateOfPotentialAcquisition, false, false, false); dropErrors.AddRange(masterGameErrors); //Drop limits var publisherGame = publisher.GetPublisherGameByPublisherGameID(request.ConditionalDropPublisherGame.PublisherGameID); if (publisherGame is null) { return(new DropResult(Result.Failure("Cannot drop a game that you do not have"))); } if (dropErrors.Any()) { return(new DropResult(Result.Failure("Game is no longer eligible for dropping."))); } bool gameWasDrafted = publisherGame.OverallDraftPosition.HasValue; if (!gameWasDrafted && leagueYear.Options.DropOnlyDraftGames) { return(new DropResult(Result.Failure("You can only drop games that you drafted due to your league settings."))); } var otherPublishers = leagueYear.GetAllPublishersExcept(publisher); bool gameWasCounterPicked = otherPublishers .SelectMany(x => x.PublisherGames) .Where(x => x.CounterPick) .ContainsGame(request.ConditionalDropPublisherGame.MasterGame.MasterGame); if (gameWasCounterPicked && leagueYear.Options.CounterPicksBlockDrops) { return(new DropResult(Result.Failure("You cannot drop that game because it was counter picked."))); } bool gameWillRelease = publisherGame.WillRelease(); var dropResult = publisher.CanDropGame(gameWillRelease, leagueYear.Options); return(new DropResult(dropResult)); }
public async Task MarkBidStatus(PickupBid bid, bool success) { using (var connection = new MySqlConnection(_connectionString)) { await connection.ExecuteAsync("update tblpickupbid SET Successful = @success where BidID = @bidID;", new { bidID = bid.BidID, success }); } }
public async Task <ClaimResult> EditPickupBid(PickupBid bid, PublisherGame?conditionalDropPublisherGame, uint bidAmount) { if (bid.Successful != null) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("Bid has already been processed", false) }, null)); } if (bidAmount < bid.LeagueYear.Options.MinimumBidAmount) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("That bid does not meet the league's minimum bid.", false) }, null)); } if (bidAmount > bid.Publisher.Budget) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("You do not have enough budget to make that bid.", false) }, null)); } int?validDropSlot = null; if (conditionalDropPublisherGame is not null) { if (bid.CounterPick) { return(new ClaimResult("Cannot make a counter pick bid with a conditional drop.", null)); } var dropResult = await MakeDropRequest(bid.LeagueYear, bid.Publisher, conditionalDropPublisherGame, true); if (dropResult.Result.IsFailure) { return(new ClaimResult(dropResult.Result.Error, null)); } validDropSlot = conditionalDropPublisherGame.SlotNumber; } await _fantasyCriticRepo.EditPickupBid(bid, conditionalDropPublisherGame, bidAmount); var currentDate = _clock.GetToday(); MasterGameWithEligibilityFactors eligibilityFactors = bid.LeagueYear.GetEligibilityFactorsForMasterGame(bid.MasterGame, currentDate); var slotResult = SlotEligibilityService.GetPublisherSlotAcquisitionResult(bid.Publisher, bid.LeagueYear.Options, eligibilityFactors, bid.CounterPick, validDropSlot, false); if (!slotResult.SlotNumber.HasValue) { return(new ClaimResult(slotResult.ClaimErrors, null)); } return(new ClaimResult(slotResult.SlotNumber.Value)); }
public PickupBidViewModel(PickupBid pickupBid, IClock clock) { BidID = pickupBid.BidID; BidAmount = pickupBid.BidAmount; Priority = pickupBid.Priority; Timestamp = pickupBid.Timestamp.ToDateTimeUtc(); Successful = pickupBid.Successful; MasterGame = new MasterGameViewModel(pickupBid.MasterGame, clock); }
public PickupBidEntity(PickupBid domain) { BidID = domain.BidID; PublisherID = domain.Publisher.PublisherID; MasterGameID = domain.MasterGame.MasterGameID; Timestamp = domain.Timestamp.ToDateTimeUtc(); Priority = domain.Priority; BidAmount = domain.BidAmount; Successful = domain.Successful; }
public async Task RemovePickupBid(PickupBid pickupBid) { using (var connection = new MySqlConnection(_connectionString)) { await connection.ExecuteAsync("delete from tblpickupbid where BidID = @bidID", new { pickupBid.BidID }); await connection.ExecuteAsync("update tblpickupbid SET Priority = Priority - 1 where PublisherID = @publisherID and Successful is NULL and Priority > @oldPriority", new { publisherID = pickupBid.Publisher.PublisherID, oldPriority = pickupBid.Priority }); } }
public async Task <Result> RemovePickupBid(PickupBid bid) { if (bid.Successful != null) { return(Result.Fail("Bid has already been processed")); } await _fantasyCriticRepo.RemovePickupBid(bid); return(Result.Ok()); }
public async Task CreatePickupBid(PickupBid currentBid) { var entity = new PickupBidEntity(currentBid); using (var connection = new MySqlConnection(_connectionString)) { await connection.ExecuteAsync( "insert into tblpickupbid(BidID,PublisherID,MasterGameID,Timestamp,Priority,BidAmount,Successful) VALUES " + "(@BidID,@PublisherID,@MasterGameID,@Timestamp,@Priority,@BidAmount,@Successful);", entity); } }
public async Task <ClaimResult> MakePickupBid(Publisher publisher, MasterGame masterGame, uint bidAmount, LeagueOptions leagueOptions) { if (bidAmount < leagueOptions.MinimumBidAmount) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("That bid does not meet the league's minimum bid.", false) })); } if (bidAmount > publisher.Budget) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("You do not have enough budget to make that bid.", false) })); } IReadOnlyList <PickupBid> pickupBids = await _fantasyCriticRepo.GetActivePickupBids(publisher); bool alreadyBidFor = pickupBids.Select(x => x.MasterGame.MasterGameID).Contains(masterGame.MasterGameID); if (alreadyBidFor) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("You cannot have two active bids for the same game.", false) })); } var claimRequest = new ClaimGameDomainRequest(publisher, masterGame.GameName, false, false, false, masterGame, null, null); var supportedYears = await _fantasyCriticRepo.GetSupportedYears(); var leagueYear = publisher.LeagueYear; var publishersForYear = await _fantasyCriticRepo.GetPublishersInLeagueForYear(publisher.LeagueYear); Instant nextBidTime = GetNextBidTime(); var claimResult = CanClaimGame(claimRequest, supportedYears, leagueYear, publishersForYear, nextBidTime, true); if (!claimResult.Success) { return(claimResult); } var nextPriority = pickupBids.Count + 1; PickupBid currentBid = new PickupBid(Guid.NewGuid(), publisher, leagueYear, masterGame, bidAmount, nextPriority, _clock.GetCurrentInstant(), null); await _fantasyCriticRepo.CreatePickupBid(currentBid); return(claimResult); }
private static IReadOnlyList <PickupBid> GetWinningBids(IEnumerable <PickupBid> winnableBids) { List <PickupBid> winningBids = new List <PickupBid>(); var groupedByPublisher = winnableBids.GroupBy(x => x.Publisher); foreach (var publisherGroup in groupedByPublisher) { PickupBid winningBid = publisherGroup.MinBy(x => x.Priority).First(); winningBids.Add(winningBid); } return(winningBids); }
public PickupBidEntity(PickupBid domain, PublisherGame?conditionalDropPublisherGame, uint bidAmount) : this(domain) { BidID = domain.BidID; PublisherID = domain.Publisher.PublisherID; MasterGameID = domain.MasterGame.MasterGameID; ConditionalDropMasterGameID = conditionalDropPublisherGame?.MasterGame?.MasterGame.MasterGameID; CounterPick = domain.CounterPick; Timestamp = domain.Timestamp; Priority = domain.Priority; BidAmount = bidAmount; Successful = domain.Successful; ProcessSetID = domain.ProcessSetID; Outcome = domain.Outcome; ProjectedPointsAtTimeOfBid = domain.ProjectedPointsAtTimeOfBid; }
public async Task <Maybe <PickupBid> > GetPickupBid(Guid bidID) { using (var connection = new MySqlConnection(_connectionString)) { var bidEntity = await connection.QuerySingleOrDefaultAsync <PickupBidEntity>("select * from tblpickupbid where BidID = @bidID", new { bidID }); if (bidEntity == null) { return(Maybe <PickupBid> .None); } var publisher = await GetPublisher(bidEntity.PublisherID); var masterGame = await GetMasterGame(bidEntity.MasterGameID); PickupBid domain = bidEntity.ToDomain(publisher.Value, masterGame.Value); return(domain); } }
public async Task <IReadOnlyList <PickupBid> > GetActivePickupBids(Publisher publisher) { using (var connection = new MySqlConnection(_connectionString)) { var bidEntities = await connection.QueryAsync <PickupBidEntity>("select * from tblpickupbid where PublisherID = @publisherID and Successful is NULL", new { publisherID = publisher.PublisherID }); List <PickupBid> domainBids = new List <PickupBid>(); foreach (var bidEntity in bidEntities) { var masterGame = await GetMasterGame(bidEntity.MasterGameID); PickupBid domain = bidEntity.ToDomain(publisher, masterGame.Value); domainBids.Add(domain); } return(domainBids); } }
public PickupBidViewModel(PickupBid pickupBid, LocalDate currentDate) { BidID = pickupBid.BidID; PublisherID = pickupBid.Publisher.PublisherID; PublisherName = pickupBid.Publisher.PublisherName; BidAmount = pickupBid.BidAmount; Priority = pickupBid.Priority; Timestamp = pickupBid.Timestamp.ToDateTimeUtc(); Successful = pickupBid.Successful; MasterGame = new MasterGameViewModel(pickupBid.MasterGame, currentDate); if (pickupBid.ConditionalDropPublisherGame is not null) { ConditionalDropPublisherGame = new PublisherGameViewModel(pickupBid.ConditionalDropPublisherGame, currentDate, false, false); } CounterPick = pickupBid.CounterPick; Outcome = pickupBid.Outcome; ProjectedPointsAtTimeOfBid = pickupBid.ProjectedPointsAtTimeOfBid; }
public async Task <ClaimResult> MakePickupBid(Publisher publisher, MasterGame masterGame, uint bidAmount) { if (bidAmount > publisher.Budget) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("You do not have enough budget to make that bid.", false) })); } IReadOnlyList <PickupBid> pickupBids = await _fantasyCriticRepo.GetActivePickupBids(publisher); bool alreadyBidFor = pickupBids.Select(x => x.MasterGame.MasterGameID).Contains(masterGame.MasterGameID); if (alreadyBidFor) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("You cannot have two active bids for the same game.", false) })); } var claimRequest = new ClaimGameDomainRequest(publisher, masterGame.GameName, false, false, masterGame, null, null); var claimResult = await CanClaimGame(claimRequest); if (!claimResult.Success) { return(claimResult); } var nextPriority = pickupBids.Count + 1; PickupBid currentBid = new PickupBid(Guid.NewGuid(), publisher, masterGame, bidAmount, nextPriority, _clock.GetCurrentInstant(), null); await _fantasyCriticRepo.CreatePickupBid(currentBid); return(claimResult); }
public async Task <IActionResult> DeletePickupBid([FromBody] PickupBidDeleteRequest request) { if (!ModelState.IsValid) { return(BadRequest()); } var maybeBid = await _fantasyCriticService.GetPickupBid(request.BidID); if (maybeBid.HasNoValue) { return(BadRequest("That bid does not exist.")); } var publisher = maybeBid.Value.Publisher; var currentUser = await _userManager.FindByNameAsync(User.Identity.Name); bool userIsInLeague = await _fantasyCriticService.UserIsInLeague(publisher.League, currentUser); bool userIsPublisher = (currentUser.UserID == publisher.User.UserID); if (!userIsInLeague || !userIsPublisher) { return(Forbid()); } PickupBid bid = maybeBid.Value; Result result = await _fantasyCriticService.RemovePickupBid(bid); if (result.IsFailure) { return(BadRequest(result.Error)); } return(Ok()); }
public LeagueAction(PickupBid action, Instant timestamp) { Timestamp = timestamp; Publisher = action.Publisher; if (!action.CounterPick) { ActionType = "Pickup Successful"; if (action.ConditionalDropPublisherGame is not null) { if (action.ConditionalDropResult !.Result.IsSuccess) { Description = $"Acquired game '{action.MasterGame.GameName}' with a bid of ${action.BidAmount}. Dropped game '{action.ConditionalDropPublisherGame.MasterGame!.MasterGame.GameName}' conditionally."; } else { Description = $"Acquired game '{action.MasterGame.GameName}' with a bid of ${action.BidAmount}. Attempted to drop game '{action.ConditionalDropPublisherGame.MasterGame!.MasterGame.GameName}' conditionally but cannot because: {action.ConditionalDropResult.Result.Error}."; } } else { Description = $"Acquired game '{action.MasterGame.GameName}' with a bid of ${action.BidAmount}"; } }
private ProcessedBidSet ProcessPickupsForLeagueYear(LeagueYear leagueYear, IReadOnlyList <PickupBid> activeBidsForLeague, PublisherStateSet publisherStateSet, SystemWideValues systemWideValues, Instant processingTime) { LeagueYear updatedLeagueYear = publisherStateSet.GetUpdatedLeagueYear(leagueYear); var gamesGroupedByPublisherAndGame = activeBidsForLeague.GroupBy(x => (x.Publisher.PublisherID, x.MasterGame.MasterGameID)); var duplicateBidGroups = gamesGroupedByPublisherAndGame.Where(x => x.Count() > 1).ToList(); List <PickupBid> duplicateBids = new List <PickupBid>(); foreach (var duplicateBidGroup in duplicateBidGroups) { var bestBid = duplicateBidGroup.WhereMax(x => x.BidAmount).WhereMin(x => x.Timestamp).First(); var otherBids = duplicateBidGroup.Except(new List <PickupBid>() { bestBid }); duplicateBids.AddRange(otherBids); } var nonDuplicateBids = activeBidsForLeague.Except(duplicateBids); List <PickupBid> noSpaceLeftBids = new List <PickupBid>(); List <PickupBid> insufficientFundsBids = new List <PickupBid>(); List <PickupBid> belowMinimumBids = new List <PickupBid>(); List <KeyValuePair <PickupBid, string> > invalidGameBids = new List <KeyValuePair <PickupBid, string> >(); var currentDate = processingTime.ToEasternDate(); List <ValidPickupBid> validPickupBids = new List <ValidPickupBid>(); foreach (var activeBid in nonDuplicateBids) { Publisher bidPublisher = publisherStateSet.GetPublisher(activeBid.Publisher.PublisherID); bool counterPickedGameIsManualWillNotRelease = PlayerGameExtensions.CounterPickedGameIsManualWillNotRelease(updatedLeagueYear, activeBid.CounterPick, activeBid.MasterGame, true); var gameRequest = new ClaimGameDomainRequest(updatedLeagueYear, bidPublisher, activeBid.MasterGame.GameName, activeBid.CounterPick, counterPickedGameIsManualWillNotRelease, false, false, activeBid.MasterGame, null, null); PickupBid pickupBidWithConditionalDropResult = activeBid; int? validConditionalDropSlot = null; if (activeBid.ConditionalDropPublisherGame is not null) { var conditionalDropResult = _gameAcquisitionService.CanConditionallyDropGame(activeBid, updatedLeagueYear, bidPublisher, processingTime); pickupBidWithConditionalDropResult = activeBid.WithConditionalDropResult(conditionalDropResult); if (conditionalDropResult.Result.IsSuccess) { validConditionalDropSlot = activeBid.ConditionalDropPublisherGame.SlotNumber; } } var claimResult = _gameAcquisitionService.CanClaimGame(gameRequest, null, validConditionalDropSlot, true, false); if (claimResult.NoSpaceError) { noSpaceLeftBids.Add(pickupBidWithConditionalDropResult); continue; } if (!claimResult.Success) { invalidGameBids.Add(new KeyValuePair <PickupBid, string>(pickupBidWithConditionalDropResult, string.Join(" AND ", claimResult.Errors.Select(x => x.Error)))); continue; } if (pickupBidWithConditionalDropResult.BidAmount > bidPublisher.Budget) { insufficientFundsBids.Add(pickupBidWithConditionalDropResult); continue; } if (pickupBidWithConditionalDropResult.BidAmount < updatedLeagueYear.Options.MinimumBidAmount) { belowMinimumBids.Add(pickupBidWithConditionalDropResult); continue; } validPickupBids.Add(new ValidPickupBid(pickupBidWithConditionalDropResult, claimResult.BestSlotNumber !.Value)); } var winnableBids = GetWinnableBids(updatedLeagueYear, validPickupBids, systemWideValues, currentDate); var winningBids = GetWinningBids(winnableBids); var takenGames = winningBids.Select(x => x.PickupBid.MasterGame); var losingBids = activeBidsForLeague .Except(winningBids.Select(x => x.PickupBid)) .Except(duplicateBids) .Except(noSpaceLeftBids) .Except(insufficientFundsBids) .Except(belowMinimumBids) .Except(invalidGameBids.Select(x => x.Key)) .Where(x => takenGames.Contains(x.MasterGame)) .Select(x => new FailedPickupBid(x, "Publisher was outbid.", systemWideValues, currentDate)); var duplicateBidFailures = duplicateBids.Select(x => new FailedPickupBid(x, "You cannot have multiple bids for the same game. This bid has been ignored.", systemWideValues, currentDate)); var invalidGameBidFailures = invalidGameBids.Select(x => new FailedPickupBid(x.Key, "Game is no longer eligible: " + x.Value, systemWideValues, currentDate)); var insufficientFundsBidFailures = insufficientFundsBids.Select(x => new FailedPickupBid(x, "Not enough budget.", systemWideValues, currentDate)); var belowMinimumBidFailures = belowMinimumBids.Select(x => new FailedPickupBid(x, "Bid is below the minimum bid amount.", systemWideValues, currentDate)); List <FailedPickupBid> noSpaceLeftBidFailures = new List <FailedPickupBid>(); foreach (var noSpaceLeftBid in noSpaceLeftBids) { FailedPickupBid failedBid; if (noSpaceLeftBid.ConditionalDropPublisherGame is not null && noSpaceLeftBid.ConditionalDropResult !.Result.IsFailure) { failedBid = new FailedPickupBid(noSpaceLeftBid, "No roster spots available. Attempted to conditionally drop game: " + $"{noSpaceLeftBid.ConditionalDropPublisherGame.MasterGame!.MasterGame.GameName} " + $"but failed because: {noSpaceLeftBid.ConditionalDropResult.Result.Error}", systemWideValues, currentDate); }
public FailedPickupBid(PickupBid pickupBid, string failureReason, SystemWideValues systemWideValues, LocalDate currentDate) { PickupBid = pickupBid; FailureReason = failureReason; ProjectedPointsAtTimeOfBid = PickupBid.Publisher.GetProjectedFantasyPoints(pickupBid.LeagueYear, systemWideValues, currentDate); }
public Task RemovePickupBid(PickupBid bid) { throw new NotImplementedException(); }
public Task CreatePickupBid(PickupBid currentBid) { throw new NotImplementedException(); }
public async Task <ClaimResult> MakePickupBid(LeagueYear leagueYear, Publisher publisher, MasterGame masterGame, PublisherGame?conditionalDropPublisherGame, bool counterPick, uint bidAmount) { if (bidAmount < leagueYear.Options.MinimumBidAmount) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("That bid does not meet the league's minimum bid.", false) }, null)); } if (bidAmount > publisher.Budget) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("You do not have enough budget to make that bid.", false) }, null)); } IReadOnlyList <PickupBid> pickupBids = await _fantasyCriticRepo.GetActivePickupBids(leagueYear, publisher); bool alreadyBidFor = pickupBids.Select(x => x.MasterGame.MasterGameID).Contains(masterGame.MasterGameID); if (alreadyBidFor) { return(new ClaimResult(new List <ClaimError>() { new ClaimError("You cannot have two active bids for the same game.", false) }, null)); } bool counterPickedGameIsManualWillNotRelease = false; if (counterPick) { var gameBeingCounterPickedOptions = leagueYear.Publishers.Select(x => x.GetPublisherGame(masterGame)) .Where(x => x is not null && !x.CounterPick).SelectNotNull().ToList(); if (gameBeingCounterPickedOptions.Count != 1) { throw new Exception($"Something very strange has happened with bid processing for publisher: {publisher.PublisherID}"); } counterPickedGameIsManualWillNotRelease = gameBeingCounterPickedOptions.Single().ManualWillNotRelease; } var claimRequest = new ClaimGameDomainRequest(leagueYear, publisher, masterGame.GameName, counterPick, counterPickedGameIsManualWillNotRelease, false, false, masterGame, null, null); Instant nextBidTime = _clock.GetNextBidTime(); int?validDropSlot = null; if (conditionalDropPublisherGame is not null) { if (counterPick) { return(new ClaimResult("Cannot make a counter pick bid with a conditional drop.", null)); } var dropResult = await MakeDropRequest(leagueYear, publisher, conditionalDropPublisherGame, true); if (dropResult.Result.IsFailure) { return(new ClaimResult(dropResult.Result.Error, null)); } validDropSlot = conditionalDropPublisherGame.SlotNumber; } var claimResult = CanClaimGame(claimRequest, nextBidTime, validDropSlot, false, false); if (!claimResult.Success) { return(claimResult); } var nextPriority = pickupBids.Count + 1; PickupBid currentBid = new PickupBid(Guid.NewGuid(), publisher, leagueYear, masterGame, conditionalDropPublisherGame, counterPick, bidAmount, nextPriority, _clock.GetCurrentInstant(), null, null, null, null); await _fantasyCriticRepo.CreatePickupBid(currentBid); return(claimResult); }
public ValidPickupBid(PickupBid pickupBid, int slotNumber) { PickupBid = pickupBid; SlotNumber = slotNumber; }