profileShare

rasmusjy / splitapp-backend-modular-monolith

Read-only snapshot

No repository description.

main default branch 418 files Expires Sep 13, 2026, 9:06 AM
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