diff --git a/server/AyaNova/Controllers/TrialController.cs b/server/AyaNova/Controllers/TrialController.cs index ab107518..640b72d9 100644 --- a/server/AyaNova/Controllers/TrialController.cs +++ b/server/AyaNova/Controllers/TrialController.cs @@ -7,6 +7,7 @@ using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Biz; using Newtonsoft.Json.Linq; +using System.ComponentModel.DataAnnotations; namespace AyaNova.Api.Controllers { @@ -47,13 +48,15 @@ namespace AyaNova.Api.Controllers /// "Medium" - Local service company with multiple employees and departments dataset /// "Large" - Large corporate multi regional dataset /// "Huge" - Used for automated testing and development, if you choose this it will take a very long time (15 minutes to overnight) + /// TimeZoneOffset - Value in hours of local time zone offset from UTC / GMT. This ensures that data is generated relative to the desired time zone + /// E2e - End to end testing mode for development automated testing; false is default and faster + /// ForceEmail - set every generated object with an email address to this email address + /// AppendPassword - append this string to the stock passwords, useful when testing on the public internet /// - /// Valid values are "Small", "Medium", "Large", "Huge" - /// Value in hours of local time zone offset from UTC / GMT. This ensures that data is generated relative to the desired time zone - /// End to end testing mode for automated testing; false is default and faster + /// /// Job Id - [HttpPost("seed/{size}/{timeZoneOffset}/{e2e}")] - public async Task SeedTrialDatabase([FromRoute] string size, [FromRoute] decimal timeZoneOffset, [FromRoute] bool e2e = false) + [HttpPost("seed")] + public async Task SeedTrialDatabase([FromBody] SeedOptions seedOptions) { if (serverState.IsClosed) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); @@ -68,7 +71,7 @@ namespace AyaNova.Api.Controllers return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, "Current license is not a trial license key. Only a trial can be seeded.")); } - Seeder.Level.SeedLevel seedLevel = Seeder.Level.StringToSeedLevel(size); + Seeder.Level.SeedLevel seedLevel = Seeder.Level.StringToSeedLevel(seedOptions.Size); if (seedLevel == Seeder.Level.SeedLevel.NotValid) return BadRequest(new ApiErrorResponse(ApiErrorCode.NOT_FOUND, "size", "Valid values are \"small\", \"medium\", \"large\", \"huge\"")); @@ -76,25 +79,38 @@ namespace AyaNova.Api.Controllers JObject o = JObject.FromObject(new { - seedLevel = seedLevel, - timeZoneOffset = timeZoneOffset, - e2e = e2e + seedLevel = seedOptions.Size, + timeZoneOffset = seedOptions.TimeZoneOffset, + e2e = seedOptions.E2e, + forceEmail=seedOptions.ForceEmail, + appendPassword=seedOptions.AppendPassword }); OpsJob j = new OpsJob(); - j.Name = $"Seed test data (size={size})"; + j.Name = $"Seed test data (size={seedOptions.Size})"; j.JobType = JobType.SeedTestData; j.Exclusive = true;//don't run other jobs, this will erase the db j.JobInfo = o.ToString(); await JobsBiz.AddJobAsync(j); //Log - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.TrialSeeder, AyaEvent.Created, size), ct); + await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.TrialSeeder, AyaEvent.Created, seedOptions.Size), ct); return Accepted(new { JobId = j.GId });//202 accepted } + public class SeedOptions + { + [Required] + public string Size { get; set; } + [Required] + public decimal TimeZoneOffset { get; set; } + public bool E2e { get; set; } = false; + [EmailAddress] + public string ForceEmail { get; set; } + public string AppendPassword { get; set; } + } //------------ diff --git a/server/AyaNova/Startup.cs b/server/AyaNova/Startup.cs index 81484e0b..4791c970 100644 --- a/server/AyaNova/Startup.cs +++ b/server/AyaNova/Startup.cs @@ -316,7 +316,7 @@ namespace AyaNova //////////////////////////////////////////////////////////// // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // - public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env, + public async void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env, AyContext dbContext, IApiVersionDescriptionProvider provider, AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, IServiceProvider serviceProvider) { @@ -633,7 +633,7 @@ namespace AyaNova _newLog.LogInformation($"Server test mode seeding, level is {ServerBootConfig.AYANOVA_SERVER_TEST_MODE_SEEDLEVEL}, tz offset is {ServerBootConfig.AYANOVA_SERVER_TEST_MODE_TZ_OFFSET}"); AyaNova.Core.License.FetchKeyAsync(apiServerState, dbContext, _newLog, true, true).Wait(); var seed = new Util.Seeder(); - seed.SeedDatabaseAsync(Seeder.Level.StringToSeedLevel(ServerBootConfig.AYANOVA_SERVER_TEST_MODE_SEEDLEVEL), ServerBootConfig.AYANOVA_SERVER_TEST_MODE_TZ_OFFSET).Wait(); + seed.SeedDatabaseAsync(Seeder.Level.StringToSeedLevel(ServerBootConfig.AYANOVA_SERVER_TEST_MODE_SEEDLEVEL), ServerBootConfig.AYANOVA_SERVER_TEST_MODE_TZ_OFFSET,null,null).Wait(); // _newLog.LogInformation("Seeding completed"); } #endif diff --git a/server/AyaNova/biz/TrialBiz.cs b/server/AyaNova/biz/TrialBiz.cs index 9533291d..1c830f64 100644 --- a/server/AyaNova/biz/TrialBiz.cs +++ b/server/AyaNova/biz/TrialBiz.cs @@ -66,8 +66,11 @@ namespace AyaNova.Biz var seedLevel = (Seeder.Level.SeedLevel)jobData["seedLevel"].Value(); var timeZoneOffset = jobData["timeZoneOffset"].Value(); var e2e = jobData["e2e"].Value(); + var forceEmail = jobData["forceEmail"].Value(); + var appendPassword = jobData["appendPassword"].Value(); + var seed = new Util.Seeder(); - await seed.SeedDatabaseAsync(seedLevel, job.GId, timeZoneOffset, e2e); + await seed.SeedDatabaseAsync(seedLevel, job.GId, timeZoneOffset,forceEmail,appendPassword, e2e); await JobsBiz.LogJobAsync(job.GId, "LT:JobCompleted"); await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Completed); } diff --git a/server/AyaNova/util/Seeder.cs b/server/AyaNova/util/Seeder.cs index 3205e0b0..edac09d0 100644 --- a/server/AyaNova/util/Seeder.cs +++ b/server/AyaNova/util/Seeder.cs @@ -59,12 +59,12 @@ namespace AyaNova.Util //Seed database for trial and testing purposes // - public async Task SeedDatabaseAsync(Level.SeedLevel slevel, Decimal timeZoneOffset, bool e2e = false) + public async Task SeedDatabaseAsync(Level.SeedLevel slevel, Decimal timeZoneOffset, string forceEmail, string appendPassword, bool e2e = false) { - await SeedDatabaseAsync(slevel, Guid.Empty, timeZoneOffset, e2e); + await SeedDatabaseAsync(slevel, Guid.Empty, timeZoneOffset, forceEmail, appendPassword, e2e); } - public async Task SeedDatabaseAsync(Level.SeedLevel slevel, Guid JobId, Decimal timeZoneOffset, bool e2e = false) + public async Task SeedDatabaseAsync(Level.SeedLevel slevel, Guid JobId, Decimal timeZoneOffset, string forceEmail, string appendPassword, bool e2e = false) { bool LogJob = JobId != Guid.Empty; _e2e = e2e; @@ -203,7 +203,7 @@ namespace AyaNova.Util //Seed special test data for integration testing //log.LogInformation("Seeding known users"); - await SeedKnownObjectsAsync(log); + await SeedKnownObjectsAsync(log, forceEmail, appendPassword); /* ███████╗███████╗███████╗██████╗ █████╗ ██╗ ██╗ ████████╗██╗ ██╗███████╗ ████████╗██╗ ██╗██╗███╗ ██╗ ██████╗ ███████╗ @@ -227,23 +227,23 @@ namespace AyaNova.Util watch.Start(); //Generate owner and lead tech - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.OpsAdmin, UserType.Service); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.OpsAdmin, UserType.Service, forceEmail, appendPassword); //Generate one office person / secretary - await SeedUserAsync(log, 1, AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.Accounting, UserType.NotService); + await SeedUserAsync(log, 1, AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.Accounting, UserType.NotService, forceEmail, appendPassword); //2 other techs (must always be enough to have no dupes per workorder) - await SeedUserAsync(log, 2, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service); + await SeedUserAsync(log, 2, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service, forceEmail, appendPassword); - await SeedVendorAsync(log, 10); + await SeedVendorAsync(log, 10, forceEmail); await SeedUnitModelAsync(log, 10); - await SeedCustomerAsync(log, 25, slevel); - await SeedHeadOfficeAsync(log, 10, slevel); - await SeedVendorAsync(log, 10); + await SeedCustomerAsync(log, 25, slevel, forceEmail, appendPassword); + await SeedHeadOfficeAsync(log, 10, slevel, forceEmail, appendPassword); + await SeedVendorAsync(log, 10, forceEmail); await SeedProjectAsync(log, 3); await SeedServiceRateAsync(log, 5); await SeedTravelRateAsync(log, 3); await SeedLoanLoanUnitAsync(log, 5); - await SeedCustomerServiceRequestAsync(log, 5); + await SeedCustomerServiceRequestAsync(log, 5, forceEmail, appendPassword); await SeedPartWarehouseAsync(log, 5); await SeedPartAsync(log, 20, 1000); await SeedPartAssemblyAsync(log, 5); @@ -270,39 +270,39 @@ namespace AyaNova.Util watch.Start(); //One IT administrator, can change ops but nothing else - await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdmin, UserType.NotService); + await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdmin, UserType.NotService, forceEmail, appendPassword); //One business administrator, can view ops issues - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdminRestricted, UserType.NotService, forceEmail, appendPassword); //One owner who doesn't control anything but views stuff - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted | AuthorizationRoles.OpsAdminRestricted | AuthorizationRoles.SalesRestricted, UserType.NotService); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted | AuthorizationRoles.OpsAdminRestricted | AuthorizationRoles.SalesRestricted, UserType.NotService, forceEmail, appendPassword); //////////////////////////////////////////////// //TECHS (LICENSE CONSUMERS) //trial license allows 1000 // //regular techs - await SeedUserAsync(log, 5, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service); + await SeedUserAsync(log, 5, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service, forceEmail, appendPassword); //Restricted techs // await SeedUserAsync(log, 2, AuthorizationRoles.TechRestricted | AuthorizationRoles.ServiceRestricted, UserType.Service); //subcontractors - await SeedUserAsync(log, 1, AuthorizationRoles.SubContractor, UserType.ServiceContractor); + await SeedUserAsync(log, 1, AuthorizationRoles.SubContractor, UserType.ServiceContractor, forceEmail, appendPassword); //Restricted subcontractors // await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorRestricted, UserType.ServiceContractor); /////////////////////////////////////////// //3 generic office people people - await SeedUserAsync(log, 3, AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 3, AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //2 Full sales people - await SeedUserAsync(log, 2, AuthorizationRoles.Sales, UserType.NotService); + await SeedUserAsync(log, 2, AuthorizationRoles.Sales, UserType.NotService, forceEmail, appendPassword); //1 Service manager - await SeedUserAsync(log, 1, AuthorizationRoles.Service | AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 1, AuthorizationRoles.Service | AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //1 Inventory manager - await SeedUserAsync(log, 1, AuthorizationRoles.Inventory | AuthorizationRoles.ServiceRestricted, UserType.NotService); + await SeedUserAsync(log, 1, AuthorizationRoles.Inventory | AuthorizationRoles.ServiceRestricted, UserType.NotService, forceEmail, appendPassword); //1 accountant / bookkeeper - await SeedUserAsync(log, 1, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 1, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService, forceEmail, appendPassword); - await SeedVendorAsync(log, 50); + await SeedVendorAsync(log, 50, forceEmail); await SeedUnitModelAsync(log, 20); - await SeedCustomerAsync(log, 500, slevel); - await SeedHeadOfficeAsync(log, 20, slevel); + await SeedCustomerAsync(log, 500, slevel, forceEmail, appendPassword); + await SeedHeadOfficeAsync(log, 20, slevel, forceEmail, appendPassword); await SeedProjectAsync(log, 5); await SeedServiceRateAsync(log, 10); @@ -310,7 +310,7 @@ namespace AyaNova.Util //await SeedUnitAsync(log, 2500); await SeedLoanLoanUnitAsync(log, 10); - await SeedCustomerServiceRequestAsync(log, 10); + await SeedCustomerServiceRequestAsync(log, 10, forceEmail, appendPassword); await SeedPartWarehouseAsync(log, 10); await SeedPartAsync(log, 100, 1000); await SeedPartAssemblyAsync(log, 5); @@ -339,45 +339,45 @@ namespace AyaNova.Util //USERS //IT administrator, can change ops but nothing else - await SeedUserAsync(log, 2, AuthorizationRoles.OpsAdmin, UserType.NotService); + await SeedUserAsync(log, 2, AuthorizationRoles.OpsAdmin, UserType.NotService, forceEmail, appendPassword); //business administrator, can view ops issues - await SeedUserAsync(log, 2, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 2, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdminRestricted, UserType.NotService, forceEmail, appendPassword); //owner / upper management who doesn't control anything but views stuff - await SeedUserAsync(log, 5, AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted | AuthorizationRoles.OpsAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 5, AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted | AuthorizationRoles.OpsAdminRestricted, UserType.NotService, forceEmail, appendPassword); //////////////////////////////////////////////// //TECHS (LICENSE CONSUMERS) //trial license allows 1000 // //regular techs - await SeedUserAsync(log, 8, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service); + await SeedUserAsync(log, 8, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service, forceEmail, appendPassword); //Restricted techs - await SeedUserAsync(log, 1, AuthorizationRoles.TechRestricted | AuthorizationRoles.ServiceRestricted, UserType.Service); + await SeedUserAsync(log, 1, AuthorizationRoles.TechRestricted | AuthorizationRoles.ServiceRestricted, UserType.Service, forceEmail, appendPassword); //subcontractors - await SeedUserAsync(log, 1, AuthorizationRoles.SubContractor, UserType.ServiceContractor); + await SeedUserAsync(log, 1, AuthorizationRoles.SubContractor, UserType.ServiceContractor, forceEmail, appendPassword); //Restricted subcontractors - await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorRestricted, UserType.ServiceContractor); + await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorRestricted, UserType.ServiceContractor, forceEmail, appendPassword); /////////////////////////////////////////// //30 generic office people people - await SeedUserAsync(log, 30, AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 30, AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //10 Full sales people - await SeedUserAsync(log, 10, AuthorizationRoles.Sales, UserType.NotService); + await SeedUserAsync(log, 10, AuthorizationRoles.Sales, UserType.NotService, forceEmail, appendPassword); //5 Restricted sales people - await SeedUserAsync(log, 5, AuthorizationRoles.SalesRestricted, UserType.NotService); + await SeedUserAsync(log, 5, AuthorizationRoles.SalesRestricted, UserType.NotService, forceEmail, appendPassword); //5 Service manager - await SeedUserAsync(log, 5, AuthorizationRoles.Service | AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 5, AuthorizationRoles.Service | AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //5 Inventory manager - await SeedUserAsync(log, 5, AuthorizationRoles.Inventory | AuthorizationRoles.ServiceRestricted, UserType.NotService); + await SeedUserAsync(log, 5, AuthorizationRoles.Inventory | AuthorizationRoles.ServiceRestricted, UserType.NotService, forceEmail, appendPassword); //10 Inventory manager assistants - await SeedUserAsync(log, 5, AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 5, AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //5 accountant / bookkeeper - await SeedUserAsync(log, 5, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 5, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService, forceEmail, appendPassword); - await SeedVendorAsync(log, 100); + await SeedVendorAsync(log, 100, forceEmail); await SeedUnitModelAsync(log, 40); - await SeedCustomerAsync(log, 1000, slevel); - await SeedHeadOfficeAsync(log, 40, slevel); + await SeedCustomerAsync(log, 1000, slevel, forceEmail, appendPassword); + await SeedHeadOfficeAsync(log, 40, slevel, forceEmail, appendPassword); await SeedProjectAsync(log, 10); await SeedServiceRateAsync(log, 20); @@ -385,7 +385,7 @@ namespace AyaNova.Util // await SeedUnitAsync(log, 5000); await SeedLoanLoanUnitAsync(log, 20); - await SeedCustomerServiceRequestAsync(log, 20); + await SeedCustomerServiceRequestAsync(log, 20, forceEmail, appendPassword); await SeedPartWarehouseAsync(log, 20); await SeedPartAsync(log, 200, 1000); await SeedPartAssemblyAsync(log, 5); @@ -415,52 +415,52 @@ namespace AyaNova.Util //USERS //IT administrator, can change ops but nothing else - await SeedUserAsync(log, 10, AuthorizationRoles.OpsAdmin, UserType.NotService); + await SeedUserAsync(log, 10, AuthorizationRoles.OpsAdmin, UserType.NotService, forceEmail, appendPassword); //business administrator, can view ops issues - await SeedUserAsync(log, 10, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 10, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdminRestricted, UserType.NotService, forceEmail, appendPassword); //owner / upper management who doesn't control anything but views stuff - await SeedUserAsync(log, 20, AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted | AuthorizationRoles.OpsAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 20, AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted | AuthorizationRoles.OpsAdminRestricted, UserType.NotService, forceEmail, appendPassword); //////////////////////////////////////////////// //TECHS (LICENSE CONSUMERS) //trial license allows 1000 // //regular techs - await SeedUserAsync(log, 15, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service); + await SeedUserAsync(log, 15, AuthorizationRoles.Tech | AuthorizationRoles.ServiceRestricted, UserType.Service, forceEmail, appendPassword); //Restricted techs - await SeedUserAsync(log, 2, AuthorizationRoles.TechRestricted | AuthorizationRoles.ServiceRestricted, UserType.Service); + await SeedUserAsync(log, 2, AuthorizationRoles.TechRestricted | AuthorizationRoles.ServiceRestricted, UserType.Service, forceEmail, appendPassword); //subcontractors - await SeedUserAsync(log, 2, AuthorizationRoles.SubContractor, UserType.ServiceContractor); + await SeedUserAsync(log, 2, AuthorizationRoles.SubContractor, UserType.ServiceContractor, forceEmail, appendPassword); //Restricted subcontractors - await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorRestricted, UserType.ServiceContractor); + await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorRestricted, UserType.ServiceContractor, forceEmail, appendPassword); /////////////////////////////////////////// //generic office people people - await SeedUserAsync(log, 500, AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 500, AuthorizationRoles.ServiceRestricted | AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //20 Full sales people - await SeedUserAsync(log, 60, AuthorizationRoles.Sales, UserType.NotService); + await SeedUserAsync(log, 60, AuthorizationRoles.Sales, UserType.NotService, forceEmail, appendPassword); //10 Restricted sales people - await SeedUserAsync(log, 10, AuthorizationRoles.SalesRestricted, UserType.NotService); + await SeedUserAsync(log, 10, AuthorizationRoles.SalesRestricted, UserType.NotService, forceEmail, appendPassword); //Service manager - await SeedUserAsync(log, 20, AuthorizationRoles.Service | AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 20, AuthorizationRoles.Service | AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //Inventory manager - await SeedUserAsync(log, 40, AuthorizationRoles.Inventory | AuthorizationRoles.ServiceRestricted, UserType.NotService); + await SeedUserAsync(log, 40, AuthorizationRoles.Inventory | AuthorizationRoles.ServiceRestricted, UserType.NotService, forceEmail, appendPassword); //Inventory manager assistants - await SeedUserAsync(log, 20, AuthorizationRoles.InventoryRestricted, UserType.NotService); + await SeedUserAsync(log, 20, AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword); //accountant / bookkeeper - await SeedUserAsync(log, 20, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService); + await SeedUserAsync(log, 20, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService, forceEmail, appendPassword); - await SeedVendorAsync(log, 5000); + await SeedVendorAsync(log, 5000, forceEmail); await SeedUnitModelAsync(log, 400); - await SeedCustomerAsync(log, 10000, slevel); - await SeedHeadOfficeAsync(log, 500, slevel); + await SeedCustomerAsync(log, 10000, slevel, forceEmail, appendPassword); + await SeedHeadOfficeAsync(log, 500, slevel, forceEmail, appendPassword); await SeedProjectAsync(log, 1000); await SeedServiceRateAsync(log, 200); await SeedTravelRateAsync(log, 100); await SeedLoanLoanUnitAsync(log, 200); - await SeedCustomerServiceRequestAsync(log, 200); + await SeedCustomerServiceRequestAsync(log, 200, forceEmail, appendPassword); await SeedPartWarehouseAsync(log, 200); await SeedPartAsync(log, 10000, 1000); await SeedPartAssemblyAsync(log, 500); @@ -586,34 +586,34 @@ namespace AyaNova.Util ////////////////////////////////////////////////////// //Seed known / expected test data for tests/development // - public async Task SeedKnownObjectsAsync(ILogger log) + public async Task SeedKnownObjectsAsync(ILogger log, string forceEmail, string appendPassword) { var KnownUserTags = new List(); KnownUserTags.Add("known-user"); KnownUserTags.Add("test-role-user"); //TRIAL USERS //one of each role type - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminRestricted, UserType.NotService, "BizAdminRestricted", "BizAdminRestricted", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin, UserType.NotService, "BizAdmin", "BizAdmin", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.ServiceRestricted, UserType.NotService, "ServiceRestricted", "ServiceRestricted", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.Service, UserType.NotService, "Service", "Service", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.InventoryRestricted, UserType.NotService, "InventoryRestricted", "InventoryRestricted", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.Inventory, UserType.NotService, "Inventory", "Inventory", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.Accounting, UserType.NotService, "Accounting", "Accounting", KnownUserTags); - KnownUserTechRestrictedId = await SeedUserAsync(log, 1, AuthorizationRoles.TechRestricted, UserType.Service, "TechRestricted", "TechRestricted", KnownUserTags); - KnownUserTechId = await SeedUserAsync(log, 1, AuthorizationRoles.Tech, UserType.Service, "Tech", "Tech", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.SalesRestricted, UserType.NotService, "SalesRestricted", "SalesRestricted", KnownUserTags); - KnownUserSalesId = await SeedUserAsync(log, 1, AuthorizationRoles.Sales, UserType.NotService, "Sales", "Sales", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminRestricted, UserType.NotService, "OpsAdminRestricted", "OpsAdminRestricted", KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdmin, UserType.NotService, "OpsAdmin", "OpsAdmin", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdminRestricted, UserType.NotService, forceEmail, appendPassword, "BizAdminRestricted", "BizAdminRestricted", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin, UserType.NotService, forceEmail, appendPassword, "BizAdmin", "BizAdmin", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.ServiceRestricted, UserType.NotService, forceEmail, appendPassword, "ServiceRestricted", "ServiceRestricted", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.Service, UserType.NotService, forceEmail, appendPassword, "Service", "Service", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.InventoryRestricted, UserType.NotService, forceEmail, appendPassword, "InventoryRestricted", "InventoryRestricted", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.Inventory, UserType.NotService, forceEmail, appendPassword, "Inventory", "Inventory", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.Accounting, UserType.NotService, forceEmail, appendPassword, "Accounting", "Accounting", KnownUserTags); + KnownUserTechRestrictedId = await SeedUserAsync(log, 1, AuthorizationRoles.TechRestricted, UserType.Service, forceEmail, appendPassword, "TechRestricted", "TechRestricted", KnownUserTags); + KnownUserTechId = await SeedUserAsync(log, 1, AuthorizationRoles.Tech, UserType.Service, forceEmail, appendPassword, "Tech", "Tech", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.SalesRestricted, UserType.NotService, forceEmail, appendPassword, "SalesRestricted", "SalesRestricted", KnownUserTags); + KnownUserSalesId = await SeedUserAsync(log, 1, AuthorizationRoles.Sales, UserType.NotService, forceEmail, appendPassword, "Sales", "Sales", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminRestricted, UserType.NotService, forceEmail, appendPassword, "OpsAdminRestricted", "OpsAdminRestricted", KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdmin, UserType.NotService, forceEmail, appendPassword, "OpsAdmin", "OpsAdmin", KnownUserTags); //Alternate translation users for each stock translation - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdmin, UserType.NotService, true, "de", "de", await TranslationBiz.TranslationNameToIdStaticAsync("de"), KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdmin, UserType.NotService, true, "es", "es", await TranslationBiz.TranslationNameToIdStaticAsync("es"), KnownUserTags); - await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdmin, UserType.NotService, true, "fr", "fr", await TranslationBiz.TranslationNameToIdStaticAsync("fr"), KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdmin, UserType.NotService, forceEmail, appendPassword, true, "de", "de", await TranslationBiz.TranslationNameToIdStaticAsync("de"), KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdmin, UserType.NotService, forceEmail, appendPassword, true, "es", "es", await TranslationBiz.TranslationNameToIdStaticAsync("es"), KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.OpsAdmin, UserType.NotService, forceEmail, appendPassword, true, "fr", "fr", await TranslationBiz.TranslationNameToIdStaticAsync("fr"), KnownUserTags); //TEST NOT ACTIVE - this is used for a test to see if inactive user can login - await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminRestricted, UserType.NotService, false, "TEST_INACTIVE", "TEST_INACTIVE", 0, KnownUserTags); + await SeedUserAsync(log, 1, AuthorizationRoles.OpsAdminRestricted, UserType.NotService, forceEmail, appendPassword, false, "TEST_INACTIVE", "TEST_INACTIVE", 0, KnownUserTags); ///////////////////////////////////////////////////// @@ -761,7 +761,7 @@ namespace AyaNova.Util ho.Phone3 = Fake.Phone.PhoneNumber(); ho.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); - ho.EmailAddress = Fake.Internet.ExampleEmail(); + ho.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? Fake.Internet.ExampleEmail() : forceEmail; ho.ContractId = 3;//gold contract ho.ContractExpires = DateTime.UtcNow.AddYears(1); @@ -778,7 +778,7 @@ namespace AyaNova.Util throw new System.Exception(err); } //Known HO type user - await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.HeadOffice, true, "HeadOffice", "HeadOffice", 0, KnownUserTags, null, null, NewObject.Id); + await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.HeadOffice, forceEmail, appendPassword, true, "HeadOffice", "HeadOffice", 0, KnownUserTags, null, null, NewObject.Id); HeadOfficeIdForCustomer = NewObject.Id; } @@ -806,7 +806,7 @@ namespace AyaNova.Util o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); - o.EmailAddress = Fake.Internet.ExampleEmail(); + o.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? Fake.Internet.ExampleEmail() : forceEmail; using (AyContext ct = ServiceProviderProvider.DBContext) @@ -821,8 +821,8 @@ namespace AyaNova.Util throw new System.Exception(err); } //Known customer type users - KnownUserCustomerId = await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, true, "Customer", "Customer", 0, KnownUserTags, null, NewObject.Id, null); - KnownUserCustomerRestrictedId = await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, true, "CustomerRestricted", "CustomerRestricted", 0, KnownUserTags, null, NewObject.Id, null); + KnownUserCustomerId = await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, forceEmail, appendPassword, true, "Customer", "Customer", 0, KnownUserTags, null, NewObject.Id, null); + KnownUserCustomerRestrictedId = await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, forceEmail, appendPassword, true, "CustomerRestricted", "CustomerRestricted", 0, KnownUserTags, null, NewObject.Id, null); //5 units per customer await SeedUnitAsync(log, 20, NewObject.Id);//5 times the customers or 5 units per customer } @@ -892,7 +892,7 @@ namespace AyaNova.Util o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); - o.EmailAddress = Fake.Internet.ExampleEmail(); + o.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? Fake.Internet.ExampleEmail() : forceEmail; //intentional: tested and faster in loop using (AyContext ct = ServiceProviderProvider.DBContext) @@ -909,8 +909,8 @@ namespace AyaNova.Util VendorIdForSubContractorUser = NewObject.Id; } - KnownUserSubContractorRestrictedId = await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorRestricted, UserType.ServiceContractor, true, "SubContractorRestricted", "SubContractorRestricted", 0, KnownUserTags, VendorIdForSubContractorUser, null, null); - KnownUserSubContractorId = await SeedUserAsync(log, 1, AuthorizationRoles.SubContractor, UserType.ServiceContractor, true, "SubContractor", "SubContractor", 0, KnownUserTags, VendorIdForSubContractorUser, null, null); + KnownUserSubContractorRestrictedId = await SeedUserAsync(log, 1, AuthorizationRoles.SubContractorRestricted, UserType.ServiceContractor, forceEmail, appendPassword, true, "SubContractorRestricted", "SubContractorRestricted", 0, KnownUserTags, VendorIdForSubContractorUser, null, null); + KnownUserSubContractorId = await SeedUserAsync(log, 1, AuthorizationRoles.SubContractor, UserType.ServiceContractor, forceEmail, appendPassword, true, "SubContractor", "SubContractor", 0, KnownUserTags, VendorIdForSubContractorUser, null, null); } @@ -1678,7 +1678,7 @@ namespace AyaNova.Util gbiz.Phone1 = Fake.Phone.PhoneNumber(); gbiz.Phone2 = Fake.Phone.PhoneNumber(); gbiz.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); - gbiz.EmailAddress = Fake.Internet.ExampleEmail(); + gbiz.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? Fake.Internet.ExampleEmail() : forceEmail; gbiz.TaxPartPurchaseId = TCGoods; gbiz.TaxPartSaleId = TCGoods; @@ -1709,11 +1709,11 @@ namespace AyaNova.Util /// 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) + public async Task SeedUserAsync(ILogger log, int count, AuthorizationRoles roles, UserType userType, string forceEmail, string appendPassword, string login, string password, List tags = null) { try { - return await SeedUserAsync(log, count, roles, userType, true, login, password, 0, tags); + return await SeedUserAsync(log, count, roles, userType, forceEmail, appendPassword, true, login, password, 0, tags); } catch { @@ -1738,7 +1738,7 @@ namespace AyaNova.Util public async Task SeedUserAsync( - ILogger log, int count, AuthorizationRoles roles, UserType userType, + ILogger log, int count, AuthorizationRoles roles, UserType userType, string forceEmail, string appendPassword, bool active = true, string login = null, string password = null, long translationId = 0, List tags = null, long? vendorId = null, long? customerId = null, long? headofficeId = null @@ -1762,6 +1762,7 @@ namespace AyaNova.Util var bogusEmail = u.Name.ToLowerInvariant().Replace(" ", "_") + "@example.net"; + if (login != null) { u.Login = login; @@ -1773,7 +1774,7 @@ namespace AyaNova.Util if (password != null) u.Password = password; else - u.Password = u.Login; + u.Password = u.Login + appendPassword; u.Roles = roles; u.UserType = userType; u.EmployeeNumber = "A-" + (454 + TotalSeededUsers + x).ToString() + "-Y"; @@ -1799,10 +1800,10 @@ namespace AyaNova.Util //Children and relations u.UserOptions = new UserOptions(); u.UserOptions.TranslationId = translationId; - u.UserOptions.EmailAddress = bogusEmail; + u.UserOptions.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? bogusEmail : forceEmail; u.UserOptions.Hour12 = true; u.UserOptions.CurrencyName = "USD"; - u.UserOptions.UiColor = Fake.Internet.Color().ToUpperInvariant()+"FF"; + u.UserOptions.UiColor = Fake.Internet.Color().ToUpperInvariant() + "FF"; //this seems wrong to get a new context inside a loop but in testing is actually faster!? @@ -1834,7 +1835,7 @@ namespace AyaNova.Util ////////////////////////////////////////////////////// //CUSTOMER // - public async Task SeedCustomerAsync(ILogger log, int count, Level.SeedLevel slevel, long? headOfficeId = null) + public async Task SeedCustomerAsync(ILogger log, int count, Level.SeedLevel slevel, string forceEmail, string appendPassword, long? headOfficeId = null) { for (int x = 0; x < count; x++) @@ -1869,7 +1870,7 @@ namespace AyaNova.Util o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); - o.EmailAddress = Fake.Internet.ExampleEmail(); + o.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? Fake.Internet.ExampleEmail() : forceEmail; if (headOfficeId != null) { @@ -1895,7 +1896,7 @@ namespace AyaNova.Util //Customer contacts //10% chance (0-9) if (Fake.Random.Number(9) == 4) - await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, true, null, null, 0, null, null, NewObject.Id, null); + await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, forceEmail, appendPassword, true, null, null, 0, null, null, NewObject.Id, null); switch (slevel) { @@ -1917,7 +1918,7 @@ namespace AyaNova.Util ////////////////////////////////////////////////////// //HEADOFFICE // - public async Task SeedHeadOfficeAsync(ILogger log, int count, Level.SeedLevel slevel) + public async Task SeedHeadOfficeAsync(ILogger log, int count, Level.SeedLevel slevel, string forceEmail, string appendPassword) { for (int x = 0; x < count; x++) @@ -1952,7 +1953,7 @@ namespace AyaNova.Util o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); - o.EmailAddress = Fake.Internet.ExampleEmail(); + o.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? Fake.Internet.ExampleEmail() : forceEmail; @@ -1969,9 +1970,9 @@ namespace AyaNova.Util throw new System.Exception(err); } //HeadOffice contacts - await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.HeadOffice, true, null, null, 0, null, null, null, NewObject.Id); + await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.HeadOffice, forceEmail, appendPassword, true, null, null, 0, null, null, null, NewObject.Id); //HeadOffice Customer - await SeedCustomerAsync(log, 2, slevel, NewObject.Id); + await SeedCustomerAsync(log, 2, slevel, forceEmail, appendPassword, NewObject.Id); } } @@ -1982,7 +1983,7 @@ namespace AyaNova.Util ////////////////////////////////////////////////////// //VENDOR // - public async Task SeedVendorAsync(ILogger log, int count) + public async Task SeedVendorAsync(ILogger log, int count, string forceEmail) { for (int x = 0; x < count; x++) @@ -2032,7 +2033,7 @@ namespace AyaNova.Util o.Phone2 = Fake.Phone.PhoneNumber(); o.Phone3 = Fake.Phone.PhoneNumber(); o.WebAddress = Fake.Internet.Protocol() + "://example." + Fake.Internet.DomainSuffix(); - o.EmailAddress = Fake.Internet.ExampleEmail(); + o.EmailAddress = string.IsNullOrWhiteSpace(forceEmail) ? Fake.Internet.ExampleEmail() : forceEmail; //intentional: tested and faster in loop using (AyContext ct = ServiceProviderProvider.DBContext) @@ -2462,7 +2463,7 @@ namespace AyaNova.Util ////////////////////////////////////////////////////// //CUSTOMERSERVICEREQUEST // - public async Task SeedCustomerServiceRequestAsync(ILogger log, int count) + public async Task SeedCustomerServiceRequestAsync(ILogger log, int count, string forceEmail, string appendPassword) { DateTime seedStartWindow = DateTime.Now.AddMonths(-1); DateTime seedEndWindow = DateTime.Now; @@ -2476,7 +2477,7 @@ namespace AyaNova.Util o.Tags = RandomTags(); o.DateRequested = Fake.Date.Between(seedStartWindow, seedEndWindow).ToUniversalTime(); o.CustomerId = GetRandomCustomerId();//Fake.Random.Long(1, TotalSeededCustomers); - o.RequestedByUserId = await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, true, null, null, 0, null, null, o.CustomerId, null); + o.RequestedByUserId = await SeedUserAsync(log, 1, AuthorizationRoles.Customer, UserType.Customer, forceEmail, appendPassword, true, null, null, 0, null, null, o.CustomerId, null); o.Status = CustomerServiceRequestStatus.Open; o.Priority = Fake.Random.Enum(); o.CustomerReferenceNumber = Fake.Finance.Account(); @@ -2849,7 +2850,7 @@ namespace AyaNova.Util for (int x = 0; x < totalDays; x++) { - int thisDayGenerateThisMany=Fake.Random.Int(0,3)+3; + int thisDayGenerateThisMany = Fake.Random.Int(0, 3) + 3; for (int perDay = 0; perDay < thisDayGenerateThisMany; perDay++) { WorkOrder o = new WorkOrder(); @@ -2863,7 +2864,7 @@ namespace AyaNova.Util bool olderThanOneWeekAgo = (woDate.Subtract(DateTime.UtcNow).TotalDays < -7); bool isFutureDate = woDate > DateTime.UtcNow; - o.CreatedDate = woDate > DateTime.UtcNow ? DateTime.UtcNow.Subtract(new TimeSpan(Fake.Random.Int(1,30),0,0,0)) : woDate;//no created dates in future but want a range of past dates to show off age of wo + o.CreatedDate = woDate > DateTime.UtcNow ? DateTime.UtcNow.Subtract(new TimeSpan(Fake.Random.Int(1, 30), 0, 0, 0)) : woDate;//no created dates in future but want a range of past dates to show off age of wo o.CompleteByDate = woDate.AddDays(5); @@ -2934,25 +2935,25 @@ namespace AyaNova.Util //SCHEDULED USERS var actualScheduledUserCount = Fake.Random.Int(1, 2); if (isFutureDate && Fake.Random.Int(1, 10) == 2)//10% chance unscheduled future wo to show off unscheduled widget - actualScheduledUserCount=0; + actualScheduledUserCount = 0; - for (int a = 0; a < actualScheduledUserCount; a++) + for (int a = 0; a < actualScheduledUserCount; a++) + { + var randomStart = Fake.Random.Int(0, 5); + var randomHours = Fake.Random.Int(1, 4); + // var randomDays = Fake.Random.Int(0, 3); + var randomStop = randomStart + randomHours; + var woItemScheduledUser = new WorkOrderItemScheduledUser() { - var randomStart = Fake.Random.Int(0, 5); - var randomHours = Fake.Random.Int(1, 4); - // var randomDays = Fake.Random.Int(0, 3); - var randomStop = randomStart + randomHours; - var woItemScheduledUser = new WorkOrderItemScheduledUser() - { - UserId = RandomServiceTechUserId(), - EstimatedQuantity = randomHours, - StartDate = woDate.AddHours(randomStart),//.AddDays(randomDays), - StopDate = woDate.AddHours(randomStop)//.AddDays(randomDays) - }; - woItem.ScheduledUsers.Add(woItemScheduledUser); - } - + UserId = RandomServiceTechUserId(), + EstimatedQuantity = randomHours, + StartDate = woDate.AddHours(randomStart),//.AddDays(randomDays), + StopDate = woDate.AddHours(randomStop)//.AddDays(randomDays) + }; + woItem.ScheduledUsers.Add(woItemScheduledUser); + } + //PARTS