Example #1
0
        private List <LottoPrizeInfoModel> GetPrizeInfo(LottoItemModel lottoItem)
        {
            var prizeInfo         = new List <LottoPrizeInfoModel>();
            var totalAmount       = lottoItem.Rate * lottoItem.TicketsInDraw;
            var siteFee           = (totalAmount / 100m) * lottoItem.Fee;
            var prizePool         = totalAmount - siteFee;
            var prizePoolFraction = prizePool / 100m;
            var prizeWeights      = LottoHelpers.GetPrizeWeights(lottoItem.Prizes);

            for (int i = 0; i < prizeWeights.Count; i++)
            {
                prizeInfo.Add(new LottoPrizeInfoModel
                {
                    Percentage = prizeWeights[i],
                    Position   = (i + 1),
                    Prize      = Math.Round(prizePoolFraction * prizeWeights[i], 8)
                });
            }
            return(prizeInfo);
        }
        /// <summary>
        /// Processes the lotto items.
        /// </summary>
        private async Task ProcessLotto()
        {
            try
            {
                var payouts = new List <PrizePayout>();
                using (var context = ExchangeDataContextFactory.CreateContext())
                {
                    Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItems...");
                    var dueLottoDraws = await context.LottoItem.Where(x => x.Status != LottoItemStatus.Disabled && DateTime.UtcNow >= x.NextDraw).ToListNoLockAsync();

                    if (dueLottoDraws.IsNullOrEmpty())
                    {
                        // no draws ready
                        Log.Message(LogLevel.Info, "[ProcessLotto] - No lotto draws are due, Waiting...");
                        return;
                    }

                    Log.Message(LogLevel.Info, "[ProcessLotto] - {0} lotto draws found.", dueLottoDraws.Count());
                    foreach (var lottoDraw in dueLottoDraws)
                    {
                        Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItem, Id: {0}, Name: {1}, Currency: {2}", lottoDraw.Id, lottoDraw.Name, lottoDraw.CurrencyId);
                        // 1. sum up total tickets, subtract site fee
                        var tickets = await context.LottoTicket.Where(x => !x.IsArchived && x.LottoItemId == lottoDraw.Id && x.DrawId == lottoDraw.CurrentDrawId).ToListNoLockAsync();

                        if (!tickets.IsNullOrEmpty())
                        {
                            Log.Message(LogLevel.Info, "[ProcessLotto] - {0} tickets found for draw.", tickets.Count());
                            // Archive all the tickets
                            foreach (var ticket in tickets)
                            {
                                ticket.IsArchived = true;
                            }

                            // Calculate prize pool
                            var totalAmount       = lottoDraw.Rate * tickets.Count();
                            var siteFee           = (totalAmount / 100m) * lottoDraw.Fee;
                            var prizePool         = totalAmount - siteFee;
                            var prizePoolFraction = prizePool / 100m;
                            var prizeWeights      = LottoHelpers.GetPrizeWeights(lottoDraw.Prizes);
                            var winningTicketIds  = GetWinningLottoItemIds(tickets.Select(x => x.Id), lottoDraw.Prizes);
                            Log.Message(LogLevel.Info, "[ProcessLotto] - LottoItem draw info, Total: {0}, PrizePool: {1}, Fee: {2}", totalAmount, prizePool, siteFee);

                            // Calculate user prizes
                            var drawTime = lottoDraw.NextDraw;
                            for (int i = 0; i < prizeWeights.Count; i++)
                            {
                                var prizeWeight   = prizeWeights[i];
                                var winningTicket = tickets.FirstOrDefault(x => x.Id == winningTicketIds[i]);
                                var amount        = Math.Round(prizePoolFraction * prizeWeight, 8);
                                payouts.Add(new PrizePayout
                                {
                                    UserId     = winningTicket.UserId,
                                    CurrencyId = lottoDraw.CurrencyId,
                                    Amount     = amount
                                });
                                context.LottoHistory.Add(new LottoHistory
                                {
                                    Amount        = amount,
                                    Percent       = prizeWeight,
                                    LottoItemId   = lottoDraw.Id,
                                    Position      = (i + 1),
                                    Timestamp     = drawTime,
                                    UserId        = winningTicket.UserId,
                                    LottoTicketId = winningTicket.Id,
                                    LottoDrawId   = lottoDraw.CurrentDrawId,
                                    TotalAmount   = prizePool
                                });
                                Log.Message(LogLevel.Info, "[ProcessLotto] - User payout info, UserId: {0}, Position: {1}, Weight: {2}, Amount: {3}", winningTicket.UserId, (i + 1), prizeWeight, amount);
                            }
                        }
                        else
                        {
                            Log.Message(LogLevel.Info, "[ProcessLotto] - No tickets found for draw.");
                        }

                        // 5. update LottoItem
                        lottoDraw.Status = LottoItemStatus.Finished;
                        if (lottoDraw.LottoType == LottoType.Recurring || (lottoDraw.LottoType == LottoType.RecurringExpire && lottoDraw.Expires > DateTime.UtcNow))
                        {
                            lottoDraw.Status        = LottoItemStatus.Active;
                            lottoDraw.CurrentDrawId = lottoDraw.CurrentDrawId + 1;
                            lottoDraw.NextDraw      = lottoDraw.NextDraw.AddHours(lottoDraw.Hours);
                            Log.Message(LogLevel.Info, "[ProcessLotto] - Set next draw date for recurring lotto, NextDraw: {0}", lottoDraw.NextDraw);
                        }

                        Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItem complete.");
                    }

                    // commit the transaction
                    Log.Message(LogLevel.Debug, "[ProcessLotto] - Comitting database transaction...");
                    await context.SaveChangesAsync();

                    Log.Message(LogLevel.Debug, "[ProcessLotto] - Comitted database transaction.");
                }

                // Send Winnings
                await PayoutUsers(payouts);

                Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItems complete.");
            }
            catch (Exception ex)
            {
                Log.Exception("[ProcessLotto] - An exception occured processing LottoItem.", ex);
            }
        }