using System; using System.Threading.Tasks; using System.Collections.Generic; using AyaNova.Models; using AyaNova.Biz; using Microsoft.Extensions.Logging; using Bogus; using AyaNova.Api.ControllerHelpers; using System.Diagnostics; using Microsoft.EntityFrameworkCore; using System.Linq; namespace AyaNova.Util { public class Seeder { public Faker Fake; //### FAKER BIG LIST OF ALL SOURCE DATA HERE: //https://github.com/bchavez/Bogus/blob/master/Source/Bogus/data/en.locale.json //https://github.com/bchavez/Bogus#bogus-api-support public Seeder() { Fake = new Faker(); } public static class Level { public enum SeedLevel { NotValid, Small, Medium, Large, Huge }; public static SeedLevel StringToSeedLevel(string size) { switch (size.ToLowerInvariant()) { case "small": return SeedLevel.Small; case "medium": return SeedLevel.Medium; case "large": return SeedLevel.Large; case "huge": return SeedLevel.Huge; default: return SeedLevel.NotValid; } } } ////////////////////////////////////////////////////// //Seed database for trial and testing purposes // public async Task SeedDatabaseAsync(Level.SeedLevel slevel, Decimal timeZoneOffset) { await SeedDatabaseAsync(slevel, Guid.Empty, timeZoneOffset); } public async Task SeedDatabaseAsync(Level.SeedLevel slevel, Guid JobId, Decimal timeZoneOffset) { bool LogJob = JobId != Guid.Empty; // TotalSeededUserCount = 0; ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("Seeder"); ApiServerState apiServerState = (ApiServerState)ServiceProviderProvider.Provider.GetService(typeof(ApiServerState)); //get the current server state so can set back to it later ApiServerState.ServerState wasServerState = apiServerState.GetState(); string wasReason = apiServerState.Reason; try { var StatusMsg = $"Seeding data, level {slevel.ToString()}, time zone offset {timeZoneOffset.ToString()}"; await LogStatusAsync(JobId, LogJob, log, StatusMsg); //Only allow this in a trial database if (!AyaNova.Core.License.ActiveKey.TrialLicense) { var msg = $"This database has a registered license key so it can't be seeded: {AyaNova.Core.License.LicenseInfoLogFormat}"; await LogStatusAsync(JobId, LogJob, log, msg); throw new System.NotSupportedException(msg); } //validate timezone offset if (timeZoneOffset > 14 || timeZoneOffset < (-12)) { var msg = $"Time zone offset \"{timeZoneOffset.ToString()}\" is not valid"; await LogStatusAsync(JobId, LogJob, log, msg); throw new System.NotSupportedException(msg); } apiServerState.SetOpsOnly("Seeding database"); ServerBootConfig.SEEDING = true; //Erase all the data except for the license, schema and the SuperUser await DbUtil.EmptyBizDataFromDatabaseForSeedingOrImportingAsync(log); //Event log erase and seeding using (var ct = ServiceProviderProvider.DBContext) { await EventLogProcessor.LogEventToDatabaseAsync(new Event(1, 0, AyaType.Global, AyaEvent.EraseAllData, "(seeding preparation)"), ct); await EventLogProcessor.LogEventToDatabaseAsync(new Event(1, 0, AyaType.Global, AyaEvent.SeedDatabase, StatusMsg), ct); } apiServerState.SetOpsOnly("Seeding database with sample data"); //WIDGET sample form customization { var fc = new FormCustom() { FormKey = AyaType.Widget.ToString(), Template = @"[ { ""fld"": ""Notes"", ""required"": true }, { ""fld"": ""WidgetCustom1"", ""required"": false, ""type"": 1 }, { ""fld"": ""WidgetCustom2"", ""required"": true, ""type"": 4 }, { ""fld"": ""WidgetCustom3"", ""required"": false, ""type"": 5 }, { ""fld"": ""WidgetCustom4"", ""required"": false, ""type"": 6 }, { ""fld"": ""WidgetCustom5"", ""required"": false, ""type"": 8 }, { ""fld"": ""WidgetCustom6"", ""required"": false, ""type"": 2 }, { ""fld"": ""WidgetCustom7"", ""required"": false, ""type"": 3 } ]" }; //Create and save to db using (var ct = ServiceProviderProvider.DBContext) await FormCustomBiz.GetBiz(ct).CreateAsync(fc); } //TODO: Add this back in or...fuck it? // //Create a couple of DataListView's for development and testing // { // var dlv = new DataListSavedFilter() // { // Name = "Name starts with generic", // UserId = 1, // ListKey = "TestWidgetDataList", // Public = true, // ListView = @"[{""fld"": ""widgetname"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Generic""}]}}]" // }; // //Create and save to db // using (var ct = ServiceProviderProvider.DBContext) // await DataListSavedFilterBiz.GetBiz(ct).CreateAsync(dlv); // dlv = new DataListSavedFilter() // { // Name = "Awesome (lots of fields)", // UserId = 1, // ListKey = "TestWidgetDataList", // Public = true, // ListView = @"[{""fld"": ""widgetname"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Awesome""}]}},{""fld"":""widgetserial""},{""fld"":""widgetdollaramount""},{""fld"":""widgetusertype""},{""fld"":""widgetstartdate""},{""fld"":""widgetactive""},{""fld"":""username""},{""fld"":""widgettags""},{""fld"":""widgetcustom1""},{""fld"":""widgetcustom2""}]" // }; // //Create and save to db // using (var ct = ServiceProviderProvider.DBContext) // await DataListSavedFilterBiz.GetBiz(ct).CreateAsync(dlv); // } //Seed special test data for integration testing //log.LogInformation("Seeding known users"); await SeedKnownObjectsAsync(log); /* ███████╗███████╗███████╗██████╗ █████╗ ██╗ ██╗ ████████╗██╗ ██╗███████╗ ████████╗██╗ ██╗██╗███╗ ██╗ ██████╗ ███████╗ ██╔════╝██╔════╝██╔════╝██╔══██╗ ██╔══██╗██║ ██║ ╚══██╔══╝██║ ██║██╔════╝ ╚══██╔══╝██║ ██║██║████╗ ██║██╔════╝ ██╔════╝ ███████╗█████╗ █████╗ ██║ ██║ ███████║██║ ██║ ██║ ███████║█████╗ ██║ ███████║██║██╔██╗ ██║██║ ███╗███████╗ ╚════██║██╔══╝ ██╔══╝ ██║ ██║ ██╔══██║██║ ██║ ██║ ██╔══██║██╔══╝ ██║ ██╔══██║██║██║╚██╗██║██║ ██║╚════██║ ███████║███████╗███████╗██████╔╝ ██║ ██║███████╗███████╗ ██║ ██║ ██║███████╗ ██║ ██║ ██║██║██║ ╚████║╚██████╔╝███████║ ╚══════╝╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ */ //log.LogInformation("Seeding all other data"); switch (slevel) { case Level.SeedLevel.Small: { #region GenSmall //This is for a busy but one man shop with a single office person handling stuff back at the shop //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding SMALL sample data...."); var watch = new Stopwatch(); watch.Start(); //Generate owner and lead tech await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminFull | AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryFull | AuthorizationRoles.OpsAdminFull, UserType.Service); //Generate one office person / secretary await SeedUserAsync(log, 1, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryFull | AuthorizationRoles.AccountingFull, UserType.NotService); await SeedWidgetAsync(log, 25); await SeedCustomerAsync(log, 25); await SeedHeadOfficeAsync(log, 10); await SeedVendorAsync(log, 10); await SeedProjectAsync(log, 10); await SeedServiceRateAsync(log, 5); await SeedTravelRateAsync(log, 3); await SeedUnitModelAsync(log, 10); await SeedUnitAsync(log, 20);//5 times the customers or 5 units per customer await SeedLoanLoanUnitAsync(log, 5); await SeedCustomerServiceRequestAsync(log, 5); await SeedPartWarehouseAsync(log, 5); await SeedPartAsync(log, 20, 5); await SeedPartAssemblyAsync(log, 5); await SeedPurchaseOrderAsync(log, 20); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"Small level sample data seeded in {watch.ElapsedMilliseconds} ms"); #endregion gensmall } break; case Level.SeedLevel.Medium: { #region GenMedium //This is for a typical AyaNova medium busy shop //has one location, many techs and full staff for each department //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding MEDIUM sample data...."); var watch = new Stopwatch(); watch.Start(); //One IT administrator, can change ops but nothing else await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminFull, UserType.NotService); //One business administrator, can view ops issues await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminFull | AuthorizationRoles.OpsAdminLimited, UserType.NotService); //One owner who doesn't control anything but views stuff await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminLimited | AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited | AuthorizationRoles.SalesLimited, UserType.NotService); //20 techs await SeedUserAsync(log, 20, AuthorizationRoles.TechFull | AuthorizationRoles.DispatchLimited, UserType.Service); //2 subcontractors await SeedUserAsync(log, 2, AuthorizationRoles.SubContractorFull, UserType.ServiceContractor); //3 generic office people people await SeedUserAsync(log, 3, AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited, UserType.NotService); //2 Full sales people await SeedUserAsync(log, 2, AuthorizationRoles.SalesFull, UserType.NotService); //1 dispatch manager await SeedUserAsync(log, 1, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryLimited, UserType.NotService); //1 Inventory manager await SeedUserAsync(log, 1, AuthorizationRoles.InventoryFull | AuthorizationRoles.DispatchLimited, UserType.NotService); //1 accountant / bookkeeper await SeedUserAsync(log, 1, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NotService); await SeedWidgetAsync(log, 100); await SeedCustomerAsync(log, 500); await SeedHeadOfficeAsync(log, 20); await SeedVendorAsync(log, 50); await SeedProjectAsync(log, 50); await SeedServiceRateAsync(log, 10); await SeedTravelRateAsync(log, 5); await SeedUnitModelAsync(log, 25); await SeedUnitAsync(log, 2500);//5 times the customers or 5 units per customer await SeedLoanLoanUnitAsync(log, 10); await SeedCustomerServiceRequestAsync(log, 10); await SeedPartWarehouseAsync(log, 10); await SeedPartAsync(log, 100, 10); await SeedPartAssemblyAsync(log, 5); await SeedPurchaseOrderAsync(log, 30); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"MEDIUM level sample data seeded in {watch.ElapsedMilliseconds} ms"); #endregion genmedium } break; case Level.SeedLevel.Large: { #region GenLarge //this is a large corporation with multiple branches in multiple locations all in the same country //Each location has a full staff and corporate head office has an overarching staff member in charge of each location //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding LARGE sample data...."); var watch = new Stopwatch(); watch.Start(); //USERS //IT administrator, can change ops but nothing else await SeedUserAsync(log, 2, AuthorizationRoles.OpsAdminFull, UserType.NotService); //business administrator, can view ops issues await SeedUserAsync(log, 2, AuthorizationRoles.BizAdminFull | AuthorizationRoles.OpsAdminLimited, UserType.NotService); //owner / upper management who doesn't control anything but views stuff await SeedUserAsync(log, 5, AuthorizationRoles.BizAdminLimited | AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited, UserType.NotService); //100 techs await SeedUserAsync(log, 100, AuthorizationRoles.TechFull | AuthorizationRoles.DispatchLimited, UserType.Service); //limited techs await SeedUserAsync(log, 50, AuthorizationRoles.TechLimited | AuthorizationRoles.DispatchLimited, UserType.Service); //20 subcontractors await SeedUserAsync(log, 20, AuthorizationRoles.SubContractorFull, UserType.ServiceContractor); //10 limited subcontractors await SeedUserAsync(log, 10, AuthorizationRoles.SubContractorLimited, UserType.ServiceContractor); //30 generic office people people await SeedUserAsync(log, 30, AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited, UserType.NotService); //10 Full sales people await SeedUserAsync(log, 10, AuthorizationRoles.SalesFull, UserType.NotService); //5 Limited sales people await SeedUserAsync(log, 5, AuthorizationRoles.SalesLimited, UserType.NotService); //5 dispatch manager await SeedUserAsync(log, 5, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryLimited, UserType.NotService); //5 Inventory manager await SeedUserAsync(log, 5, AuthorizationRoles.InventoryFull | AuthorizationRoles.DispatchLimited, UserType.NotService); //10 Inventory manager assistants await SeedUserAsync(log, 5, AuthorizationRoles.InventoryLimited, UserType.NotService); //5 accountant / bookkeeper await SeedUserAsync(log, 5, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NotService); await SeedWidgetAsync(log, 100); await SeedCustomerAsync(log, 5000); await SeedHeadOfficeAsync(log, 30); await SeedVendorAsync(log, 75); await SeedProjectAsync(log, 75); await SeedServiceRateAsync(log, 20); await SeedTravelRateAsync(log, 10); await SeedUnitModelAsync(log, 30); await SeedUnitAsync(log, 25000);//5 times the customers or 5 units per customer await SeedLoanLoanUnitAsync(log, 15); await SeedCustomerServiceRequestAsync(log, 15); await SeedPartWarehouseAsync(log, 15); await SeedPartAsync(log, 200, 15); await SeedPartAssemblyAsync(log, 5); await SeedPurchaseOrderAsync(log, 50); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"LARGE level sample data seeded in {watch.ElapsedMilliseconds} ms"); #endregion genlarge } break; case Level.SeedLevel.Huge: { #region GenHuge //this is the HUGE dataset for load and other testing //It is acceptable for this seeding to take many hours as it would normally be used rarely //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding HUGE sample data...."); var watch = new Stopwatch(); watch.Start(); //USERS //IT administrator, can change ops but nothing else await SeedUserAsync(log, 10, AuthorizationRoles.OpsAdminFull, UserType.NotService); //business administrator, can view ops issues await SeedUserAsync(log, 10, AuthorizationRoles.BizAdminFull | AuthorizationRoles.OpsAdminLimited, UserType.NotService); //owner / upper management who doesn't control anything but views stuff await SeedUserAsync(log, 20, AuthorizationRoles.BizAdminLimited | AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited, UserType.NotService); //regular techs await SeedUserAsync(log, 500, AuthorizationRoles.TechFull | AuthorizationRoles.DispatchLimited, UserType.Service); //limited techs await SeedUserAsync(log, 200, AuthorizationRoles.TechLimited | AuthorizationRoles.DispatchLimited, UserType.Service); //subcontractors await SeedUserAsync(log, 80, AuthorizationRoles.SubContractorFull, UserType.ServiceContractor); //limited subcontractors await SeedUserAsync(log, 40, AuthorizationRoles.SubContractorLimited, UserType.ServiceContractor); //generic office people people await SeedUserAsync(log, 200, AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited, UserType.NotService); //20 Full sales people await SeedUserAsync(log, 20, AuthorizationRoles.SalesFull, UserType.NotService); //10 Limited sales people await SeedUserAsync(log, 10, AuthorizationRoles.SalesLimited, UserType.NotService); //dispatch manager await SeedUserAsync(log, 20, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryLimited, UserType.NotService); //Inventory manager await SeedUserAsync(log, 40, AuthorizationRoles.InventoryFull | AuthorizationRoles.DispatchLimited, UserType.NotService); //Inventory manager assistants await SeedUserAsync(log, 20, AuthorizationRoles.InventoryLimited, UserType.NotService); //accountant / bookkeeper await SeedUserAsync(log, 20, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NotService); await SeedWidgetAsync(log, 100); await SeedCustomerAsync(log, 20000); await SeedHeadOfficeAsync(log, 40); await SeedVendorAsync(log, 100); await SeedProjectAsync(log, 500); await SeedServiceRateAsync(log, 30); await SeedTravelRateAsync(log, 15); await SeedUnitModelAsync(log, 40); await SeedUnitAsync(log, 100000);//5 times the customers or 5 units per customer await SeedLoanLoanUnitAsync(log, 20); await SeedCustomerServiceRequestAsync(log, 20); await SeedPartWarehouseAsync(log, 20); await SeedPartAsync(log, 500, 20); await SeedPartAssemblyAsync(log, 5); await SeedPurchaseOrderAsync(log, 200); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"HUGE level sample data seeded in {watch.ElapsedMilliseconds} ms"); #endregion genhuge } break; } //Seed logo files var LogoFilesPath = System.IO.Path.Combine(ServerBootConfig.AYANOVA_CONTENT_ROOT_PATH, "resource", "rpt", "stock-report-templates"); if (System.IO.Directory.Exists(LogoFilesPath)) { using (var ct = ServiceProviderProvider.DBContext) { var logo = await ct.Logo.FirstOrDefaultAsync(); if (logo == null) { logo = new Logo(); ct.Logo.Add(logo); await ct.SaveChangesAsync(); } logo.Small = System.IO.File.ReadAllBytes(System.IO.Path.Combine(LogoFilesPath, "150x50.png")); logo.SmallType = "image/png"; logo.Medium = System.IO.File.ReadAllBytes(System.IO.Path.Combine(LogoFilesPath, "300x100.png")); logo.MediumType = "image/png"; logo.Large = System.IO.File.ReadAllBytes(System.IO.Path.Combine(LogoFilesPath, "600x200.png")); logo.LargeType = "image/png"; await ct.SaveChangesAsync(); } } await LogStatusAsync(JobId, LogJob, log, "Seeding completed successfully"); } catch (Exception ex) { log.LogError(ex, "Seeder:SeedDatabase error during ops"); if (LogJob) await JobsBiz.LogJobAsync(JobId, $"Seeder:SeedDatabase error during ops\r\n{ex.Message}"); throw; } finally { //No matter what seeding is done ServerBootConfig.SEEDING = false; log.LogInformation($"Seeder: setting server state back to {wasServerState.ToString()}"); apiServerState.SetState(wasServerState, wasReason); } } //Log the status and also job if it's run via job private async Task LogStatusAsync(Guid JobId, bool LogJob, ILogger log, string msg) { log.LogInformation(msg); if (LogJob) await JobsBiz.LogJobAsync(JobId, msg); } public long RUNNING_COUNT = 0; public string Uniquify(string s) { return s + " " + (++RUNNING_COUNT).ToString(); } private string[] TagSet = new[] { "red", "orange", "yellow", "green", "blue", "indigo", "violet", "brown", "black", "white", "silver", "gold", "fuchsia", "jade", "mauve", "purple", "quince", "xanthic", "zebra", "zone0", "zone1", "zone2", "zone3", "zone4", "zone5", "zone6", "zone7", "zone8", "zone9" }; private List RandomTags() { var t = Fake.PickRandom(TagSet, Fake.Random.Int(1, 5));//pick up to 5 tags to apply return new List(t); } ////////////////////////////////////////////////////// //Seed test data for integration tests // public async Task SeedKnownObjectsAsync(ILogger log) { try { var KnownUserTags = new List(); KnownUserTags.Add("known-user"); KnownUserTags.Add("test-role-user"); //TEST USERS //one of each role type await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminLimited, UserType.NotService, "BizAdminLimited", "BizAdminLimited", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminFull, UserType.NotService, "BizAdminFull", "BizAdminFull", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.DispatchLimited, UserType.NotService, "DispatchLimited", "DispatchLimited", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.DispatchFull, UserType.NotService, "DispatchFull", "DispatchFull", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.InventoryLimited, UserType.NotService, "InventoryLimited", "InventoryLimited", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.InventoryFull, UserType.NotService, "InventoryFull", "InventoryFull", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.AccountingFull, UserType.NotService, "Accounting", "Accounting", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.TechLimited, UserType.Service, "TechLimited", "TechLimited", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.TechFull, UserType.Service, "TechFull", "TechFull", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.SalesLimited, UserType.NotService, "SalesLimited", "SalesLimited", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.SalesFull, UserType.NotService, "SalesFull", "SalesFull", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminLimited, UserType.NotService, "OpsAdminLimited", "OpsAdminLimited", KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminFull, UserType.NotService, "OpsAdminFull", "OpsAdminFull", KnownUserTags); //Alternate translation users for each stock translation await SeedUserAsync(log, 1, AuthorizationRoles.All, UserType.NotService, true, "de", "de", await TranslationBiz.TranslationNameToIdStaticAsync("de"), KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.All, UserType.NotService, true, "es", "es", await TranslationBiz.TranslationNameToIdStaticAsync("es"), KnownUserTags); await SeedUserAsync(log, 1, AuthorizationRoles.All, UserType.NotService, true, "fr", "fr", await TranslationBiz.TranslationNameToIdStaticAsync("fr"), KnownUserTags); #if(DEBUG) //PRIVACY TEST USER - this is used for a test to see if user info leaks into the logs await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminLimited, UserType.NotService, "TEST_PRIVACY_USER_ACCOUNT", "TEST_PRIVACY_USER_ACCOUNT", KnownUserTags); //TEST NOT ACTIVE - this is used for a test to see if inactive user can login await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminLimited, UserType.NotService, false, "TEST_INACTIVE", "TEST_INACTIVE", 0, KnownUserTags); #endif ///////////////////////////////////////////////////// //CONTRACTS { await SeedTravelRateAsync(log, 1, "Bronze travel rate", true);//1 await SeedTravelRateAsync(log, 1, "Silver travel rate", true);//2 await SeedTravelRateAsync(log, 1, "Gold travel rate", true);//3 await SeedServiceRateAsync(log, 1, "Bronze service rate", true);//1 await SeedServiceRateAsync(log, 1, "Silver service rate", true);//2 await SeedServiceRateAsync(log, 1, "Gold service rate", true);//3 { Contract c = new Contract(); c.Name = "Bronze"; c.Active = true; c.Notes = "These are notes providing additional information when users view the contract"; c.AlertNotes = "These are alert notes displayed on workorders about this contract"; c.PartsOverridePct = 5m; c.PartsOverrideType = ContractOverrideType.PriceDiscount; c.ServiceRatesOverridePct = 0m; c.ServiceRatesOverrideType = ContractOverrideType.PriceDiscount; c.TravelRatesOverridePct = 0; c.TravelRatesOverrideType = ContractOverrideType.PriceDiscount; c.ResponseTime = TimeSpan.Zero; c.ContractServiceRatesOnly = true; c.ServiceRateItems.Add(new ContractServiceRate() { ServiceRateId = 1 }); c.ContractTravelRatesOnly = true; c.TravelRateItems.Add(new ContractTravelRate() { TravelRateId = 1 }); c.ContractServiceRateOverrideItems.Add(new ContractServiceRateOverride() { Tags = new string[] { "blue" }.ToList(), OverridePct = 5m, OverrideType = ContractOverrideType.PriceDiscount }); c.ContractTravelRateOverrideItems.Add(new ContractTravelRateOverride() { Tags = new string[] { "blue" }.ToList(), OverridePct = 5m, OverrideType = ContractOverrideType.PriceDiscount }); c.ContractPartOverrideItems.Add(new ContractPartOverride() { Tags = new string[] { "blue" }.ToList(), OverridePct = 10m, OverrideType = ContractOverrideType.PriceDiscount }); using (AyContext ct = ServiceProviderProvider.DBContext) { ContractBiz biz = ContractBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(c); if (NewObject == null) { var err = $"Seeder::SeedKnownObjects error creating Bronze contract\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } { Contract c = new Contract(); c.Name = "Silver"; c.Active = true; c.Notes = "These are notes providing additional information when users view the contract"; c.AlertNotes = "These are alert notes displayed on workorders about this contract"; c.PartsOverridePct = .1m; c.PartsOverrideType = ContractOverrideType.PriceDiscount; c.ServiceRatesOverridePct = 0m; c.ServiceRatesOverrideType = ContractOverrideType.PriceDiscount; c.TravelRatesOverridePct = 0; c.TravelRatesOverrideType = ContractOverrideType.PriceDiscount; c.ResponseTime = TimeSpan.Zero; c.ContractServiceRatesOnly = true; c.ServiceRateItems.Add(new ContractServiceRate() { ServiceRateId = 2 }); c.ContractTravelRatesOnly = true; c.TravelRateItems.Add(new ContractTravelRate() { TravelRateId = 2 }); c.ContractServiceRateOverrideItems.Add(new ContractServiceRateOverride() { Tags = new string[] { "red" }.ToList(), OverridePct = 10m, OverrideType = ContractOverrideType.PriceDiscount }); c.ContractTravelRateOverrideItems.Add(new ContractTravelRateOverride() { Tags = new string[] { "red" }.ToList(), OverridePct = 10m, OverrideType = ContractOverrideType.PriceDiscount }); c.ContractPartOverrideItems.Add(new ContractPartOverride() { Tags = new string[] { "red" }.ToList(), OverridePct = 5m, OverrideType = ContractOverrideType.PriceDiscount }); using (AyContext ct = ServiceProviderProvider.DBContext) { ContractBiz biz = ContractBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(c); if (NewObject == null) { var err = $"Seeder::SeedKnownObjects error creating Silver contract\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } { Contract c = new Contract(); c.Name = "Gold"; c.Active = true; c.Notes = "These are notes providing additional information when users view the contract"; c.AlertNotes = "These are alert notes displayed on workorders about this contract"; c.PartsOverridePct = .2m; c.PartsOverrideType = ContractOverrideType.PriceDiscount; c.ServiceRatesOverridePct = .2m; c.ServiceRatesOverrideType = ContractOverrideType.PriceDiscount; c.TravelRatesOverridePct = .2m; c.TravelRatesOverrideType = ContractOverrideType.PriceDiscount; c.ResponseTime = new TimeSpan(24, 0, 0);//24 hour response time c.ContractServiceRatesOnly = false; c.ServiceRateItems.Add(new ContractServiceRate() { ServiceRateId = 3 }); c.ContractTravelRatesOnly = false; c.TravelRateItems.Add(new ContractTravelRate() { TravelRateId = 3 }); c.ContractServiceRateOverrideItems.Add(new ContractServiceRateOverride() { Tags = new string[] { "green" }.ToList(), OverridePct = 10m, OverrideType = ContractOverrideType.PriceDiscount }); c.ContractTravelRateOverrideItems.Add(new ContractTravelRateOverride() { Tags = new string[] { "green" }.ToList(), OverridePct = 10m, OverrideType = ContractOverrideType.PriceDiscount }); c.ContractPartOverrideItems.Add(new ContractPartOverride() { Tags = new string[] { "green" }.ToList(), OverridePct = 10m, OverrideType = ContractOverrideType.PriceDiscount }); using (AyContext ct = ServiceProviderProvider.DBContext) { ContractBiz biz = ContractBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(c); if (NewObject == null) { var err = $"Seeder::SeedKnownObjects error creating Gold contract\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } { long HeadOfficeIdForCustomer = 0; //seed a HO HeadOffice ho = new HeadOffice(); ho.Name = "XYZ Head Office"; ho.Active = true; ho.Notes = Fake.Company.CatchPhrase(); ho.Tags = RandomTags(); ho.AccountNumber = Fake.Finance.Account(); ho.Latitude = (decimal)Fake.Address.Latitude(); ho.Longitude = (decimal)Fake.Address.Longitude(); ho.Address = Fake.Address.StreetAddress(); ho.City = Fake.Address.City(); ho.Region = Fake.Address.State(); ho.Country = Fake.Address.Country(); ho.Phone1 = Fake.Phone.PhoneNumber(); ho.Phone2 = Fake.Phone.PhoneNumber(); ho.Phone3 = Fake.Phone.PhoneNumber(); ho.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); ho.EmailAddress = Fake.Internet.ExampleEmail(); ho.ContractId = 3;//gold contract ho.ContractExpires = DateTime.UtcNow.AddYears(1); using (AyContext ct = ServiceProviderProvider.DBContext) { HeadOfficeBiz biz = HeadOfficeBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(ho); if (NewObject == null) { var err = $"Seeder::SeedKnownHeadOffice error creating {ho.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } //Known HO type user await SeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.HeadOffice, true, "HeadOffice", "HeadOffice", 0, KnownUserTags, null, null, NewObject.Id); HeadOfficeIdForCustomer = NewObject.Id; } //CUSTOMER / HO Users //seed a customer Customer o = new Customer(); o.Name = "XYZ Accounting"; o.HeadOfficeId = HeadOfficeIdForCustomer; o.Active = true; o.Notes = Fake.Company.CatchPhrase(); o.Tags = RandomTags(); o.AccountNumber = Fake.Finance.Account(); o.Latitude = (decimal)Fake.Address.Latitude(); o.Longitude = (decimal)Fake.Address.Longitude(); o.Address = Fake.Address.StreetAddress(); o.City = Fake.Address.City(); o.Region = Fake.Address.State(); o.Country = Fake.Address.Country(); o.Phone1 = Fake.Phone.PhoneNumber(); o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); o.EmailAddress = Fake.Internet.ExampleEmail(); using (AyContext ct = ServiceProviderProvider.DBContext) { CustomerBiz biz = CustomerBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); if (NewObject == null) { var err = $"Seeder::SeedKnownCustomer error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } //Known customer type users await SeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.Customer, true, "CustomerFull", "CustomerFull", 0, KnownUserTags, null, NewObject.Id, null); await SeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.Customer, true, "CustomerLimited", "CustomerLimited", 0, KnownUserTags, null, NewObject.Id, null); } } { //VENDOR AND SUBCONTRACTORS //Yellow Cedar Consulting long VendorIdForSubContractorUser = 0; Vendor o = new Vendor(); o.Name = "Yellow Cedar Consulting"; o.Active = true; o.Notes = Fake.Company.CatchPhrase(); o.Tags = RandomTags(); o.Contact = Fake.Name.FullName(); o.ContactNotes = Fake.Name.FullName(); o.AccountNumber = Fake.Finance.Account(); o.Latitude = (decimal)Fake.Address.Latitude(); o.Longitude = (decimal)Fake.Address.Longitude(); o.Address = Fake.Address.StreetAddress(); o.City = Fake.Address.City(); o.Region = Fake.Address.State(); o.Country = Fake.Address.Country(); o.Phone1 = Fake.Phone.PhoneNumber(); o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); o.EmailAddress = Fake.Internet.ExampleEmail(); //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { VendorBiz biz = VendorBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); if (NewObject == null) { var err = $"Seeder::SeedKnownVendor error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } VendorIdForSubContractorUser = NewObject.Id; } await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorLimited, UserType.ServiceContractor, true, "SubContractorLimited", "SubContractorLimited", 0, KnownUserTags, VendorIdForSubContractorUser, null, null); await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorFull, UserType.ServiceContractor, true, "SubContractorFull", "SubContractorFull", 0, KnownUserTags, VendorIdForSubContractorUser, null, null); } ///////////////////////////////////////////////////// //Seed some test memos { for (int x = 0; x < 200; x++) { Memo memo = new Memo(); memo.Name = Fake.Lorem.Sentence(); memo.Notes = Fake.Lorem.Paragraphs(); memo.ToId = Fake.Random.Long(1, 17); memo.FromId = Fake.Random.Long(1, 17); memo.Tags = RandomTags(); using (AyContext ct = ServiceProviderProvider.DBContext) { MemoBiz biz = MemoBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(memo); if (NewObject == null) { var err = $"Seeder::SeedKnownObjects error creating memo\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } ///////////////////////////////////////////////////// //TAX CODES long TCSales = 0, TCGoods = 0, TCBoth = 0; { { TaxCode tc = new TaxCode(); tc.Name = "Sales only"; tc.Notes = "Example sales only tax"; tc.Active = true; tc.Tags = RandomTags(); tc.TaxAPct = 0; tc.TaxBPct = 7m; tc.TaxOnTax = false; using (AyContext ct = ServiceProviderProvider.DBContext) { TaxCodeBiz biz = TaxCodeBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(tc); if (NewObject == null) { var err = $"Seeder::SeedKnownObjects error creating TaxCode\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } TCSales = NewObject.Id; } } { TaxCode tc = new TaxCode(); tc.Name = "Goods only"; tc.Active = true; tc.Notes = "Example goods only tax"; tc.Tags = RandomTags(); tc.TaxBPct = 0; tc.TaxAPct = 7m; tc.TaxOnTax = false; using (AyContext ct = ServiceProviderProvider.DBContext) { TaxCodeBiz biz = TaxCodeBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(tc); if (NewObject == null) { var err = $"Seeder::SeedKnownObjects error creating TaxCode\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } TCGoods = NewObject.Id; } } { TaxCode tc = new TaxCode(); tc.Name = "Sales & Goods"; tc.Active = true; tc.Notes = "Example sales and goods tax"; tc.Tags = RandomTags(); tc.TaxAPct = 7m; tc.TaxBPct = 7m; tc.TaxOnTax = false; using (AyContext ct = ServiceProviderProvider.DBContext) { TaxCodeBiz biz = TaxCodeBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(tc); if (NewObject == null) { var err = $"Seeder::SeedKnownObjects error creating TaxCode\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } TCBoth = NewObject.Id; } } } ///////////////////////////////////////////////////// //GLOBAL SETTINGS { using (AyContext ct = ServiceProviderProvider.DBContext) { GlobalBizSettingsBiz biz = GlobalBizSettingsBiz.GetBiz(ct); var gbiz = await biz.GetAsync(false); gbiz.TaxPartPurchaseId = TCGoods; gbiz.TaxPartSaleId = TCGoods; gbiz.TaxRateSaleId = TCSales; await biz.PutAsync(gbiz); } } /////////////////////////////////////////////// } catch { throw; } } /// /// Generate seed user with active=true /// (override to save typing) /// public async Task SeedUserAsync(ILogger log, int count, AuthorizationRoles roles, UserType userType, string login, string password, List tags = null) { try { await SeedUserAsync(log, count, roles, userType, true, login, password, 0, tags); } catch { throw; } } public HashSet HashUserNames = new HashSet(); private int TotalSeededUsers = 0; public async Task SeedUserAsync( ILogger log, int count, AuthorizationRoles roles, UserType userType, bool active = true, string login = null, string password = null, long translationId = 0, List tags = null, long? vendorId = null, long? customerId = null, long? headofficeId = null ) { if (translationId == 0) translationId = ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID; //to return for code that creates a single user and needs the id long LastSeededUserId = 0; for (int x = 0; x < count; x++) { User u = new User(); u.Active = active; do { u.Name = Fake.Name.FullName(); } while (!HashUserNames.Add(u.Name)); var bogusEmail = u.Name.ToLowerInvariant().Replace(" ", "_") + "@example.net"; if (login != null) { u.Login = login; u.Name += " - " + login; } else u.Login = bogusEmail; if (password != null) u.Password = password; else u.Password = u.Login; u.Roles = roles; u.UserType = userType; u.EmployeeNumber = "A-" + (454 + TotalSeededUsers + x).ToString() + "-Y"; u.Notes = Fake.Lorem.Sentence(null, 5);//Fake.Lorem.Paragraph(2); //TODO: After have USER and HEADOFFICE and VENDOR, if usertype is subcontractor or client or headoffice it needs to set a corresponding user's parent org record id to go with it //use provided tags or generate them if (tags == null) u.Tags = RandomTags(); else u.Tags = tags; //relations u.VendorId = vendorId; u.CustomerId = customerId; u.HeadOfficeId = headofficeId; //Children and relations u.UserOptions = new UserOptions(); u.UserOptions.TranslationId = translationId; u.UserOptions.EmailAddress = bogusEmail; u.UserOptions.Hour12 = true; u.UserOptions.CurrencyName = "USD"; u.UserOptions.UiColor = Fake.Internet.Color().ToUpperInvariant(); //this seems wrong to get a new context inside a loop but in testing is actually faster!? using (AyContext ct = ServiceProviderProvider.DBContext) { UserBiz biz = UserBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(u); TotalSeededUsers++; if (NewObject == null) { log.LogError($"Seeder::SeedUser error creating {u.Name}\r\n" + biz.GetErrorsAsString()); throw new System.Exception("Seeder::SeedUser error creating user\r\n" + biz.GetErrorsAsString()); } LastSeededUserId = NewObject.Id; } } return LastSeededUserId; } #region WIDGET ////////////////////////////////////////////////////// //Seed widget for testing // public async Task SeedWidgetAsync(ILogger log, int count) { //this is 4 times slower than doing it inside the loop below //seems counterintuitive but maybe it's to do with the db context not being refreshed? //RANDOM ROLES Array values = Enum.GetValues(typeof(UserType)); Random random = new Random(); DateTime seedStartWindow = DateTime.Now.AddYears(-1).AddMonths(-6); DateTime seedEndWindow = DateTime.Now.AddYears(1).AddMonths(6); for (int x = 0; x < count; x++) { Widget o = new Widget(); o.Name = Uniquify(Fake.Commerce.ProductName()); o.Active = true; DateTime dtSeed = Fake.Date.Between(seedStartWindow, seedEndWindow).ToUniversalTime(); o.StartDate = dtSeed; o.EndDate = dtSeed.AddMinutes(60).ToUniversalTime(); o.DollarAmount = Convert.ToDecimal(Fake.Commerce.Price()); //Random but valid enum UserType randomUserType = (UserType)values.GetValue(random.Next(values.Length)); o.UserType = randomUserType; o.Notes = Fake.Lorem.Sentence(null, 5); o.Tags = RandomTags(); o.UserId = Fake.Random.Int(1, TotalSeededUsers); //RANDOM CUSTOM FIELD DATA var c1 = DateUtil.UniversalISO8661Format(Fake.Date.Between(DateTime.Now.AddYears(-1), DateTime.Now.AddYears(1))); var c2 = Fake.Lorem.Sentence(null, 5); var c3 = Fake.Random.Int(1, 99999999); var c4 = Fake.Random.Bool().ToString().ToLowerInvariant(); var c5 = Fake.Random.Decimal(); o.CustomFields = $@"{{c1:""{c1}"",c2:""{c2}"",c3:{c3},c4:{c4},c5:{c5}}}"; //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { WidgetBiz biz = WidgetBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); if (NewObject == null) { log.LogError($"Seeder::SeedWidget error creating {o.Name}\r\n" + biz.GetErrorsAsString()); throw new System.Exception("Seeder::SeedWidget error creating widget\r\n" + biz.GetErrorsAsString()); } } } } #endregion public HashSet HashCompanyNames = new HashSet(); private int TotalSeededCustomers = 0; ////////////////////////////////////////////////////// //CUSTOMER // public async Task SeedCustomerAsync(ILogger log, int count, long? headOfficeId = null) { for (int x = 0; x < count; x++) { Customer o = new Customer(); do { o.Name = Fake.Company.CompanyName(); } while (!HashCompanyNames.Add(o.Name)); o.Active = true; o.Notes = Fake.Company.CatchPhrase(); o.Tags = RandomTags(); o.AccountNumber = Fake.Finance.Account(); o.Latitude = (decimal)Fake.Address.Latitude(); o.Longitude = (decimal)Fake.Address.Longitude(); o.Address = Fake.Address.StreetAddress(); o.City = Fake.Address.City(); o.Region = Fake.Address.State(); o.Country = Fake.Address.Country(); o.Phone1 = Fake.Phone.PhoneNumber(); o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); o.EmailAddress = Fake.Internet.ExampleEmail(); if (headOfficeId != null) { o.HeadOfficeId = headOfficeId; o.BillHeadOffice = true; } //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { CustomerBiz biz = CustomerBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededCustomers++; if (NewObject == null) { var err = $"Seeder::SeedCustomer error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } //Customer contacts //10% chance (0-9) if (Fake.Random.Number(9) == 4) await SeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.Customer, true, null, null, 0, null, null, NewObject.Id, null); } } } private int TotalSeededHeadOffices = 0; ////////////////////////////////////////////////////// //HEADOFFICE // public async Task SeedHeadOfficeAsync(ILogger log, int count) { for (int x = 0; x < count; x++) { HeadOffice o = new HeadOffice(); do { o.Name = Fake.Company.CompanyName(); } while (!HashCompanyNames.Add(o.Name)); o.Active = true; o.Notes = Fake.Company.CatchPhrase(); o.Tags = RandomTags(); o.AccountNumber = Fake.Finance.Account(); o.Latitude = (decimal)Fake.Address.Latitude(); o.Longitude = (decimal)Fake.Address.Longitude(); o.Address = Fake.Address.StreetAddress(); o.City = Fake.Address.City(); o.Region = Fake.Address.State(); o.Country = Fake.Address.Country(); o.Phone1 = Fake.Phone.PhoneNumber(); o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); o.EmailAddress = Fake.Internet.ExampleEmail(); //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { HeadOfficeBiz biz = HeadOfficeBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededHeadOffices++; if (NewObject == null) { var err = $"Seeder::SeedHeadOffice error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } //HeadOffice contacts await SeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.HeadOffice, true, null, null, 0, null, null, null, NewObject.Id); //HeadOffice Customer await SeedCustomerAsync(log, 2, NewObject.Id); } } } private int TotalSeededVendors = 0; ////////////////////////////////////////////////////// //VENDOR // public async Task SeedVendorAsync(ILogger log, int count) { for (int x = 0; x < count; x++) { Vendor o = new Vendor(); do { o.Name = Fake.Company.CompanyName(); } while (!HashCompanyNames.Add(o.Name)); o.Active = true; o.Notes = Fake.Company.CatchPhrase(); o.Tags = RandomTags(); o.Contact = Fake.Name.FullName(); o.ContactNotes = Fake.Name.FullName(); o.AccountNumber = Fake.Finance.Account(); o.Latitude = (decimal)Fake.Address.Latitude(); o.Longitude = (decimal)Fake.Address.Longitude(); o.Address = Fake.Address.StreetAddress(); o.City = Fake.Address.City(); o.Region = Fake.Address.State(); o.Country = Fake.Address.Country(); o.Phone1 = Fake.Phone.PhoneNumber(); o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); o.EmailAddress = Fake.Internet.ExampleEmail(); //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { VendorBiz biz = VendorBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededVendors++; if (NewObject == null) { var err = $"Seeder::SeedVendor error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } public HashSet HashProjectNames = new HashSet(); private int TotalSeededProjects = 0; ////////////////////////////////////////////////////// //PROJECT // public async Task SeedProjectAsync(ILogger log, int count) { DateTime seedStartWindow = DateTime.Now.AddYears(-1); DateTime seedEndWindow = DateTime.Now.AddYears(1); for (int x = 0; x < count; x++) { Project o = new Project(); do { var color = Fake.Commerce.Color(); o.Name = $"{char.ToUpper(color[0]) + color.Substring(1)} {Fake.Address.StreetSuffix()}"; } while (!HashProjectNames.Add(o.Name)); o.AccountNumber = Fake.Finance.Account(); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); DateTime dtSeed = Fake.Date.Between(seedStartWindow, seedEndWindow).ToUniversalTime(); o.DateStarted = dtSeed; if (Fake.Random.Number(9) != 5) o.DateCompleted = dtSeed.AddDays(Fake.Random.Long(2, 100)); o.ProjectOverseerId = Fake.Random.Long(2, 13);//NOTE: this is exactly 13 not total seeded users because it needs to be inside users and they're seeded first //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { ProjectBiz biz = ProjectBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededProjects++; if (NewObject == null) { var err = $"Seeder::SeedProject error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } public HashSet HashRateNames = new HashSet(); private int TotalSeededServiceRates = 0; ////////////////////////////////////////////////////// //SERVICERATE // public async Task SeedServiceRateAsync(ILogger log, int count, string presetName = null, bool contractOnly = false) { for (int x = 0; x < count; x++) { ServiceRate o = new ServiceRate(); do { if (!string.IsNullOrWhiteSpace(presetName)) { o.Name = presetName; } else { var color = Fake.Commerce.Color(); o.Name = $"{char.ToUpper(color[0]) + color.Substring(1)} {Fake.Address.CountryCode()}"; } } while (!HashRateNames.Add(o.Name)); o.AccountNumber = Fake.Finance.Account(); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); o.Cost = Fake.Random.Decimal(0.25m, 50); o.Charge = o.Cost * 1.55m; o.Unit = "hour"; o.ContractOnly = contractOnly; //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { ServiceRateBiz biz = ServiceRateBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededServiceRates++; if (NewObject == null) { var err = $"Seeder::SeedServiceRate error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } private int TotalSeededTravelRates = 0; ////////////////////////////////////////////////////// //TRAVELRATE // public async Task SeedTravelRateAsync(ILogger log, int count, string presetName = null, bool contractOnly = false) { var Units = new[] { "km", "miles", "hours" }; for (int x = 0; x < count; x++) { TravelRate o = new TravelRate(); do { if (!string.IsNullOrWhiteSpace(presetName)) { o.Name = presetName; } else { var color = Fake.Commerce.Color(); o.Name = $"{char.ToUpper(color[0]) + color.Substring(1)} {Fake.Address.CountryCode()}"; } } while (!HashRateNames.Add(o.Name)); o.AccountNumber = Fake.Finance.Account(); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); o.Cost = Fake.Random.Decimal(0.25m, 10); o.Charge = o.Cost * 2m; o.Unit = Fake.PickRandom(Units); o.ContractOnly = contractOnly; //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { TravelRateBiz biz = TravelRateBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededTravelRates++; if (NewObject == null) { var err = $"Seeder::SeedTravelRate error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } public HashSet HashUnitModelNames = new HashSet(); private int TotalSeededUnitModels = 0; ////////////////////////////////////////////////////// //UNITMODEL // public async Task SeedUnitModelAsync(ILogger log, int count) { DateTime seedStartWindow = DateTime.Now.AddYears(-5); DateTime seedEndWindow = DateTime.Now.AddYears(1); var WarrantyMonths = new[] { 1, 6, 12, 24, 36 }; var WarrantyTerms = new[] { "Parts only", "Parts and service", "Service only", "Shipping parts and service", "First month parts and service here; after is depot only" }; for (int x = 0; x < count; x++) { UnitModel o = new UnitModel(); do { o.Name = $"{Fake.Vehicle.Model()} {Fake.Commerce.Categories(1)[0]}"; } while (!HashUnitModelNames.Add(o.Name)); do { o.Number = Fake.Finance.Account(6); } while (!HashUnitModelNames.Add(o.Number)); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); o.VendorId = Fake.Random.Long(1, TotalSeededVendors);//random picks in range Inclusive but sql id's start at 1 so this is kosher (not zero based) o.UPC = Fake.Commerce.Ean13(); o.LifeTimeWarranty = false; o.IntroducedDate = Fake.Date.Between(seedStartWindow, DateTime.Now).ToUniversalTime(); o.Discontinued = false; o.DiscontinuedDate = null; o.WarrantyLength = Fake.PickRandom(WarrantyMonths); o.WarrantyTerms = Fake.PickRandom(WarrantyTerms); //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { UnitModelBiz biz = UnitModelBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededUnitModels++; if (NewObject == null) { var err = $"Seeder::SeedUnitModel error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } public HashSet HashUnitNames = new HashSet(); private int TotalSeededUnits = 0; ////////////////////////////////////////////////////// //UNIT // public async Task SeedUnitAsync(ILogger log, int count) { DateTime seedStartWindow = DateTime.Now.AddYears(-10); DateTime seedEndWindow = DateTime.Now.AddYears(1); var WarrantyMonths = new[] { 1, 6, 12, 24, 36 }; var WarrantyTerms = new[] { "Parts only", "Parts and service", "Service only", "Shipping parts and service", "First month parts and service here; after is depot only" }; for (int x = 0; x < count; x++) { Unit o = new Unit(); do { o.Serial = Fake.Finance.Account(); } while (!HashUnitNames.Add(o.Serial)); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); //Override model warranty 5% chance (1/20) if (Fake.Random.Number(1, 20) == 5) { o.OverrideModelWarranty = true; o.LifeTimeWarranty = false; o.WarrantyLength = Fake.PickRandom(WarrantyMonths); o.WarrantyTerms = Fake.PickRandom(WarrantyTerms); } o.CustomerId = Fake.Random.Long(1, TotalSeededCustomers); o.UnitModelId = Fake.Random.Long(1, TotalSeededUnitModels); o.BoughtHere = true; //Unit bought elsewhere 10% chance (1/10) if (Fake.Random.Number(1, 10) == 5) { o.BoughtHere = false; o.PurchasedFromVendorId = Fake.Random.Long(1, TotalSeededVendors); } o.Receipt = Fake.Finance.Account(6); o.PurchasedDate = Fake.Date.Between(seedStartWindow, DateTime.Now).ToUniversalTime(); o.Description = Fake.Commerce.ProductName(); o.ReplacedByUnitId = null; //Has unit contract 5% chance (1/20) if (Fake.Random.Number(1, 20) == 5) { o.ContractId = Fake.Random.Number(1, 3); o.ContractExpires = DateTime.UtcNow.AddYears(1); } //for now no banked units in seeds o.UsesBanking = false; o.Metered = false;//for now no meters either o.Text1 = null; o.Text2 = null; o.Text3 = null; o.Text4 = null; //Unit has own address 5% chance (1/20) if (Fake.Random.Number(1, 20) == 5) { o.UnitHasOwnAddress = true; o.Latitude = (decimal)Fake.Address.Latitude(); o.Longitude = (decimal)Fake.Address.Longitude(); o.Address = Fake.Address.StreetAddress(); o.City = Fake.Address.City(); o.Region = Fake.Address.State(); o.Country = Fake.Address.Country(); } else { o.UnitHasOwnAddress = false; } //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { UnitBiz biz = UnitBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededUnits++; if (NewObject == null) { var err = $"Seeder::SeedUnit error creating {o.Serial}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } private int TotalSeededLoanUnits = 0; ////////////////////////////////////////////////////// //LOANUNIT // public async Task SeedLoanLoanUnitAsync(ILogger log, int count) { for (int x = 0; x < count; x++) { LoanUnit o = new LoanUnit(); do { o.Serial = Fake.Finance.Account(); } while (!HashUnitNames.Add(o.Serial)); do { o.Name = Fake.Commerce.ProductName(); } while (!HashUnitNames.Add(o.Name)); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); o.RateHour = Fake.Random.Decimal(1, 25); o.RateHalfDay = o.RateHour * 4; o.RateDay = o.RateHour * 8; o.RateWeek = o.RateHour * 36.8m; o.RateMonth = o.RateHour * 21 * 8; o.RateYear = o.RateHour * 36.8m * 52; o.DefaultRate = Fake.Random.Enum(); using (AyContext ct = ServiceProviderProvider.DBContext) { LoanUnitBiz biz = LoanUnitBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededLoanUnits++; if (NewObject == null) { var err = $"Seeder::SeedLoanUnit error creating {o.Serial}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } ////////////////////////////////////////////////////// //CUSTOMERSERVICEREQUEST // public async Task SeedCustomerServiceRequestAsync(ILogger log, int count) { DateTime seedStartWindow = DateTime.Now.AddYears(-1); DateTime seedEndWindow = DateTime.Now.AddMonths(-11); for (int x = 0; x < count; x++) { CustomerServiceRequest o = new CustomerServiceRequest(); o.Name = Fake.Hacker.Phrase(); o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); o.DateRequested = Fake.Date.Between(seedStartWindow, seedEndWindow).ToUniversalTime(); o.CustomerId = Fake.Random.Long(1, TotalSeededCustomers); o.RequestedByUserId = await SeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.Customer, true, null, null, 0, null, null, o.CustomerId, null); o.Status = CustomerServiceRequestStatus.Open; o.Priority = Fake.Random.Enum(); o.CustomerReferenceNumber = Fake.Finance.Account(); using (AyContext ct = ServiceProviderProvider.DBContext) { CustomerServiceRequestBiz biz = CustomerServiceRequestBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); if (NewObject == null) { var err = $"Seeder::SeedCustomerServiceRequest error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } public HashSet HashPartWarehouseNames = new HashSet(); private int TotalSeededPartWarehouses = 1;//Default warehouse is already present ////////////////////////////////////////////////////// //PARTWAREHOUSE // public async Task SeedPartWarehouseAsync(ILogger log, int count) { for (int x = 0; x < count; x++) { PartWarehouse o = new PartWarehouse(); do { o.Name = $"WHS- {Fake.Address.StreetName()}"; } while (!HashPartWarehouseNames.Add(o.Name)); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { PartWarehouseBiz biz = PartWarehouseBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededPartWarehouses++; if (NewObject == null) { var err = $"Seeder::SeedPartWarehouse error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } public HashSet HashPartNumbers = new HashSet(); private int TotalSeededParts = 0; ////////////////////////////////////////////////////// //PART // public async Task SeedPartAsync(ILogger log, int count, int maxQuantity) { //for testing purposes make a quarter (approx) of parts that are lower than restock level int PartStockLevelParts = count / 4; //Console.WriteLine($"SEEDER PartStockLevelParts is {PartStockLevelParts}"); for (int x = 0; x < count; x++) { Part o = new Part(); do { o.PartNumber = Fake.Finance.Account(6); } while (!HashPartNumbers.Add(o.PartNumber)); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); o.ManufacturerId = Fake.Random.Long(1, 3);//There are minimum 10 vendors seeded, want parts all in the first few so that some po stuff can kick in (vendorpartnumber etc) o.ManufacturerNumber = "man-" + o.PartNumber; o.UPC = Fake.Commerce.Ean13(); o.WholeSalerId = Fake.Random.Long(4, 6); o.WholeSalerNumber = "ws-" + o.PartNumber; o.AlternativeWholeSalerId = Fake.Random.Long(7, 9); o.AlternativeWholeSalerNumber = "aws-" + o.PartNumber; o.Cost = Fake.Random.Decimal(1, 25); o.Retail = o.Cost * 1.2m; o.UnitOfMeasure = "each"; //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { PartBiz biz = PartBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededParts++; if (NewObject == null) { var err = $"Seeder::SeedPart error creating {o.PartNumber}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } int OpeningInventoryLevel = Fake.Random.Number(1, maxQuantity); PartInventoryBiz PartInventoryBizNess = PartInventoryBiz.GetBiz(ct); // 25% chance it has serial numbers if (Fake.Random.Number(0, 4) == 1) { var serialStart = Fake.Finance.Account(5).ToString(); for (int y = 0; y < OpeningInventoryLevel; y++) { await ct.PartSerial.AddAsync(new PartSerial() { PartId = NewObject.Id, Serial = serialStart + "-" + y.ToString() }); } await ct.SaveChangesAsync(); } PartInventory partInventory = null; //Add inventory into multiple warehouses for testing for (int y = 0; y < 3; y++) { int WarehouseNumber = y + 1; //add opening inventory partInventory = await PartInventoryBizNess.CreateAsync(new dtPartInventory() { PartId = NewObject.Id, PartWarehouseId = WarehouseNumber, Quantity = OpeningInventoryLevel, Description = "New part opening inventory" }); //Example adjustments? if (Fake.Random.Number(1, 10) == 1) // 10% adjusted { //make two adjustments to have some testing data if (partInventory != null) partInventory = await PartInventoryBizNess.CreateAsync(new dtPartInventory() { PartId = NewObject.Id, PartWarehouseId = WarehouseNumber, Quantity = -1, Description = "example adjustment" }); if (partInventory != null) partInventory = await PartInventoryBizNess.CreateAsync(new dtPartInventory() { PartId = NewObject.Id, PartWarehouseId = WarehouseNumber, Quantity = Fake.Random.Number(1, 3), Description = "example adjustment" }); } if (partInventory == null) { var err = $"Seeder::SeedPart - error creating {o.PartNumber} INVENTORY \r\n{PartInventoryBizNess.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } if (PartStockLevelParts > 0) { PartStockLevelParts--; List partStockLevels = new List(); partStockLevels.Add(new PartStockLevel() { PartWarehouseId = 1, PartId = NewObject.Id, MinimumQuantity = OpeningInventoryLevel * 2 }); await biz.PutStockLevelsAsync(NewObject.Id, partStockLevels); } } } } public HashSet HashPartAssemblyNames = new HashSet(); private int TotalSeededPartAssemblies = 0; ////////////////////////////////////////////////////// //PARTASSEMBLY // public async Task SeedPartAssemblyAsync(ILogger log, int count) { for (int x = 0; x < count; x++) { PartAssembly o = new PartAssembly(); List partsAdded = new List(); do { o.Name = "asm" + Fake.Finance.Account(4); } while (!HashPartAssemblyNames.Add(o.Name)); o.Active = true; o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); int partCount = Fake.Random.Int(2, 5); for (int y = 0; y < partCount; y++) { long partId = 0; do { partId = Fake.Random.Long(1, TotalSeededParts); } while (partsAdded.Contains(partId)); partsAdded.Add(partId); o.Items.Add(new PartAssemblyItem() { PartId = partId }); } //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { PartAssemblyBiz biz = PartAssemblyBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o); TotalSeededPartAssemblies++; if (NewObject == null) { var err = $"Seeder::SeedPartAssembly error creating {o.Name}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } private int TotalSeededPurchaseOrders = 0; ////////////////////////////////////////////////////// //PURCHASE ORDER // public async Task SeedPurchaseOrderAsync(ILogger log, int count) { DateTime seedStartWindow = DateTime.Now.AddYears(-1); DateTime seedEndWindow = DateTime.Now.AddDays(-5); for (int x = 0; x < count; x++) { PurchaseOrder o = new PurchaseOrder(); o.Notes = Fake.Lorem.Sentence(); o.Tags = RandomTags(); o.VendorId = Fake.Random.Long(1, 9);//this matches the range set in parts so that we get ALL vendor numbers being set var poDate = Fake.Date.Between(seedStartWindow, seedEndWindow); o.OrderedDate = poDate.ToUniversalTime(); o.ExpectedReceiveDate = poDate.AddDays(5).ToUniversalTime(); o.ReferenceNumber = Fake.Finance.Account(6); o.VendorMemo = Fake.Lorem.Sentence(); if (Fake.Random.Number(1, 10) == 5) o.ProjectId = Fake.Random.Long(1, TotalSeededProjects); o.Text1 = Fake.Lorem.Sentence(1, 3); o.Text2 = Fake.Lorem.Sentence(1, 3); List partsAdded = new List(); int partCount = Fake.Random.Int(1, 5); //simulate some items without tax codes bool addTaxCode = (Fake.Random.Number(1, 4) != 3); //simulate some items not received bool isReceived = (Fake.Random.Number(1, 4) != 3); o.Status = isReceived ? PurchaseOrderStatus.ClosedFullReceived : PurchaseOrderStatus.OpenOrdered; for (int y = 0; y < partCount; y++) { long partId = 0; do { partId = Fake.Random.Long(1, TotalSeededParts); } while (partsAdded.Contains(partId)); partsAdded.Add(partId); var qty = Fake.Random.Int(1, 5); var cost = Fake.Random.Decimal(1, 25); // 50% chance it has received serial numbers string serials = string.Empty; if (isReceived && Fake.Random.Number() == 1) { var serialStart = Fake.Finance.Account().ToString(); for (int si = 0; si < qty; si++) { serials += serialStart + si.ToString() + ", "; } serials = serials.TrimEnd().TrimEnd(','); } o.Items.Add(new PurchaseOrderItem() { PartId = partId, PartWarehouseId = Fake.Random.Long(1, 3), QuantityOrdered = qty, QuantityReceived = isReceived ? qty : 0, PurchaseOrderCost = cost, ReceivedCost = isReceived ? cost : 0, ReceivedDate = isReceived ? o.ExpectedReceiveDate : null, PurchaseTaxCodeId = addTaxCode ? 3 : null,//sales and goods Serials = serials }); } //This seems wrong to do in a loop but is 4 times faster this way ?!? using (AyContext ct = ServiceProviderProvider.DBContext) { PurchaseOrderBiz biz = PurchaseOrderBiz.GetBiz(ct); var NewObject = await biz.CreateAsync(o, false); TotalSeededPurchaseOrders++; if (NewObject == null) { var err = $"Seeder::SeedPurchaseOrder error creating {o.Serial}\r\n{biz.GetErrorsAsString()}"; log.LogError(err); throw new System.Exception(err); } } } } ////////////////////////////////////////////////////////////////////////////////////////////////// }//eoc }//eons