Пример #1
0
        private async Task <TimesheetBasicData[]> GetTimesheetBasicDataAsync(TimesheetStates state, DateTime date, DateTime startOfWeek)
        {
            var timesheets = new List <OpenAirClient.Timesheet>();

            if (state == TimesheetStates.Unsubmitted)
            {
                var nextDay = date.AddDays(1);
                timesheets.AddRange(await _client.GetTimesheetsByStatusAsync(startOfWeek, nextDay, "S"));
                timesheets.AddRange(await _client.GetTimesheetsByStatusAsync(startOfWeek, nextDay, "A"));
            }
            else if (state == TimesheetStates.Unapproved)
            {
                var lastWeek = startOfWeek.AddDays(-DaysInWeek);
                timesheets.AddRange(await _client.GetTimesheetsByStatusAsync(lastWeek, startOfWeek, "A"));
            }

            var timesheetsData = timesheets
                                 .GroupBy(it => it.UserId)
                                 .Select(it =>
                                         new TimesheetBasicData(
                                             it.Key.Value,
                                             it.Where(sheet => sheet.StartDate.Date > startOfWeek)
                                             .Where(sheet =>
                                                    (state == TimesheetStates.Unapproved && sheet.Status == "A") ||
                                                    (state == TimesheetStates.Unsubmitted && (sheet.Status == "S" || sheet.Status == "A")))
                                             .Sum(sheet => sheet.Total ?? 0)))
                                 .ToArray();

            return(timesheetsData);
        }
Пример #2
0
        private async Task SendNotificationsAsync(
            Dictionary <string, IReadOnlyList <Timesheet> > timesheets,
            string key,
            string email,
            bool notify,
            TimesheetStates state,
            DateTime scheduleDate,
            GoogleChatAddress address,
            IReadOnlyList <string> customerToExcludes,
            ITimesheetProcessor processor)
        {
            if (!timesheets.TryGetValue(key, out var timesheetValues))
            {
                timesheetValues = await processor.GetTimesheetsAsync(scheduleDate, state, email, true, customerToExcludes);

                timesheets.Add(key, timesheetValues);
            }

            await processor.SendTimesheetNotificationsToUsersAsync(
                timesheetValues,
                email,
                department : null,
                notify : notify,
                notifyByEmail : false,
                state,
                address,
                _hangoutsChatConnector);
        }
Пример #3
0
 /// <summary>Get timesheets and notifies by message or email the users asynchronous.</summary>
 public async Task NotifyAsync(
     DateTime date,
     TimesheetStates state,
     string email,
     IReadOnlyList <string> customersToExclude,
     string department,
     bool notify,
     bool notifyByEmail,
     bool filterOutSender,
     GoogleChatAddress address,
     IHangoutsChatConnector connector) =>
 await SendTimesheetNotificationsToUsersAsync(
     await _openAirConnector.GetUnsubmittedTimesheetsAsync(
         date,
         Contract.LocalDateTime.Date,
         state,
         email,
         filterOutSender,
         TimesheetsProperties.UserMaxHours,
         customersToExclude),
     email,
     department,
     notify,
     notifyByEmail,
     state,
     address,
     connector);
Пример #4
0
 /// <inheritdoc/>
 public Task <IReadOnlyList <Timesheet> > GetTimesheetsAsync(
     DateTime dateTime,
     TimesheetStates state,
     string senderEmail,
     bool filterOutSender,
     IReadOnlyList <string> customersToExclude) =>
 _openAirConnector.GetUnsubmittedTimesheetsAsync(
     dateTime,
     Contract.LocalDateTime.Date,
     state,
     senderEmail,
     filterOutSender,
     TimesheetsProperties.UserMaxHours,
     customersToExclude);
