using System.Text; using FsToolbox.Cli.Helper; using FsToolbox.Cli.Tasks; using NLog; namespace FsToolbox.Cli { public partial class CustomTasks { private static readonly Logger Logger = LoggingService.GetLogger(); #region Public Method CheckAldiMembershipsAsync /// /// Analyzes ALDI store memberships in the Siegen region and writes users with multiple memberships to a report file. /// /// The HTTP client used to perform the requests. public static async Task CheckAldiMembershipsAsync(HttpClient httpClient) { await AuthHelper.EnsureAuthenticationAsync(httpClient); // Implementation for checking Aldi memberships would go here. var stores = await RegionTasks.GetStoresInRegionAsync(httpClient, 139); var activeAldis = stores.Where(x => x.CooperationStatus == RegionTasks.CooperationStatus.Cooperating && x.Name.Contains("ALDI", StringComparison.CurrentCultureIgnoreCase)).ToList(); Logger.Info("Found {ActiveCount} active ALDI stores in region Siegen.", activeAldis.Count); var aldiMembers = new List(); // Collect members from each active ALDI store foreach (var activeAldi in activeAldis) { Thread.Sleep(200); Logger.Info("Checking members for store: {Store}", activeAldi.Name); var members = await StoreTasks.GetStoreMembersAsync(httpClient, activeAldi.Id); var activeMembers = members.Where(x => x is { Verified: StoreTasks.VerifiedStatus.Verified, Team_Active: StoreTasks.TeamActiveStatus.Active }).ToList(); activeMembers.ForEach(x => aldiMembers.Add(new(activeAldi, x))); } // Group memberships var grouped = aldiMembers.GroupBy(x => x.Member.Id); // Find groups with more than two memberships var multipleMemberships = grouped.Where(g => g.Count() > 2).OrderByDescending(g => g.Count()).ToList(); Logger.Info("Users with more than two ALDI store memberships: {Count}", multipleMemberships.Count); Logger.Info("Saving data to file."); var sb = new StringBuilder(); sb.AppendLine("ALDI Store Memberships Report"); sb.AppendLine("Generated: " + DateTime.Now.ToString("dd.MM.yyyy HH:mm")); sb.AppendLine("============================"); sb.AppendLine(); foreach (var group in multipleMemberships) { sb.AppendLine($"{group.First().Member.Name} ({group.Key}) - {group.Count()} ALDIs"); foreach (var membership in group) sb.AppendLine($" - {membership.Store.Name}"); sb.AppendLine(); } // Write to file with timestamp var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); var filename = $"AldiMemberships_{timestamp}.txt"; await File.WriteAllTextAsync(filename, sb.ToString()); } #endregion #region Public Method AnalyzeSlotUnregistrationsAsync /// /// Retrieves the store log for the first cooperating store in region 135 for the last month. /// /// The HTTP client used to perform the requests. public static async Task AnalyzeSlotUnregistrationsAsync(HttpClient httpClient) { await AuthHelper.EnsureAuthenticationAsync(httpClient); var stores = await RegionTasks.GetStoresInRegionAsync(httpClient, 139); var cooperatingStores = stores.Where(x => x.CooperationStatus == RegionTasks.CooperationStatus.Cooperating).ToList(); if (cooperatingStores.Count == 0) { Logger.Info("No cooperating stores found in region 139."); return; } var fromDate = DateTime.Today.AddMonths(-1).ToString("yyyy-MM-dd"); var toDate = DateTime.Today.ToString("yyyy-MM-dd"); const string storeLogActionIds = "12"; var collected = new List(); foreach (var store in cooperatingStores) { Logger.Info("Fetching store log for {StoreId} {StoreName} ({From} to {To})", store.Id, store.Name, fromDate, toDate); var logEntries = await StoreTasks.GetStoreLogEntriesAsync(httpClient, store.Id, fromDate, toDate, storeLogActionIds); foreach (var entry in logEntries) { if (entry.ActingFoodsaver == null) continue; collected.Add(new StoreLogProfileEntry(entry.ActingFoodsaver, store, entry.DateReference, entry.PerformedAt)); } Logger.Info("Collected {Count} log entries for {StoreName}.", collected.Count, store.Name); Thread.Sleep(1000); } // Group entries by profile and sort by count var grouped = collected .GroupBy(x => x.Profile.Id) .Select(g => new { Profile = g.First().Profile, Count = g.Count() }) .OrderByDescending(x => x.Count) .ToList(); // Create txt file report var sb = new StringBuilder(); sb.AppendLine("Store Log Unregistration Report"); sb.AppendLine("Generated: " + DateTime.Now.ToString("dd.MM.yyyy HH:mm")); sb.AppendLine($"Timeframe: {fromDate} to {toDate}"); sb.AppendLine($"Total analyzed stores: {cooperatingStores.Count} (cooperating)"); sb.AppendLine($"Total unregistrations: {collected.Count}"); sb.AppendLine("Region: Siegen (139)"); sb.AppendLine("============================"); sb.AppendLine(); foreach (var entry in grouped) { sb.AppendLine($"{entry.Profile.Name} ({entry.Profile.Id}) - {entry.Count} unregistrations"); sb.AppendLine("----------------------------"); // List the stores and dates var userEntries = collected .Where(x => x.Profile.Id == entry.Profile.Id) .OrderBy(x => x.DateReference) .ToList(); foreach (var userEntry in userEntries) sb.AppendLine($" - {userEntry.Store.Name} on {userEntry.DateReference} (Performed at: {userEntry.PerformedAt})"); sb.AppendLine(); } // Write to file with timestamp var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); var filename = $"SlotUnregistrations_{timestamp}.txt"; await File.WriteAllTextAsync(filename, sb.ToString()); } #endregion #region Public Method ConfirmUnconfirmedPickupsLindenbergAsync /// /// Confirms all unconfirmed pickup slots for the configured Lindenberg store after user confirmation. /// /// The HTTP client used to perform the requests. public static async Task ConfirmUnconfirmedPickupsLindenbergAsync(HttpClient httpClient) { await AuthHelper.EnsureAuthenticationAsync(httpClient); var toConfirm = new List<(string Name, string Date, int User)>(); // Collect unconfirmed slots var pickups = await StoreTasks.GetPickupsAsync(httpClient, 56749); foreach (var pickup in pickups) foreach (var slot in pickup.OccupiedSlots) if (!slot.IsConfirmed) { var pickupDate = pickup.Date; var userId = slot.Profile.Id; var userName = slot.Profile.Name; toConfirm.Add((userName, pickupDate, userId)); } if (toConfirm.Count != 0) { toConfirm.ForEach(x => Logger.Info("Slot found: {Name} on {Date}", x.Name, x.Date)); } else { Logger.Info("No unconfirmed slots found."); return; } // Confirm question Logger.Info("Confirm all unconfirmed slots? (y/n) (Enter for default): "); var input = Console.ReadLine(); if (string.IsNullOrEmpty(input) || input.Equals("y", StringComparison.OrdinalIgnoreCase)) { Logger.Info("Confirming unconfirmed slots..."); // Confirm the unconfirmed slots foreach (var confirmEntry in toConfirm) await StoreTasks.PatchPickupAsync(httpClient, 52170, confirmEntry.Date, confirmEntry.User); Logger.Info("Done confirming slots."); } } #endregion } }