namespace Yavsc.Helpers { using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Yavsc.Abstract.Workflow; using Yavsc.Billing; using Yavsc.Models; using Yavsc.Models.Billing; using Yavsc.Models.Haircut; using Yavsc.Models.Workflow; using Yavsc.Services; using Yavsc.ViewModels.FrontOffice; public static class WorkflowHelpers { // Synchronization lock for billing service configuration private static readonly object _billingLock = new object(); public static async Task> ListPerformersAsync(this ApplicationDbContext context, IBillingService billing, string actCode) { var actors = context.Performers .Include(p => p.Activity) .Include(p => p.Performer) .Where(p => p.Active && p.Activity.Any(u => u.DoesCode == actCode)).OrderBy(x => x.Rate) .ToArray(); List result = new(); foreach (var a in actors) { var settings = await billing.GetPerformersSettingsAsync(actCode, a.PerformerId); result.Add(new PerformerProfileViewModel(a, actCode, settings)); } return result; } public static void RegisterBilling(string code, Func getter) where T : IBillable { lock (_billingLock) { string typeName = typeof(T).Name; if (BillingService.GlobalBillingMap.ContainsKey(typeName)) { throw new InvalidOperationException($"Billing setup: type '{typeName}' already registered with different code"); } if (BillingService.Billing.ContainsKey(code)) { throw new InvalidOperationException($"Billing setup: code '{code}' already registered with different type"); } BillingService.Billing.Add(code, getter); BillingService.GlobalBillingMap.Add(typeName, code); } } public static void ConfigureBillingService() { lock (_billingLock) { BillingService.Billing.Clear(); BillingService.GlobalBillingMap.Clear(); BillingService.UserSettings.Clear(); Config.ProfileTypes.Clear(); foreach (var a in System.AppDomain.CurrentDomain.GetAssemblies()) { Type[] types; try { types = a.GetTypes(); } catch (System.Reflection.ReflectionTypeLoadException rtle) { // Some referenced types failed to load; keep the // ones that did and skip the rest so a flaky // dependency in one assembly does not break // billing initialization for every other assembly. types = rtle.Types.Where(t => t != null).ToArray(); } catch { // Assembly itself cannot be loaded (FileNotFoundException // on a referenced assembly, etc.). Skip it entirely. continue; } foreach (var c in types) { if (c.IsClass && !c.IsAbstract && c.GetInterface(nameof(IUserSettings)) != null) { Config.ProfileTypes.Add(c); } } } foreach (var propertyInfo in typeof(ApplicationDbContext).GetProperties()) { if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)) { var entityType = propertyInfo.PropertyType.GetGenericArguments()[0]; if (typeof(IUserSettings).IsAssignableFrom(entityType)) { BillingService.UserSettings.Add(propertyInfo); } } } RegisterBilling(BillingCodes.Brush, new Func ((db, id) => { var query = db.HairCutQueries.Include(q => q.Prestation).Include(q => q.Regularization).Single(q => q.Id == id); query.SelectedProfile = db.BrusherProfile.Single(b => b.UserId == query.PerformerId); return query; })); RegisterBilling(BillingCodes.MBrush, new Func ((db, id) => db.HairMultiCutQueries.Include(q => q.Regularization).Single(q => q.Id == id))); RegisterBilling(BillingCodes.Rdv, new Func ((db, id) => db.RdvQueries.Include(q => q.Regularization).Single(q => q.Id == id))); } } } }