Пример #5
0
        private async Task SaveGlobalStatisticsAsync(
            DateTime scheduleDate,
            IReadOnlyList <string> customerToExcludes,
            IPluginPropertiesAccessor accessor,
            ITimesheetProcessor processor)
        {
            var group = accessor.GetPluginPropertyGroup(TimesheetsProperties.GlobalStatisticsGroup).FirstOrDefault();

            if (group == null)
            {
                return;
            }

            var cron = group.GetValue <string>(TimesheetsProperties.GlobalStatisticsCron);

            if (string.IsNullOrEmpty(cron) ||
                !CronCheck(cron, scheduleDate))
            {
                return;
            }

            const TimesheetStates state = TimesheetStates.Unsubmitted;
            var dateValue  = scheduleDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
            var timeValue  = scheduleDate.ToString("HH:00", CultureInfo.InvariantCulture);
            var email      = group.GetValue <string>(TimesheetsProperties.GlobalStatisticsEmail);
            var timesheets = await processor.GetTimesheetsAsync(scheduleDate, state, email, true, customerToExcludes);

            var statistics = new Statistics <TimesheetStatistics[]>
            {
                Id   = Guid.NewGuid().ToString(),
                Date = dateValue,
                Time = timeValue,
                Type = nameof(TimesheetStatistics),
                Data = timesheets
                       .Select(it =>
                               new TimesheetStatistics
                {
                    UserName       = it.UserName,
                    ManagerName    = it.ManagerName,
                    DepartmentName = it.DepartmentName,
                    State          = state,
                })
                       .ToArray()
            };

            await _storageService.AddOrUpdateStatisticsAsync(statistics);
        }
Пример #6
0
 /// <summary>Get timesheets and notifies by message or email the users asynchronous.</summary>
 public Task NotifyAsync(
     DateTime date,
     TimesheetStates state,
     string email,
     string[] customersToExclude,
     string department,
     bool notify,
     bool notifyByEmail,
     GoogleChatAddress address,
     IHangoutsChatConnector connector) =>
 _openAirConnector.GetUnsubmittedTimesheetsAsync(date, state, email, customersToExclude)
 .ContinueWith(task => ProcessNotifyAsync(
                   task.Result,
                   email,
                   department,
                   notify,
                   notifyByEmail,
                   state,
                   address,
                   connector));
Пример #7
0
        /// <inheritdoc/>
        public async Task <IReadOnlyList <Timesheet> > GetUnsubmittedTimesheetsAsync(DateTime date, TimesheetStates state, string senderEmail, string[] filterByCustomers)
        {
            var requiredHours           = date.DayOfWeek == DayOfWeek.Saturday ? 40 : (int)date.DayOfWeek * 8;
            var toweek                  = date.AddDays(-(double)date.DayOfWeek);
            var lastWeek                = toweek.AddDays(-7);
            var timesheets              = new List <OpenAirClient.Timesheet>();
            var normalizedCustomerNames = filterByCustomers?.Select(NormalizeValue).ToArray();

            timesheets.AddRange(await _client.GetTimesheetsAsync(lastWeek, lastWeek.AddDays(2)));
            timesheets.AddRange(await _client.GetTimesheetsAsync(toweek, date.AddDays(1)));

            var timesheetsData = timesheets
                                 .GroupBy(it => it.UserId)
                                 .Select(it =>
                                         new TimesheetBasicData(
                                             it.Key.Value,
                                             it.FirstOrDefault()?.Name,
                                             it.Where(sheet => sheet.StartDate.Date > toweek)
                                             .Where(sheet =>
                                                    (state == TimesheetStates.Unapproved && sheet.Status == "A") ||
                                                    (state == TimesheetStates.Unsubmitted && (sheet.Status == "S" || sheet.Status == "A")))
                                             .Sum(sheet => sheet.Total ?? 0)))
                                 .ToArray();

            var users = await _storageService.GetAllActiveUsersAsync();

            // 0. Filter out the sender.
            // 1. Filter out only users where the sender is line manager.
            // 2. Filter out customers.
            // 3. Select timesheet
            var result = users
                         .Where(it => it.Email != senderEmail)
                         .Where(it => IsManager(it, senderEmail, users, new List <string>()))
                         .Where(it => FiterCustomersByNames(it.Customers, normalizedCustomerNames))
                         .Select(user => new TimesheetExtendedData(timesheetsData.FirstOrDefault(it => it.UserId == user.OpenAirUserId), user))
                         .Where(it => it.Timesheet.Total < requiredHours)
                         .Select(it => new Timesheet
            {
                Name           = it.Timesheet.Name,
                Total          = it.Timesheet.Total,
                UserName       = FormatDisplayName(it.User.Name),
                UserEmail      = it.User.Email,
                DepartmentName = it.User.Department.Name,
                ManagerName    = FormatDisplayName(FindUser(it.User.Manager, users)?.Name)
            })
                         .ToArray();

            return(result);
        }
Пример #8
0
 /// <summary>Gets the open air text.</summary>
 public static string GetText(TimesheetStates state, OpenAirTextTypes type) =>
 Phrases[type.ToString() + state];
