AppDataInit.cs
25,871 bytes
| 1 | using Microsoft.EntityFrameworkCore; |
|---|---|
| 2 | using SplitApp.Modules.Expenses.Domain.Entities; |
| 3 | using SplitApp.Modules.Expenses.Domain.Enums; |
| 4 | using SplitApp.Modules.Expenses.Infrastructure.Persistence; |
| 5 | using SplitApp.Modules.Trips.Domain.Entities; |
| 6 | using SplitApp.Modules.Trips.Domain.Enums; |
| 7 | using SplitApp.Modules.Trips.Infrastructure.Persistence; |
| 8 | using SplitApp.Modules.Users.Infrastructure.Persistence; |
| 9 | using SplitApp.Shared.Kernel.Localization; |
| 10 | |
| 11 | namespace SplitApp.WebApp.Hosting; |
| 12 | |
| 13 | public static class AppDataInit |
| 14 | { |
| 15 | public static void SeedExampleData(IServiceProvider services) |
| 16 | { |
| 17 | using var scope = services.CreateScope(); |
| 18 | var users = scope.ServiceProvider.GetRequiredService<UsersDbContext>(); |
| 19 | var trips = scope.ServiceProvider.GetRequiredService<TripsDbContext>(); |
| 20 | var expenses = scope.ServiceProvider.GetRequiredService<ExpensesDbContext>(); |
| 21 | |
| 22 | if (trips.Trips.Any()) return; |
| 23 | |
| 24 | var admin = users.Users.First(u => u.Email == "admin@taltech.ee").Id; |
| 25 | var testUser = users.Users.First(u => u.Email == "user@taltech.ee").Id; |
| 26 | var alice = users.Users.First(u => u.Email == "alice@taltech.ee").Id; |
| 27 | var bob = users.Users.First(u => u.Email == "bob@taltech.ee").Id; |
| 28 | var charlie = users.Users.First(u => u.Email == "charlie@taltech.ee").Id; |
| 29 | var diana = users.Users.First(u => u.Email == "diana@taltech.ee").Id; |
| 30 | |
| 31 | var eur = expenses.Currencies.First(c => c.Code == "EUR").Id; |
| 32 | var usd = expenses.Currencies.First(c => c.Code == "USD").Id; |
| 33 | var gbp = expenses.Currencies.First(c => c.Code == "GBP").Id; |
| 34 | |
| 35 | var now = DateTime.UtcNow; |
| 36 | |
| 37 | // ────────────────────────────────────────────────────────────── |
| 38 | // Trip 1: Barcelona Weekend — Active, 4 participants |
| 39 | // ────────────────────────────────────────────────────────────── |
| 40 | var trip1 = new Trip |
| 41 | { |
| 42 | Name = "Barcelona Weekend", |
| 43 | Description = "A long weekend exploring Barcelona with friends", |
| 44 | Destination = "Barcelona, Spain", |
| 45 | StartDate = new DateTime(2026, 4, 10, 0, 0, 0, DateTimeKind.Utc), |
| 46 | EndDate = new DateTime(2026, 4, 13, 0, 0, 0, DateTimeKind.Utc), |
| 47 | Status = ETripStatus.Active, |
| 48 | DefaultCurrencyId = eur, |
| 49 | CreatedById = admin, |
| 50 | }; |
| 51 | trips.Trips.Add(trip1); |
| 52 | |
| 53 | trips.TripParticipants.AddRange( |
| 54 | new TripParticipant { TripId = trip1.Id, UserId = admin, Role = EParticipantRole.Organizer, JoinedAt = now.AddDays(-10), IsActive = true }, |
| 55 | new TripParticipant { TripId = trip1.Id, UserId = alice, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-9), IsActive = true }, |
| 56 | new TripParticipant { TripId = trip1.Id, UserId = bob, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-8), IsActive = true }, |
| 57 | new TripParticipant { TripId = trip1.Id, UserId = charlie, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-7), IsActive = true }); |
| 58 | |
| 59 | var cat1Food = new BudgetCategory { TripId = trip1.Id, Name = Lang("Food & Drinks", "Toit ja joogid"), IconName = "cup-hot", PlannedAmount = 400m, DisplayOrder = 0 }; |
| 60 | var cat1Transport = new BudgetCategory { TripId = trip1.Id, Name = Lang("Transport", "Transport"), IconName = "bus-front", PlannedAmount = 150m, DisplayOrder = 1 }; |
| 61 | var cat1Activities = new BudgetCategory { TripId = trip1.Id, Name = Lang("Activities", "Tegevused"), IconName = "binoculars", PlannedAmount = 200m, DisplayOrder = 2 }; |
| 62 | var cat1Accommodation = new BudgetCategory { TripId = trip1.Id, Name = Lang("Accommodation", "Majutus"), IconName = "house", PlannedAmount = 500m, DisplayOrder = 3 }; |
| 63 | trips.BudgetCategories.AddRange(cat1Food, cat1Transport, cat1Activities, cat1Accommodation); |
| 64 | |
| 65 | var poll1 = new TripPoll { TripId = trip1.Id, CreatedByUserId = admin, Question = "Where should we eat on the last night?" }; |
| 66 | trips.TripPolls.Add(poll1); |
| 67 | var poll1A = new TripPollOption { PollId = poll1.Id, Text = "Can Culleretes (oldest restaurant)", DisplayOrder = 0 }; |
| 68 | var poll1B = new TripPollOption { PollId = poll1.Id, Text = "El Xampanyet (tapas)", DisplayOrder = 1 }; |
| 69 | var poll1C = new TripPollOption { PollId = poll1.Id, Text = "Cerveceria Catalana", DisplayOrder = 2 }; |
| 70 | trips.TripPollOptions.AddRange(poll1A, poll1B, poll1C); |
| 71 | trips.TripPollVotes.AddRange( |
| 72 | new TripPollVote { PollOptionId = poll1B.Id, UserId = admin }, |
| 73 | new TripPollVote { PollOptionId = poll1A.Id, UserId = alice }, |
| 74 | new TripPollVote { PollOptionId = poll1B.Id, UserId = bob }); |
| 75 | |
| 76 | trips.TripWishlistItems.AddRange( |
| 77 | new TripWishlistItem { TripId = trip1.Id, AddedByUserId = alice, Title = "Casa Batllo", Description = "Gaudi's famous building on Passeig de Gracia", Category = EWishlistCategory.Place, Priority = EWishlistPriority.MustDo, EstimatedCost = 35m, Location = "Passeig de Gracia 43", DisplayOrder = 0 }, |
| 78 | new TripWishlistItem { TripId = trip1.Id, AddedByUserId = bob, Title = "Beach volleyball", Description = "Play at Barceloneta beach in the morning", Category = EWishlistCategory.Activity, Priority = EWishlistPriority.NiceToHave, Location = "Barceloneta Beach", DisplayOrder = 1 }, |
| 79 | new TripWishlistItem { TripId = trip1.Id, AddedByUserId = charlie, Title = "Flamenco show", Description = "Evening flamenco performance", Category = EWishlistCategory.Activity, Priority = EWishlistPriority.MustDo, EstimatedCost = 45m, DisplayOrder = 2 }, |
| 80 | new TripWishlistItem { TripId = trip1.Id, AddedByUserId = admin, Title = "La Paradeta seafood", Description = "Fresh seafood market-style restaurant", Category = EWishlistCategory.Restaurant, Priority = EWishlistPriority.Optional, Location = "Carrer Comercial 7", DisplayOrder = 3 }); |
| 81 | |
| 82 | // ────────────────────────────────────────────────────────────── |
| 83 | // Trip 2: London Business Trip — Settled, 3 participants |
| 84 | // ────────────────────────────────────────────────────────────── |
| 85 | var trip2 = new Trip |
| 86 | { |
| 87 | Name = "London Business Trip", |
| 88 | Description = "Conference and team meetings in London", |
| 89 | Destination = "London, UK", |
| 90 | StartDate = new DateTime(2026, 3, 1, 0, 0, 0, DateTimeKind.Utc), |
| 91 | EndDate = new DateTime(2026, 3, 4, 0, 0, 0, DateTimeKind.Utc), |
| 92 | Status = ETripStatus.Settled, |
| 93 | DefaultCurrencyId = gbp, |
| 94 | CreatedById = testUser, |
| 95 | }; |
| 96 | trips.Trips.Add(trip2); |
| 97 | trips.TripParticipants.AddRange( |
| 98 | new TripParticipant { TripId = trip2.Id, UserId = testUser, Role = EParticipantRole.Organizer, JoinedAt = now.AddDays(-30), IsActive = true }, |
| 99 | new TripParticipant { TripId = trip2.Id, UserId = admin, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-29), IsActive = true }, |
| 100 | new TripParticipant { TripId = trip2.Id, UserId = diana, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-28), IsActive = true }); |
| 101 | |
| 102 | // ────────────────────────────────────────────────────────────── |
| 103 | // Trip 3: Summer Cabin — Active, 5 participants, partial settlement |
| 104 | // ────────────────────────────────────────────────────────────── |
| 105 | var trip3 = new Trip |
| 106 | { |
| 107 | Name = "Summer Cabin Getaway", |
| 108 | Description = "Relaxing weekend at a cabin by the lake", |
| 109 | Destination = "Otepää, Estonia", |
| 110 | StartDate = new DateTime(2026, 5, 15, 0, 0, 0, DateTimeKind.Utc), |
| 111 | EndDate = new DateTime(2026, 5, 18, 0, 0, 0, DateTimeKind.Utc), |
| 112 | Status = ETripStatus.Active, |
| 113 | DefaultCurrencyId = eur, |
| 114 | CreatedById = alice, |
| 115 | }; |
| 116 | trips.Trips.Add(trip3); |
| 117 | trips.TripParticipants.AddRange( |
| 118 | new TripParticipant { TripId = trip3.Id, UserId = alice, Role = EParticipantRole.Organizer, JoinedAt = now.AddDays(-3), IsActive = true }, |
| 119 | new TripParticipant { TripId = trip3.Id, UserId = bob, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-2), IsActive = true }, |
| 120 | new TripParticipant { TripId = trip3.Id, UserId = charlie, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-2), IsActive = true }, |
| 121 | new TripParticipant { TripId = trip3.Id, UserId = diana, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-1), IsActive = true }, |
| 122 | new TripParticipant { TripId = trip3.Id, UserId = admin, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-1), IsActive = true }); |
| 123 | |
| 124 | var poll3 = new TripPoll { TripId = trip3.Id, CreatedByUserId = alice, Question = "What activity for Saturday afternoon?", AllowMultipleVotes = true }; |
| 125 | trips.TripPolls.Add(poll3); |
| 126 | var poll3A = new TripPollOption { PollId = poll3.Id, Text = "Hiking to the viewpoint", DisplayOrder = 0 }; |
| 127 | var poll3B = new TripPollOption { PollId = poll3.Id, Text = "Fishing at the lake", DisplayOrder = 1 }; |
| 128 | var poll3C = new TripPollOption { PollId = poll3.Id, Text = "Board games at the cabin", DisplayOrder = 2 }; |
| 129 | var poll3D = new TripPollOption { PollId = poll3.Id, Text = "Cycling around the area", DisplayOrder = 3 }; |
| 130 | trips.TripPollOptions.AddRange(poll3A, poll3B, poll3C, poll3D); |
| 131 | trips.TripPollVotes.AddRange( |
| 132 | new TripPollVote { PollOptionId = poll3A.Id, UserId = alice }, |
| 133 | new TripPollVote { PollOptionId = poll3B.Id, UserId = alice }, |
| 134 | new TripPollVote { PollOptionId = poll3A.Id, UserId = bob }, |
| 135 | new TripPollVote { PollOptionId = poll3C.Id, UserId = charlie }, |
| 136 | new TripPollVote { PollOptionId = poll3B.Id, UserId = diana }, |
| 137 | new TripPollVote { PollOptionId = poll3D.Id, UserId = admin }, |
| 138 | new TripPollVote { PollOptionId = poll3A.Id, UserId = admin }); |
| 139 | |
| 140 | trips.TripWishlistItems.AddRange( |
| 141 | new TripWishlistItem { TripId = trip3.Id, AddedByUserId = bob, Title = "Smoke sauna experience", Description = "Traditional Estonian smoke sauna at the lakeside", Category = EWishlistCategory.Activity, Priority = EWishlistPriority.MustDo, EstimatedCost = 15m, DisplayOrder = 0 }, |
| 142 | new TripWishlistItem { TripId = trip3.Id, AddedByUserId = diana, Title = "Visit Otepää Adventure Park",Description = "Rope courses and zip lines in the forest", Category = EWishlistCategory.Activity, Priority = EWishlistPriority.NiceToHave,EstimatedCost = 25m, Location = "Otepää Adventure Park", DisplayOrder = 1 }, |
| 143 | new TripWishlistItem { TripId = trip3.Id, AddedByUserId = alice, Title = "Pühajärve beach", Description = "Swimming and sunbathing at the sacred lake", Category = EWishlistCategory.Place, Priority = EWishlistPriority.MustDo, Location = "Pühajärv", DisplayOrder = 2, IsCompleted = true, CompletedAt = now.AddHours(-5) }); |
| 144 | |
| 145 | trips.TripInvitations.Add(new TripInvitation |
| 146 | { |
| 147 | TripId = trip3.Id, InvitedByUserId = alice, |
| 148 | Token = Guid.NewGuid().ToString("N"), |
| 149 | Status = EInvitationStatus.Pending, |
| 150 | ExpiresAt = now.AddDays(7), |
| 151 | }); |
| 152 | |
| 153 | // ────────────────────────────────────────────────────────────── |
| 154 | // Trip 4: NYC Adventure — Archived, 3 participants |
| 155 | // ────────────────────────────────────────────────────────────── |
| 156 | var trip4 = new Trip |
| 157 | { |
| 158 | Name = "NYC Adventure", |
| 159 | Description = "Week in New York City exploring Manhattan and Brooklyn", |
| 160 | Destination = "New York, USA", |
| 161 | StartDate = new DateTime(2025, 12, 20, 0, 0, 0, DateTimeKind.Utc), |
| 162 | EndDate = new DateTime(2025, 12, 27, 0, 0, 0, DateTimeKind.Utc), |
| 163 | Status = ETripStatus.Archived, |
| 164 | DefaultCurrencyId = usd, |
| 165 | CreatedById = bob, |
| 166 | }; |
| 167 | trips.Trips.Add(trip4); |
| 168 | trips.TripParticipants.AddRange( |
| 169 | new TripParticipant { TripId = trip4.Id, UserId = bob, Role = EParticipantRole.Organizer, JoinedAt = now.AddDays(-90), IsActive = true }, |
| 170 | new TripParticipant { TripId = trip4.Id, UserId = alice, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-89), IsActive = true }, |
| 171 | new TripParticipant { TripId = trip4.Id, UserId = diana, Role = EParticipantRole.Participant, JoinedAt = now.AddDays(-88), IsActive = true }); |
| 172 | |
| 173 | var poll4 = new TripPoll |
| 174 | { |
| 175 | TripId = trip4.Id, CreatedByUserId = bob, |
| 176 | Question = "Best day of the trip?", |
| 177 | ClosedAt = new DateTime(2025, 12, 27, 12, 0, 0, DateTimeKind.Utc), |
| 178 | }; |
| 179 | trips.TripPolls.Add(poll4); |
| 180 | var poll4A = new TripPollOption { PollId = poll4.Id, Text = "Broadway night", DisplayOrder = 0 }; |
| 181 | var poll4B = new TripPollOption { PollId = poll4.Id, Text = "Central Park day", DisplayOrder = 1 }; |
| 182 | var poll4C = new TripPollOption { PollId = poll4.Id, Text = "Brooklyn Bridge walk", DisplayOrder = 2 }; |
| 183 | trips.TripPollOptions.AddRange(poll4A, poll4B, poll4C); |
| 184 | trips.TripPollVotes.AddRange( |
| 185 | new TripPollVote { PollOptionId = poll4A.Id, UserId = alice }, |
| 186 | new TripPollVote { PollOptionId = poll4A.Id, UserId = diana }, |
| 187 | new TripPollVote { PollOptionId = poll4B.Id, UserId = bob }); |
| 188 | |
| 189 | // Save Trips first so all Trip/Participant/BudgetCategory IDs are committed |
| 190 | // before Expenses references them by Guid (cross-schema, no FK). |
| 191 | trips.SaveChanges(); |
| 192 | |
| 193 | // ────────────────────────────────────────────────────────────── |
| 194 | // Trip 1 expenses: 11 items, equal split among 4 (one subset) |
| 195 | // ────────────────────────────────────────────────────────────── |
| 196 | var trip1Members = new[] { admin, alice, bob, charlie }; |
| 197 | var trip1Expenses = new (string desc, decimal amount, Guid paidBy, Guid? catId, DateTime date, ESplitMethod split)[] |
| 198 | { |
| 199 | ("Airbnb apartment (3 nights)", 480.00m, admin, cat1Accommodation.Id, now.AddDays(-5), ESplitMethod.EqualAll), |
| 200 | ("Airport taxi", 35.00m, alice, cat1Transport.Id, now.AddDays(-5), ESplitMethod.EqualAll), |
| 201 | ("Grocery shopping", 62.50m, bob, cat1Food.Id, now.AddDays(-4), ESplitMethod.EqualAll), |
| 202 | ("Dinner at La Boqueria", 128.00m, admin, cat1Food.Id, now.AddDays(-4), ESplitMethod.EqualAll), |
| 203 | ("Sagrada Familia tickets", 104.00m, charlie, cat1Activities.Id, now.AddDays(-3), ESplitMethod.EqualAll), |
| 204 | ("Metro passes (4x)", 44.00m, alice, cat1Transport.Id, now.AddDays(-3), ESplitMethod.EqualAll), |
| 205 | ("Tapas bar lunch", 76.00m, bob, cat1Food.Id, now.AddDays(-3), ESplitMethod.EqualAll), |
| 206 | ("Park Guell entry", 40.00m, admin, cat1Activities.Id, now.AddDays(-2), ESplitMethod.EqualAll), |
| 207 | ("Sangria and snacks", 48.50m, charlie, cat1Food.Id, now.AddDays(-2), ESplitMethod.EqualAll), |
| 208 | ("Souvenir shopping", 55.00m, alice, cat1Food.Id, now.AddDays(-1), ESplitMethod.EqualSubset), |
| 209 | ("Return taxi to airport", 38.00m, bob, cat1Transport.Id, now.AddDays(-1), ESplitMethod.EqualAll), |
| 210 | }; |
| 211 | |
| 212 | foreach (var (desc, amount, paidBy, catId, date, split) in trip1Expenses) |
| 213 | { |
| 214 | var ex = new Expense |
| 215 | { |
| 216 | TripId = trip1.Id, PaidByUserId = paidBy, Amount = amount, |
| 217 | Description = desc, ExpenseDate = date, BudgetCategoryId = catId, |
| 218 | CurrencyId = eur, SplitMethod = split, |
| 219 | }; |
| 220 | expenses.Expenses.Add(ex); |
| 221 | AddEqualSplits(expenses, ex, split == ESplitMethod.EqualSubset |
| 222 | ? new[] { alice, bob, charlie } |
| 223 | : trip1Members); |
| 224 | } |
| 225 | |
| 226 | // SplitPresets (Expenses module) |
| 227 | var preset1All = new SplitPreset { TripId = trip1.Id, Name = "Everyone equal", SplitMethod = ESplitMethod.EqualAll, CreatedById = admin }; |
| 228 | var preset1Hotel = new SplitPreset { TripId = trip1.Id, Name = "Hotel group", SplitMethod = ESplitMethod.EqualSubset, CreatedById = admin }; |
| 229 | expenses.SplitPresets.AddRange(preset1All, preset1Hotel); |
| 230 | expenses.SplitPresetMembers.AddRange( |
| 231 | new SplitPresetMember { SplitPresetId = preset1Hotel.Id, UserId = admin }, |
| 232 | new SplitPresetMember { SplitPresetId = preset1Hotel.Id, UserId = alice }, |
| 233 | new SplitPresetMember { SplitPresetId = preset1Hotel.Id, UserId = bob }); |
| 234 | |
| 235 | // ────────────────────────────────────────────────────────────── |
| 236 | // Trip 2 expenses + completed settlement |
| 237 | // ────────────────────────────────────────────────────────────── |
| 238 | var trip2Members = new[] { testUser, admin, diana }; |
| 239 | var trip2Expenses = new (string desc, decimal amount, Guid paidBy, DateTime date)[] |
| 240 | { |
| 241 | ("Hotel (2 nights)", 340.00m, testUser, now.AddDays(-28)), |
| 242 | ("Heathrow Express", 75.00m, admin, now.AddDays(-28)), |
| 243 | ("Conference dinner", 185.00m, testUser, now.AddDays(-27)), |
| 244 | ("Uber rides", 48.00m, diana, now.AddDays(-27)), |
| 245 | ("Team lunch", 92.00m, admin, now.AddDays(-26)), |
| 246 | ("Coffee & snacks", 24.50m, diana, now.AddDays(-26)), |
| 247 | }; |
| 248 | foreach (var (desc, amount, paidBy, date) in trip2Expenses) |
| 249 | { |
| 250 | var ex = new Expense |
| 251 | { |
| 252 | TripId = trip2.Id, PaidByUserId = paidBy, Amount = amount, |
| 253 | Description = desc, ExpenseDate = date, CurrencyId = gbp, |
| 254 | SplitMethod = ESplitMethod.EqualAll, |
| 255 | }; |
| 256 | expenses.Expenses.Add(ex); |
| 257 | AddEqualSplits(expenses, ex, trip2Members); |
| 258 | } |
| 259 | |
| 260 | var plan2 = new SettlementPlan |
| 261 | { |
| 262 | TripId = trip2.Id, CreatedByUserId = testUser, |
| 263 | TotalAmount = 158.50m, Status = ESettlementStatus.Completed, |
| 264 | CompletedAt = now.AddDays(-20), |
| 265 | }; |
| 266 | expenses.SettlementPlans.Add(plan2); |
| 267 | expenses.SettlementPayments.AddRange( |
| 268 | new SettlementPayment { SettlementPlanId = plan2.Id, FromUserId = diana, ToUserId = testUser, Amount = 130.50m, Status = EPaymentStatus.Confirmed, MarkedPaidAt = now.AddDays(-22), ConfirmedAt = now.AddDays(-20) }, |
| 269 | new SettlementPayment { SettlementPlanId = plan2.Id, FromUserId = diana, ToUserId = admin, Amount = 28.00m, Status = EPaymentStatus.Confirmed, MarkedPaidAt = now.AddDays(-21), ConfirmedAt = now.AddDays(-20) }); |
| 270 | |
| 271 | // ────────────────────────────────────────────────────────────── |
| 272 | // Trip 3 expenses + in-progress settlement |
| 273 | // ────────────────────────────────────────────────────────────── |
| 274 | var trip3Members = new[] { alice, bob, charlie, diana, admin }; |
| 275 | var trip3Expenses = new (string desc, decimal amount, Guid paidBy, DateTime date)[] |
| 276 | { |
| 277 | ("Cabin rental (3 nights)", 600.00m, alice, now.AddDays(-2)), |
| 278 | ("BBQ supplies and meat", 95.00m, bob, now.AddDays(-1)), |
| 279 | ("Firewood and charcoal", 25.00m, charlie, now.AddDays(-1)), |
| 280 | ("Drinks and beverages", 78.00m, diana, now), |
| 281 | ("Fishing gear rental", 40.00m, admin, now), |
| 282 | ("Breakfast groceries", 42.00m, alice, now), |
| 283 | ("Canoe rental (half day)", 60.00m, bob, now), |
| 284 | }; |
| 285 | foreach (var (desc, amount, paidBy, date) in trip3Expenses) |
| 286 | { |
| 287 | var ex = new Expense |
| 288 | { |
| 289 | TripId = trip3.Id, PaidByUserId = paidBy, Amount = amount, |
| 290 | Description = desc, ExpenseDate = date, CurrencyId = eur, |
| 291 | SplitMethod = ESplitMethod.EqualAll, |
| 292 | }; |
| 293 | expenses.Expenses.Add(ex); |
| 294 | AddEqualSplits(expenses, ex, trip3Members); |
| 295 | } |
| 296 | |
| 297 | var plan3 = new SettlementPlan |
| 298 | { |
| 299 | TripId = trip3.Id, CreatedByUserId = alice, |
| 300 | TotalAmount = 350m, Status = ESettlementStatus.InProgress, |
| 301 | }; |
| 302 | expenses.SettlementPlans.Add(plan3); |
| 303 | expenses.SettlementPayments.AddRange( |
| 304 | new SettlementPayment { SettlementPlanId = plan3.Id, FromUserId = charlie, ToUserId = alice, Amount = 145.00m, Status = EPaymentStatus.MarkedPaid, MarkedPaidAt = now.AddHours(-2) }, |
| 305 | new SettlementPayment { SettlementPlanId = plan3.Id, FromUserId = diana, ToUserId = alice, Amount = 110.00m, Status = EPaymentStatus.Pending }, |
| 306 | new SettlementPayment { SettlementPlanId = plan3.Id, FromUserId = admin, ToUserId = bob, Amount = 95.00m, Status = EPaymentStatus.Pending }); |
| 307 | |
| 308 | // ────────────────────────────────────────────────────────────── |
| 309 | // Trip 4 expenses (archived) |
| 310 | // ────────────────────────────────────────────────────────────── |
| 311 | var trip4Members = new[] { bob, alice, diana }; |
| 312 | var trip4Expenses = new (string desc, decimal amount, Guid paidBy, DateTime date)[] |
| 313 | { |
| 314 | ("Hotel in Midtown (6 nights)", 1800.00m, bob, new DateTime(2025, 12, 20, 12, 0, 0, DateTimeKind.Utc)), |
| 315 | ("Broadway show tickets", 450.00m, alice, new DateTime(2025, 12, 21, 20, 0, 0, DateTimeKind.Utc)), |
| 316 | ("Statue of Liberty ferry", 63.00m, diana, new DateTime(2025, 12, 22, 10, 0, 0, DateTimeKind.Utc)), |
| 317 | ("Central Park bike rental", 75.00m, bob, new DateTime(2025, 12, 23, 14, 0, 0, DateTimeKind.Utc)), |
| 318 | ("Dinner in Little Italy", 195.00m, alice, new DateTime(2025, 12, 23, 20, 0, 0, DateTimeKind.Utc)), |
| 319 | ("Brooklyn Bridge walk snacks", 28.00m, diana, new DateTime(2025, 12, 24, 11, 0, 0, DateTimeKind.Utc)), |
| 320 | ("MoMA tickets", 75.00m, bob, new DateTime(2025, 12, 25, 10, 0, 0, DateTimeKind.Utc)), |
| 321 | ("Times Square shopping", 220.00m, alice, new DateTime(2025, 12, 26, 15, 0, 0, DateTimeKind.Utc)), |
| 322 | ("JFK taxi", 65.00m, diana, new DateTime(2025, 12, 27, 8, 0, 0, DateTimeKind.Utc)), |
| 323 | }; |
| 324 | foreach (var (desc, amount, paidBy, date) in trip4Expenses) |
| 325 | { |
| 326 | var ex = new Expense |
| 327 | { |
| 328 | TripId = trip4.Id, PaidByUserId = paidBy, Amount = amount, |
| 329 | Description = desc, ExpenseDate = date, CurrencyId = usd, |
| 330 | SplitMethod = ESplitMethod.EqualAll, |
| 331 | }; |
| 332 | expenses.Expenses.Add(ex); |
| 333 | AddEqualSplits(expenses, ex, trip4Members); |
| 334 | } |
| 335 | |
| 336 | expenses.SaveChanges(); |
| 337 | } |
| 338 | |
| 339 | private static LangStr Lang(string en, string et) |
| 340 | { |
| 341 | var s = new LangStr(en, "en"); |
| 342 | s["et"] = et; |
| 343 | return s; |
| 344 | } |
| 345 | |
| 346 | private static void AddEqualSplits(ExpensesDbContext db, Expense expense, Guid[] memberIds) |
| 347 | { |
| 348 | var count = memberIds.Length; |
| 349 | var baseAmt = Math.Floor(expense.Amount / count * 100m) / 100m; |
| 350 | var remainderCents = (int)Math.Round((expense.Amount - baseAmt * count) * 100m); |
| 351 | |
| 352 | for (var i = 0; i < count; i++) |
| 353 | { |
| 354 | var splitAmt = baseAmt + (i < remainderCents ? 0.01m : 0m); |
| 355 | db.ExpenseSplits.Add(new ExpenseSplit |
| 356 | { |
| 357 | ExpenseId = expense.Id, |
| 358 | UserId = memberIds[i], |
| 359 | Amount = splitAmt, |
| 360 | }); |
| 361 | } |
| 362 | } |
| 363 | } |
| 364 | |