Files
raven/server/AyaNova/util/Seeder.cs
2021-03-07 20:18:19 +00:00

1980 lines
95 KiB
C#

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<string> RandomTags()
{
var t = Fake.PickRandom(TagSet, Fake.Random.Int(1, 5));//pick up to 5 tags to apply
return new List<string>(t);
}
//////////////////////////////////////////////////////
//Seed test data for integration tests
//
public async Task SeedKnownObjectsAsync(ILogger log)
{
try
{
var KnownUserTags = new List<string>();
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;
}
}
/// <summary>
/// Generate seed user with active=true
/// (override to save typing)
/// </summary>
public async Task SeedUserAsync(ILogger log, int count, AuthorizationRoles roles, UserType userType, string login, string password, List<string> tags = null)
{
try
{
await SeedUserAsync(log, count, roles, userType, true, login, password, 0, tags);
}
catch
{
throw;
}
}
public HashSet<string> HashUserNames = new HashSet<string>();
private int TotalSeededUsers = 0;
public async Task<long> SeedUserAsync(
ILogger log, int count, AuthorizationRoles roles, UserType userType,
bool active = true, string login = null, string password = null,
long translationId = 0, List<string> 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<string> HashCompanyNames = new HashSet<string>();
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<string> HashProjectNames = new HashSet<string>();
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<string> HashRateNames = new HashSet<string>();
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<string> HashUnitModelNames = new HashSet<string>();
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<string> HashUnitNames = new HashSet<string>();
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<LoanUnitRateUnit>();
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<CustomerServiceRequestPriority>();
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<string> HashPartWarehouseNames = new HashSet<string>();
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<string> HashPartNumbers = new HashSet<string>();
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<PartStockLevel> partStockLevels = new List<PartStockLevel>();
partStockLevels.Add(new PartStockLevel() { PartWarehouseId = 1, PartId = NewObject.Id, MinimumQuantity = OpeningInventoryLevel * 2 });
await biz.PutStockLevelsAsync(NewObject.Id, partStockLevels);
}
}
}
}
public HashSet<string> HashPartAssemblyNames = new HashSet<string>();
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<long> partsAdded = new List<long>();
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<long> partsAdded = new List<long>();
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