Пример #9
0
        /// <inheritdoc/>
        public async Task <IReadOnlyList <Timesheet> > GetUnsubmittedTimesheetsAsync(
            DateTime date,
            DateTime today,
            TimesheetStates state,
            string senderEmail,
            bool filterSender,
            string userPropertyMaxHoursKey,
            IReadOnlyList <string> filterByCustomers)
        {
            var startOfWeek    = date.AddDays(-(double)date.DayOfWeek);
            var timesheetsData = await GetTimesheetBasicDataAsync(state, date, startOfWeek);

            var users = await _storageService.GetAllActiveUsersAsync();

            var normalizedCustomerNames = filterByCustomers?.Select(NormalizeValue).ToArray();
            var isEndOfMonthReport      = date.Date == today && today.AddDays(1).Day == 1;
            var isTodayWeekend          = today.DayOfWeek == DayOfWeek.Saturday || today.DayOfWeek == DayOfWeek.Sunday;
            var dayOfWeekMultiplier     = isTodayWeekend ? WorkDaysInWeek : (int)today.DayOfWeek;

            // 1. Filter out user that are not started.
            // 2. Filter out users by a predefined list of emails
            // 3. Filter out only users where the sender is line manager.
            // 4. Filter out customers.
            // 5. Select timesheet
            var result = users
                         .Where(it => !it.StartDate.HasValue || it.StartDate <= today)
                         .Where(it =>
                                !filterSender ||
                                !senderEmail.Equals(it.Email, StringComparison.InvariantCultureIgnoreCase))
                         .Where(it => it.Manager != null)
                         .Where(it =>
            {
                try
                {
                    return((it.Department?.Owner?.Email.Equals(senderEmail, StringComparison.InvariantCultureIgnoreCase) ?? false) ||
                           users.IsRequestorManager(it, senderEmail));
                }
                catch (Exception ex)
                {
                    Debug.Write(ex.Message);
                    return(false);
                }
            })
                         .Where(it =>
            {
                try
                {
                    return(FilterCustomersByNames(it.Customers, normalizedCustomerNames));
                }
                catch (Exception ex)
                {
                    Debug.Write(ex.Message);
                    return(false);
                }
            })
                         .Select(user =>
            {
                try
                {
                    // Normally how many hours this users should work in week?
                    var requiredUserHoursPerWeek = user.Properties
                                                   .GetAllUserValues <int>(userPropertyMaxHoursKey)
                                                   .DefaultIfEmpty(WorkingHoursInWeek)
                                                   .First();

                    var requiredDays = WorkDaysInWeek;

                    // If user starts that week, calculate valid dates.
                    if (user.StartDate.HasValue && user.StartDate.Value >= startOfWeek && user.StartDate.Value <= date)
                    {
                        // If date difference + 1. So if we start today (date (today) - startDate (today)) + 1 = 1.
                        requiredDays = (date.Date - user.StartDate.Value).Days + 1;
                    }
                    else if (isEndOfMonthReport)
                    {
                        requiredDays = dayOfWeekMultiplier;
                    }

                    return(new TimesheetExtendedData(
                               timesheetsData.FirstOrDefault(it => it.UserId == user.OpenAirUserId),
                               user,
                               requiredHours: (requiredUserHoursPerWeek / WorkDaysInWeek) * requiredDays));
                }
                catch (Exception ex)
                {
                    Debug.Write(ex.Message);
                    return(new TimesheetExtendedData(null, user, WorkingHoursInWeek));
                }
            })
                         .Where(it => it.Timesheet.Total < it.RequiredHours)
                         .Select(it => new Timesheet
            {
                Total = it.Timesheet.Total,
                UtilizationInHours = it.RequiredHours,
                UserName           = FormatDisplayName(it.User?.Name ?? "Unknown User"),
                UserEmail          = it.User.Email,
                DepartmentName     = it.User.Department.Name,
                ManagerName        = FormatDisplayName(users.FindUserByRef(it.User.Manager)?.Name)
            })
                         .ToArray();

            return(result);
        }
Пример #10
0
        private async Task <IReadOnlyList <string> > NotifyUsersOverChatAsync(
            IHangoutsChatConnector connector,
            TimesheetStates state,
            Timesheet[] timesheets)
        {
            var notifiedUserList   = new List <string>();
            var addressesForUpdate = new List <GoogleAddress>();
            var storeAddresses     = await _storageService.GetAddressesAsync();

            var emails            = timesheets.Select(it => it.UserEmail).ToArray();
            var filteredAddresses = storeAddresses.Where(it => emails.Contains(it.UserEmail)).ToArray();

            IReadOnlyList <GoogleAddress> privateAddresses = new GoogleAddress[0];

            if (filteredAddresses.Length < timesheets.Length)
            {
                var storeAddressesNames = storeAddresses.Select(it => it.SpaceName).Distinct().ToArray();
                privateAddresses = connector
                                   .GetPrivateAddress(storeAddressesNames)
                                   .Select(it => new GoogleAddress
                {
                    SpaceName       = it.Space.Name,
                    UserName        = it.Sender.Name,
                    UserDisplayName = it.Sender.DisplayName
                })
                                   .ToArray();

                // Store inactive spaces, so not to be requested the next time
                addressesForUpdate.AddRange(privateAddresses.Where(it => it.UserName == null));
            }

            var textMessage = OpenAirText.GetText(state, OpenAirTextTypes.Notify);

            foreach (var timesheet in timesheets)
            {
                var message = timesheet.UserName + textMessage;
                var addr    = filteredAddresses.FirstOrDefault(it => it.UserEmail == timesheet.UserEmail);
                if (addr == null)
                {
                    addr = privateAddresses.FirstOrDefault(it => it.UserDisplayName == timesheet.UserName);
                    if (addr == null)
                    {
                        continue;
                    }

                    addr.UserEmail = timesheet.UserEmail;

                    addressesForUpdate.Add(addr);
                }

                notifiedUserList.Add(timesheet.UserName);

                await connector.SendMessageAsync(
                    message,
                    new GoogleChatAddress(addr.SpaceName, string.Empty, "DM", addr.UserName, addr.UserDisplayName));
            }

            if (addressesForUpdate.Count > 0)
            {
                await _storageService.AddAddressesAsync(addressesForUpdate);
            }

            return(notifiedUserList);
        }
Пример #11
0
        /// <summary>Processes the specified timesheets.</summary>
        public async Task SendTimesheetNotificationsToUsersAsync(
            IReadOnlyList <Timesheet> timesheets,
            string email,
            string department,
            bool notify,
            bool notifyByEmail,
            TimesheetStates state,
            GoogleChatAddress address,
            IHangoutsChatConnector connector)
        {
            string text;
            var    filteredTimesheet = timesheets
                                       .Where(it =>
                                              department == null ||
                                              department.Equals(it.DepartmentName, StringComparison.InvariantCultureIgnoreCase))
                                       .OrderBy(it => it.ManagerName)
                                       .ThenBy(it => it.UserName)
                                       .ToArray();

            var notifiedUserList = new List <string>();

            if (filteredTimesheet.Length == 0)
            {
                var responses = OpenAirText.GetText(state, OpenAirTextTypes.AllAreDone).Split('|', StringSplitOptions.RemoveEmptyEntries);
                var rand      = new Random();
                text = responses[rand.Next(0, responses.Length - 1)];
            }
            else if (notify && filteredTimesheet.Length > 0)
            {
                notifiedUserList.AddRange(
                    await NotifyUsersOverChatAsync(connector, state, filteredTimesheet));

                if (notifyByEmail)
                {
                    var textMessage = OpenAirText.GetText(state, OpenAirTextTypes.Notify);
                    var emails      = filteredTimesheet
                                      .Where(it => !notifiedUserList.Contains(it.UserName))
                                      .Apply(it => notifiedUserList.Add(it.UserName))
                                      .Select(it => it.UserEmail)
                                      .Distinct()
                                      .ToArray();

                    await _mailService.SendMailAsync("Timesheet is pending", textMessage, emails);
                }

                text = notifiedUserList.Count == filteredTimesheet.Length ?
                       string.Format(
                    CultureInfo.InvariantCulture,
                    OpenAirText.GetText(state, OpenAirTextTypes.AllAreNotified),
                    notifiedUserList.Count) :
                       OpenAirText.GetText(state, OpenAirTextTypes.SomeAreNotified) + GetCardText(filteredTimesheet, notifiedUserList);
            }
            else
            {
                text = OpenAirText.GetText(state, OpenAirTextTypes.SomeAreDone) + GetCardText(filteredTimesheet, notifiedUserList);
            }

            var paragraph = new TextParagraph {
                Text = text
            };
            var card = ChatEventFactory.CreateCard(paragraph);

            if (address != null)
            {
                await connector.SendMessageAsync(null, address, card);
            }
            else if (email != null)
            {
                var emailedUsers = string.Join("</b><br/><b>", notifiedUserList);
                var emailText    =
                    $"{text}<br/><br/><b>The following people where notified by a direct massage or email:" +
                    $"<br/><b>{emailedUsers}</b>";
                await _mailService.SendMailAsync("Users not notified", emailText, email);
            }
        }