diff --git a/src/PowderCoating.Core/Entities/Accounting.cs b/src/PowderCoating.Core/Entities/Accounting.cs index 760494c..f9982da 100644 --- a/src/PowderCoating.Core/Entities/Accounting.cs +++ b/src/PowderCoating.Core/Entities/Accounting.cs @@ -395,3 +395,62 @@ public class FixedAssetDepreciationEntry : BaseEntity public virtual FixedAsset FixedAsset { get; set; } = null!; public virtual JournalEntry? JournalEntry { get; set; } } + +/// +/// A named annual budget. Contains one BudgetLine per account per month. Supports +/// multiple budgets per fiscal year (e.g. "Conservative" vs "Optimistic") but only +/// one is marked IsDefault for the Budget vs. Actual report. +/// +public class Budget : BaseEntity +{ + public string Name { get; set; } = string.Empty; + public int FiscalYear { get; set; } + public string? Notes { get; set; } + public bool IsDefault { get; set; } = false; + + public virtual ICollection Lines { get; set; } = new List(); +} + +/// +/// Monthly budget amount for one account within a Budget. Jan–Dec stored as separate +/// columns so the grid editor can write them in a single POST without a line-item loop. +/// Annual is a computed property summing all twelve months. +/// +public class BudgetLine : BaseEntity +{ + public int BudgetId { get; set; } + public int AccountId { get; set; } + + public decimal Jan { get; set; } + public decimal Feb { get; set; } + public decimal Mar { get; set; } + public decimal Apr { get; set; } + public decimal May { get; set; } + public decimal Jun { get; set; } + public decimal Jul { get; set; } + public decimal Aug { get; set; } + public decimal Sep { get; set; } + public decimal Oct { get; set; } + public decimal Nov { get; set; } + public decimal Dec { get; set; } + + public decimal Annual => Jan + Feb + Mar + Apr + May + Jun + Jul + Aug + Sep + Oct + Nov + Dec; + + public virtual Budget Budget { get; set; } = null!; + public virtual Account Account { get; set; } = null!; +} + +/// +/// Records a completed year-end close. The close posts a JE that zeroes all +/// Revenue and Expense account balances into Retained Earnings, and marks +/// the year as closed so it cannot be closed again. +/// +public class YearEndClose : BaseEntity +{ + public int ClosedYear { get; set; } + public DateTime ClosedAt { get; set; } = DateTime.UtcNow; + public string? ClosedBy { get; set; } + public int JournalEntryId { get; set; } + + public virtual JournalEntry JournalEntry { get; set; } = null!; +} diff --git a/src/PowderCoating.Core/Interfaces/IUnitOfWork.cs b/src/PowderCoating.Core/Interfaces/IUnitOfWork.cs index fe97b53..224ff68 100644 --- a/src/PowderCoating.Core/Interfaces/IUnitOfWork.cs +++ b/src/PowderCoating.Core/Interfaces/IUnitOfWork.cs @@ -113,6 +113,13 @@ public interface IUnitOfWork : IDisposable IRepository FixedAssets { get; } IRepository FixedAssetDepreciationEntries { get; } + // Budgeting + IRepository Budgets { get; } + IRepository BudgetLines { get; } + + // Year-End Close + IRepository YearEndCloses { get; } + // Notifications — typed repository for IgnoreQueryFilters-based history lookups INotificationLogRepository NotificationLogs { get; } IRepository NotificationTemplates { get; } diff --git a/src/PowderCoating.Infrastructure/Data/ApplicationDbContext.cs b/src/PowderCoating.Infrastructure/Data/ApplicationDbContext.cs index 641319f..65e95d0 100644 --- a/src/PowderCoating.Infrastructure/Data/ApplicationDbContext.cs +++ b/src/PowderCoating.Infrastructure/Data/ApplicationDbContext.cs @@ -343,6 +343,13 @@ public class ApplicationDbContext : IdentityDbContext, IDataPro /// One record per asset per period for each depreciation posting; soft-delete only. public DbSet FixedAssetDepreciationEntries { get; set; } + /// Named annual budgets with monthly amounts per GL account; tenant-filtered with soft delete. + public DbSet Budgets { get; set; } + /// One row per account per Budget; contains Jan–Dec decimal columns. + public DbSet BudgetLines { get; set; } + /// Audit trail of completed year-end closes; tenant-filtered with soft delete. + public DbSet YearEndCloses { get; set; } + /// Credit notes received from vendors (returned goods, pricing disputes); tenant-filtered with soft delete. public DbSet VendorCredits { get; set; } /// Expense-reversal line items on a vendor credit; soft-delete only. @@ -687,6 +694,27 @@ public class ApplicationDbContext : IdentityDbContext, IDataPro .HasForeignKey(e => e.JournalEntryId) .OnDelete(DeleteBehavior.NoAction); + // Budgets: tenant-filtered; BudgetLines soft-delete only + modelBuilder.Entity().HasQueryFilter(e => + !e.IsDeleted && (IsPlatformAdmin || e.CompanyId == CurrentCompanyId)); + modelBuilder.Entity().HasQueryFilter(e => !e.IsDeleted); + + // BudgetLine → Account: Restrict delete so removing an account doesn't cascade into budget data + modelBuilder.Entity() + .HasOne(bl => bl.Account) + .WithMany() + .HasForeignKey(bl => bl.AccountId) + .OnDelete(DeleteBehavior.Restrict); + + // YearEndClose: tenant-filtered; links to a specific JE + modelBuilder.Entity().HasQueryFilter(e => + !e.IsDeleted && (IsPlatformAdmin || e.CompanyId == CurrentCompanyId)); + modelBuilder.Entity() + .HasOne(y => y.JournalEntry) + .WithMany() + .HasForeignKey(y => y.JournalEntryId) + .OnDelete(DeleteBehavior.Restrict); + // Vendor Credits: tenant-filtered; child rows soft-delete only modelBuilder.Entity().HasQueryFilter(e => !e.IsDeleted && (IsPlatformAdmin || e.CompanyId == CurrentCompanyId)); diff --git a/src/PowderCoating.Infrastructure/Migrations/20260510165511_AddBudgetsAndYearEndClose.Designer.cs b/src/PowderCoating.Infrastructure/Migrations/20260510165511_AddBudgetsAndYearEndClose.Designer.cs new file mode 100644 index 0000000..1f158e6 --- /dev/null +++ b/src/PowderCoating.Infrastructure/Migrations/20260510165511_AddBudgetsAndYearEndClose.Designer.cs @@ -0,0 +1,10585 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PowderCoating.Infrastructure.Data; + +#nullable disable + +namespace PowderCoating.Infrastructure.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20260510165511_AddBudgetsAndYearEndClose")] + partial class AddBudgetsAndYearEndClose + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FriendlyName") + .HasColumnType("nvarchar(max)"); + + b.Property("Xml") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("DataProtectionKeys"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("AccountSubType") + .HasColumnType("int"); + + b.Property("AccountType") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CurrentBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsSystem") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OpeningBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("OpeningBalanceDate") + .HasColumnType("datetime2"); + + b.Property("ParentAccountId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ParentAccountId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AiItemPrediction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AiTags") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("Confidence") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ConversationRounds") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("PredictedComplexity") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PredictedMinutes") + .HasColumnType("int"); + + b.Property("PredictedSurfaceAreaSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("PredictedUnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Reasoning") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UserOverrodeEstimate") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.ToTable("AiItemPredictions"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AiUsageLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CalledAt") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("Feature") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("InputLength") + .HasColumnType("int"); + + b.Property("Success") + .HasColumnType("bit"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId", "CalledAt") + .HasDatabaseName("IX_AiUsageLogs_CompanyId_CalledAt"); + + b.ToTable("AiUsageLogs"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Announcement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedByUserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedByUserName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDismissible") + .HasColumnType("bit"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartsAt") + .HasColumnType("datetime2"); + + b.Property("Target") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TargetCompanyId") + .HasColumnType("int"); + + b.Property("TargetPlan") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.ToTable("Announcements"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AnnouncementDismissal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AnnouncementId") + .HasColumnType("int"); + + b.Property("DismissedAt") + .HasColumnType("datetime2"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("AnnouncementId", "UserId") + .IsUnique(); + + b.ToTable("AnnouncementDismissals"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("BanReason") + .HasColumnType("nvarchar(max)"); + + b.Property("BannedAt") + .HasColumnType("datetime2"); + + b.Property("BannedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CanApproveQuotes") + .HasColumnType("bit"); + + b.Property("CanCreateQuotes") + .HasColumnType("bit"); + + b.Property("CanManageCalendar") + .HasColumnType("bit"); + + b.Property("CanManageCustomers") + .HasColumnType("bit"); + + b.Property("CanManageEquipment") + .HasColumnType("bit"); + + b.Property("CanManageInventory") + .HasColumnType("bit"); + + b.Property("CanManageInvoices") + .HasColumnType("bit"); + + b.Property("CanManageJobs") + .HasColumnType("bit"); + + b.Property("CanManageMaintenance") + .HasColumnType("bit"); + + b.Property("CanManageProducts") + .HasColumnType("bit"); + + b.Property("CanManageVendors") + .HasColumnType("bit"); + + b.Property("CanViewCalendar") + .HasColumnType("bit"); + + b.Property("CanViewProducts") + .HasColumnType("bit"); + + b.Property("CanViewReports") + .HasColumnType("bit"); + + b.Property("CanViewShopFloor") + .HasColumnType("bit"); + + b.Property("City") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompanyRole") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("DashboardLayout") + .HasColumnType("int"); + + b.Property("DateFormat") + .HasColumnType("nvarchar(max)"); + + b.Property("Department") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("EmployeeNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("HireDate") + .HasColumnType("datetime2"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsBanned") + .HasColumnType("bit"); + + b.Property("LastLoginDate") + .HasColumnType("datetime2"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PasskeyPromptDismissed") + .HasColumnType("bit"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("Position") + .HasColumnType("nvarchar(max)"); + + b.Property("ProfilePictureFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("SidebarColor") + .HasColumnType("nvarchar(max)"); + + b.Property("State") + .HasColumnType("nvarchar(max)"); + + b.Property("TerminationDate") + .HasColumnType("datetime2"); + + b.Property("Theme") + .HasColumnType("nvarchar(max)"); + + b.Property("TimeZone") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ZipCode") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Appointment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActualEndTime") + .HasColumnType("datetime2"); + + b.Property("ActualStartTime") + .HasColumnType("datetime2"); + + b.Property("AppointmentNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("AppointmentStatusId") + .HasColumnType("int"); + + b.Property("AppointmentTypeId") + .HasColumnType("int"); + + b.Property("AssignedUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsAllDay") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsReminderEnabled") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Location") + .HasColumnType("nvarchar(max)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("ReminderMinutesBefore") + .HasColumnType("int"); + + b.Property("ScheduledEndTime") + .HasColumnType("datetime2"); + + b.Property("ScheduledStartTime") + .HasColumnType("datetime2"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AppointmentStatusId"); + + b.HasIndex("AppointmentTypeId"); + + b.HasIndex("AssignedUserId"); + + b.HasIndex("CustomerId"); + + b.HasIndex("JobId"); + + b.HasIndex("ScheduledStartTime"); + + b.HasIndex("CompanyId", "AppointmentStatusId") + .HasDatabaseName("IX_Appointments_CompanyId_AppointmentStatusId"); + + b.HasIndex("CompanyId", "ScheduledStartTime") + .HasDatabaseName("IX_Appointments_CompanyId_ScheduledStartTime"); + + b.ToTable("Appointments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AppointmentStatusLookup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ColorClass") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IconClass") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsSystemDefined") + .HasColumnType("bit"); + + b.Property("IsTerminalStatus") + .HasColumnType("bit"); + + b.Property("StatusCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("AppointmentStatusLookups"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AppointmentTypeLookup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ColorClass") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IconClass") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsSystemDefined") + .HasColumnType("bit"); + + b.Property("RequiresJobLink") + .HasColumnType("bit"); + + b.Property("TypeCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("AppointmentTypeLookups"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompanyName") + .HasColumnType("nvarchar(max)"); + + b.Property("EntityDescription") + .HasColumnType("nvarchar(max)"); + + b.Property("EntityId") + .HasColumnType("nvarchar(450)"); + + b.Property("EntityType") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("IpAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("NewValues") + .HasColumnType("nvarchar(max)"); + + b.Property("OldValues") + .HasColumnType("nvarchar(max)"); + + b.Property("Timestamp") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("nvarchar(max)"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId", "Timestamp"); + + b.HasIndex("EntityType", "EntityId"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BankReconciliation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("BeginningBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompletedAt") + .HasColumnType("datetime2"); + + b.Property("CompletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EndingBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("StatementDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("BankReconciliations"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BannedIp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BannedAt") + .HasColumnType("datetime2"); + + b.Property("BannedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IpAddress") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Reason") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("BannedIps"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Bill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("APAccountId") + .HasColumnType("int"); + + b.Property("AmountPaid") + .HasColumnType("decimal(18,2)"); + + b.Property("BillDate") + .HasColumnType("datetime2"); + + b.Property("BillNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Memo") + .HasColumnType("nvarchar(max)"); + + b.Property("ReceiptFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("TaxAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TaxPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("Terms") + .HasColumnType("nvarchar(max)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.Property("VendorInvoiceNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("APAccountId"); + + b.HasIndex("DueDate"); + + b.HasIndex("Status"); + + b.HasIndex("VendorId"); + + b.HasIndex("CompanyId", "Status"); + + b.ToTable("Bills"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BillLineItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("BillId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("BillId"); + + b.HasIndex("JobId"); + + b.ToTable("BillLineItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BillPayment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("BankAccountId") + .HasColumnType("int"); + + b.Property("BillId") + .HasColumnType("int"); + + b.Property("CheckNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("ClearedDate") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsCleared") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Memo") + .HasColumnType("nvarchar(max)"); + + b.Property("PaymentDate") + .HasColumnType("datetime2"); + + b.Property("PaymentMethod") + .HasColumnType("int"); + + b.Property("PaymentNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BankAccountId"); + + b.HasIndex("BillId"); + + b.HasIndex("VendorId"); + + b.ToTable("BillPayments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Budget", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FiscalYear") + .HasColumnType("int"); + + b.Property("IsDefault") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Budgets"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BudgetLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("Apr") + .HasColumnType("decimal(18,2)"); + + b.Property("Aug") + .HasColumnType("decimal(18,2)"); + + b.Property("BudgetId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Dec") + .HasColumnType("decimal(18,2)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Feb") + .HasColumnType("decimal(18,2)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Jan") + .HasColumnType("decimal(18,2)"); + + b.Property("Jul") + .HasColumnType("decimal(18,2)"); + + b.Property("Jun") + .HasColumnType("decimal(18,2)"); + + b.Property("Mar") + .HasColumnType("decimal(18,2)"); + + b.Property("May") + .HasColumnType("decimal(18,2)"); + + b.Property("Nov") + .HasColumnType("decimal(18,2)"); + + b.Property("Oct") + .HasColumnType("decimal(18,2)"); + + b.Property("Sep") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("BudgetId"); + + b.ToTable("BudgetLines"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BugReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompanyName") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("ResolutionNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("ResolvedAt") + .HasColumnType("datetime2"); + + b.Property("ResolvedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SubmittedByUserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SubmittedByUserName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("BugReports"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BugReportAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlobPath") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("BugReportId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FileSizeBytes") + .HasColumnType("bigint"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("BugReportId"); + + b.ToTable("BugReportAttachments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CatalogCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsMerchandise") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ParentCategoryId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("ParentCategoryId"); + + b.ToTable("CatalogCategories"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CatalogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApproximateArea") + .HasColumnType("decimal(18,2)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("CogsAccountId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultEstimatedMinutes") + .HasColumnType("int"); + + b.Property("DefaultPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("DefaultRequiresMasking") + .HasColumnType("bit"); + + b.Property("DefaultRequiresSandblasting") + .HasColumnType("bit"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("ImagePath") + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryItemId") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsMerchandise") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RevenueAccountId") + .HasColumnType("int"); + + b.Property("SKU") + .HasColumnType("nvarchar(max)"); + + b.Property("ThumbnailPath") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("CogsAccountId"); + + b.HasIndex("CompanyId"); + + b.HasIndex("InventoryItemId"); + + b.HasIndex("RevenueAccountId"); + + b.ToTable("CatalogItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CatalogPriceCheckReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ItemsChecked") + .HasColumnType("int"); + + b.Property("OperatingCostsSummary") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ResultsJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RunAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("CatalogPriceCheckReports"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Company", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountingMethod") + .HasColumnType("int"); + + b.Property("AccountingOverride") + .HasColumnType("bit"); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("AiCatalogPriceCheckEnabled") + .HasColumnType("bit"); + + b.Property("AiInventoryAssistEnabled") + .HasColumnType("bit"); + + b.Property("AiPhotoQuotesEnabled") + .HasColumnType("bit"); + + b.Property("BookLockedThrough") + .HasColumnType("datetime2"); + + b.Property("City") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyCode") + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsAnnualBilling") + .HasColumnType("bit"); + + b.Property("IsComped") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LogoContentType") + .HasColumnType("nvarchar(max)"); + + b.Property("LogoData") + .HasColumnType("varbinary(max)"); + + b.Property("LogoFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("MarketingEmailOptOut") + .HasColumnType("bit"); + + b.Property("MarketingUnsubscribeToken") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaxActiveJobsOverride") + .HasColumnType("int"); + + b.Property("MaxAiPhotoQuotesPerMonthOverride") + .HasColumnType("int"); + + b.Property("MaxCatalogItemsOverride") + .HasColumnType("int"); + + b.Property("MaxCustomersOverride") + .HasColumnType("int"); + + b.Property("MaxJobPhotosOverride") + .HasColumnType("int"); + + b.Property("MaxQuotePhotosOverride") + .HasColumnType("int"); + + b.Property("MaxQuotesOverride") + .HasColumnType("int"); + + b.Property("MaxUsersOverride") + .HasColumnType("int"); + + b.Property("OnlinePaymentSurchargeType") + .HasColumnType("int"); + + b.Property("OnlinePaymentSurchargeValue") + .HasColumnType("decimal(18,2)"); + + b.Property("OnlinePaymentsOverride") + .HasColumnType("bit"); + + b.Property("OnlineSurchargeAcknowledged") + .HasColumnType("bit"); + + b.Property("Phone") + .HasColumnType("nvarchar(max)"); + + b.Property("PrimaryContactEmail") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PrimaryContactName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SmsDisabledByAdmin") + .HasColumnType("bit"); + + b.Property("SmsEnabled") + .HasColumnType("bit"); + + b.Property("State") + .HasColumnType("nvarchar(max)"); + + b.Property("StripeAccountId") + .HasColumnType("nvarchar(max)"); + + b.Property("StripeConnectStatus") + .HasColumnType("int"); + + b.Property("StripeCustomerId") + .HasColumnType("nvarchar(max)"); + + b.Property("StripeSubscriptionId") + .HasColumnType("nvarchar(max)"); + + b.Property("SubscriptionEndDate") + .HasColumnType("datetime2"); + + b.Property("SubscriptionNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("SubscriptionPlan") + .HasColumnType("int"); + + b.Property("SubscriptionStartDate") + .HasColumnType("datetime2"); + + b.Property("SubscriptionStatus") + .HasColumnType("int"); + + b.Property("TimeZone") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ZipCode") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyCode") + .IsUnique() + .HasFilter("[CompanyCode] IS NOT NULL"); + + b.ToTable("Companies"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CompanyBlastSetup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlastNozzleSize") + .HasColumnType("int"); + + b.Property("BlastRateSqFtPerHourOverride") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompressorCfm") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDefault") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("PrimarySubstrate") + .HasColumnType("int"); + + b.Property("SetupType") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.ToTable("CompanyBlastSetups"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CompanyOperatingCosts", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdditionalCoatLaborPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("AiContextProfile") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("BlastNozzleSize") + .HasColumnType("int"); + + b.Property("BlastRateSqFtPerHourOverride") + .HasColumnType("decimal(18,2)"); + + b.Property("BlastSetupType") + .HasColumnType("int"); + + b.Property("CoatingBoothCostPerHour") + .HasColumnType("decimal(18,2)"); + + b.Property("CoatingGunType") + .HasColumnType("int"); + + b.Property("CoatingRateSqFtPerHourOverride") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ComplexityComplexPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("ComplexityExtremePercent") + .HasColumnType("decimal(18,2)"); + + b.Property("ComplexityModeratePercent") + .HasColumnType("decimal(18,2)"); + + b.Property("ComplexitySimplePercent") + .HasColumnType("decimal(18,2)"); + + b.Property("CompressorCfm") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultOvenCycleMinutes") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("GeneralMarkupPercentage") + .HasColumnType("decimal(18,2)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("MonthlyBillableHours") + .HasColumnType("int"); + + b.Property("MonthlyRent") + .HasColumnType("decimal(18,2)"); + + b.Property("MonthlyUtilities") + .HasColumnType("decimal(18,2)"); + + b.Property("OvenOperatingCostPerHour") + .HasColumnType("decimal(18,2)"); + + b.Property("PowderCoatingCostPerSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("PricingMode") + .HasColumnType("int"); + + b.Property("PrimaryBlastSubstrate") + .HasColumnType("int"); + + b.Property("RushChargeFixedAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("RushChargePercentage") + .HasColumnType("decimal(18,2)"); + + b.Property("RushChargeType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SandblasterCostPerHour") + .HasColumnType("decimal(18,2)"); + + b.Property("ShopCapabilityTier") + .HasColumnType("int"); + + b.Property("ShopMinimumCharge") + .HasColumnType("decimal(18,2)"); + + b.Property("ShopSuppliesRate") + .HasColumnType("decimal(18,2)"); + + b.Property("StandardLaborRate") + .HasColumnType("decimal(18,2)"); + + b.Property("TargetMarginPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("TaxPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId") + .IsUnique(); + + b.ToTable("CompanyOperatingCosts"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CompanyPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AllowCustomerApproval") + .HasColumnType("bit"); + + b.Property("AutoArchiveJobsDays") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultCurrency") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultDateFormat") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultJobPriority") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultPaymentTerms") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultQuoteValidityDays") + .HasColumnType("int"); + + b.Property("DefaultTimeFormat") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultTurnaroundDays") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedRecordRetentionDays") + .HasColumnType("int"); + + b.Property("DueDateWarningDays") + .HasColumnType("int"); + + b.Property("EmailFromAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("EmailFromName") + .HasColumnType("nvarchar(max)"); + + b.Property("EmailNotificationsEnabled") + .HasColumnType("bit"); + + b.Property("FirstInvoiceCreatedAt") + .HasColumnType("datetime2"); + + b.Property("FirstJobCreatedAt") + .HasColumnType("datetime2"); + + b.Property("FirstQuoteCreatedAt") + .HasColumnType("datetime2"); + + b.Property("FirstWorkflowCompleted") + .HasColumnType("bit"); + + b.Property("FirstWorkflowCompletedAt") + .HasColumnType("datetime2"); + + b.Property("GuidedActivationDismissedAt") + .HasColumnType("datetime2"); + + b.Property("InAccentColor") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("InDefaultTerms") + .HasColumnType("nvarchar(max)"); + + b.Property("InFooterNote") + .HasColumnType("nvarchar(max)"); + + b.Property("InvoiceNumberPrefix") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobNumberPrefix") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("JobRetentionYears") + .HasColumnType("int"); + + b.Property("LogRetentionDays") + .HasColumnType("int"); + + b.Property("MaintenanceAlertDays") + .HasColumnType("int"); + + b.Property("MigratingFromQuickBooks") + .HasColumnType("bit"); + + b.Property("NotifyOnJobStatusChange") + .HasColumnType("bit"); + + b.Property("NotifyOnNewJob") + .HasColumnType("bit"); + + b.Property("NotifyOnNewQuote") + .HasColumnType("bit"); + + b.Property("NotifyOnPaymentReceived") + .HasColumnType("bit"); + + b.Property("NotifyOnQuoteApproval") + .HasColumnType("bit"); + + b.Property("OnboardingPath") + .HasColumnType("nvarchar(max)"); + + b.Property("PaymentReminderDays") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PaymentRemindersEnabled") + .HasColumnType("bit"); + + b.Property("QbMigrationStateJson") + .HasColumnType("nvarchar(max)"); + + b.Property("QtAccentColor") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QtDefaultTerms") + .HasColumnType("nvarchar(max)"); + + b.Property("QtFooterNote") + .HasColumnType("nvarchar(max)"); + + b.Property("QuoteExpiryWarningDays") + .HasColumnType("int"); + + b.Property("QuoteNumberPrefix") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuoteRetentionYears") + .HasColumnType("int"); + + b.Property("RequireCustomerPO") + .HasColumnType("bit"); + + b.Property("SetupWizardCompleted") + .HasColumnType("bit"); + + b.Property("SetupWizardCompletedAt") + .HasColumnType("datetime2"); + + b.Property("SetupWizardCompletedByName") + .HasColumnType("nvarchar(max)"); + + b.Property("SetupWizardCompletedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("SetupWizardDoneSteps") + .HasColumnType("nvarchar(max)"); + + b.Property("SetupWizardSkippedSteps") + .HasColumnType("nvarchar(max)"); + + b.Property("SetupWizardStarted") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UseMetricSystem") + .HasColumnType("bit"); + + b.Property("WoAccentColor") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WoTerms") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId") + .IsUnique(); + + b.ToTable("CompanyPreferences"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CompanySmsAgreement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AgreedAt") + .HasColumnType("datetime2"); + + b.Property("AgreedByUserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("AgreedByUserName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IpAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("TermsVersion") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UserAgent") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("CompanySmsAgreements"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ContactSubmission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsRead") + .HasColumnType("bit"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReadAt") + .HasColumnType("datetime2"); + + b.Property("ReadByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ReadByUserName") + .HasColumnType("nvarchar(max)"); + + b.Property("SenderEmail") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SenderName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ContactSubmissions"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CreditMemo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("AmountApplied") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IssueDate") + .HasColumnType("datetime2"); + + b.Property("IssuedById") + .HasColumnType("nvarchar(450)"); + + b.Property("MemoNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalInvoiceId") + .HasColumnType("int"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReworkRecordId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("IssuedById"); + + b.HasIndex("OriginalInvoiceId"); + + b.HasIndex("ReworkRecordId"); + + b.HasIndex("CompanyId", "MemoNumber") + .IsUnique() + .HasDatabaseName("IX_CreditMemos_CompanyId_MemoNumber"); + + b.ToTable("CreditMemos"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CreditMemoApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AmountApplied") + .HasColumnType("decimal(18,2)"); + + b.Property("AppliedById") + .HasColumnType("nvarchar(450)"); + + b.Property("AppliedDate") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreditMemoId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("InvoiceId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AppliedById"); + + b.HasIndex("CreditMemoId"); + + b.HasIndex("InvoiceId"); + + b.ToTable("CreditMemoApplications"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("BillingEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("City") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompanyName") + .HasColumnType("nvarchar(450)"); + + b.Property("ContactFirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("ContactLastName") + .HasColumnType("nvarchar(max)"); + + b.Property("Country") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreditBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("CreditLimit") + .HasColumnType("decimal(18,2)"); + + b.Property("CurrentBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(450)"); + + b.Property("GeneralNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsCommercial") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsTaxExempt") + .HasColumnType("bit"); + + b.Property("LastContactDate") + .HasColumnType("datetime2"); + + b.Property("MobilePhone") + .HasColumnType("nvarchar(max)"); + + b.Property("NotifyByEmail") + .HasColumnType("bit"); + + b.Property("NotifyBySms") + .HasColumnType("bit"); + + b.Property("PaymentTerms") + .HasColumnType("nvarchar(max)"); + + b.Property("Phone") + .HasColumnType("nvarchar(max)"); + + b.Property("PricingTierId") + .HasColumnType("int"); + + b.Property("SmsConsentMethod") + .HasColumnType("nvarchar(max)"); + + b.Property("SmsConsentedAt") + .HasColumnType("datetime2"); + + b.Property("SmsOptedOutAt") + .HasColumnType("datetime2"); + + b.Property("State") + .HasColumnType("nvarchar(max)"); + + b.Property("TaxExemptCertificateContentType") + .HasColumnType("nvarchar(max)"); + + b.Property("TaxExemptCertificateData") + .HasColumnType("varbinary(max)"); + + b.Property("TaxExemptCertificateFileName") + .HasColumnType("nvarchar(max)"); + + b.Property("TaxId") + .HasColumnType("nvarchar(max)"); + + b.Property("UnsubscribeToken") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)") + .HasDefaultValueSql("REPLACE(NEWID(),'-','')"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ZipCode") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CompanyName"); + + b.HasIndex("PricingTierId"); + + b.HasIndex("UnsubscribeToken") + .IsUnique() + .HasDatabaseName("IX_Customers_UnsubscribeToken"); + + b.HasIndex("CompanyId", "Email") + .IsUnique() + .HasFilter("[Email] IS NOT NULL"); + + b.ToTable("Customers"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CustomerNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsImportant") + .HasColumnType("bit"); + + b.Property("Note") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId", "CreatedAt") + .HasDatabaseName("IX_CustomerNotes_CustomerId_CreatedAt"); + + b.ToTable("CustomerNotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.DashboardTip", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("TipText") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("DashboardTips"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Deposit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("AppliedDate") + .HasColumnType("datetime2"); + + b.Property("AppliedToInvoiceId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PaymentMethod") + .HasColumnType("int"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("ReceiptNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReceivedDate") + .HasColumnType("datetime2"); + + b.Property("RecordedById") + .HasColumnType("nvarchar(450)"); + + b.Property("Reference") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AppliedToInvoiceId"); + + b.HasIndex("CustomerId"); + + b.HasIndex("JobId"); + + b.HasIndex("QuoteId"); + + b.HasIndex("RecordedById"); + + b.ToTable("Deposits"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Equipment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LastMaintenanceDate") + .HasColumnType("datetime2"); + + b.Property("Location") + .HasColumnType("nvarchar(max)"); + + b.Property("ManualContentType") + .HasColumnType("nvarchar(max)"); + + b.Property("ManualFileName") + .HasColumnType("nvarchar(max)"); + + b.Property("ManualFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("ManualFileSize") + .HasColumnType("bigint"); + + b.Property("ManualUploadedDate") + .HasColumnType("datetime2"); + + b.Property("Manufacturer") + .HasColumnType("nvarchar(max)"); + + b.Property("MaxLoadSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("Model") + .HasColumnType("nvarchar(max)"); + + b.Property("NextScheduledMaintenance") + .HasColumnType("datetime2"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OvenCycleMinutes") + .HasColumnType("int"); + + b.Property("PurchaseDate") + .HasColumnType("datetime2"); + + b.Property("PurchasePrice") + .HasColumnType("decimal(18,2)"); + + b.Property("RecommendedMaintenanceIntervalDays") + .HasColumnType("int"); + + b.Property("SerialNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("WarrantyExpiration") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CompanyId", "Status") + .HasDatabaseName("IX_Equipment_CompanyId_Status"); + + b.ToTable("Equipment"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Expense", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("ClearedDate") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ExpenseAccountId") + .HasColumnType("int"); + + b.Property("ExpenseNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsCleared") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Memo") + .HasColumnType("nvarchar(max)"); + + b.Property("PaymentAccountId") + .HasColumnType("int"); + + b.Property("PaymentMethod") + .HasColumnType("int"); + + b.Property("ReceiptFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ExpenseAccountId"); + + b.HasIndex("JobId"); + + b.HasIndex("PaymentAccountId"); + + b.HasIndex("VendorId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.FixedAsset", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccumDepreciationAccountId") + .HasColumnType("int"); + + b.Property("AccumulatedDepreciation") + .HasColumnType("decimal(18,2)"); + + b.Property("AssetAccountId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DepreciationExpenseAccountId") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisposalDate") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsDisposed") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PurchaseCost") + .HasColumnType("decimal(18,2)"); + + b.Property("PurchaseDate") + .HasColumnType("datetime2"); + + b.Property("SalvageValue") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UsefulLifeMonths") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccumDepreciationAccountId"); + + b.HasIndex("AssetAccountId"); + + b.HasIndex("DepreciationExpenseAccountId"); + + b.ToTable("FixedAssets"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.FixedAssetDepreciationEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FixedAssetId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JournalEntryId") + .HasColumnType("int"); + + b.Property("PeriodMonth") + .HasColumnType("int"); + + b.Property("PeriodYear") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("FixedAssetId"); + + b.HasIndex("JournalEntryId"); + + b.ToTable("FixedAssetDepreciationEntries"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.GiftCertificate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CertificateCode") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IssueDate") + .HasColumnType("datetime2"); + + b.Property("IssuedById") + .HasColumnType("nvarchar(450)"); + + b.Property("IssuedReason") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("PurchasePrice") + .HasColumnType("decimal(18,2)"); + + b.Property("PurchasingCustomerId") + .HasColumnType("int"); + + b.Property("RecipientCustomerId") + .HasColumnType("int"); + + b.Property("RecipientEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("RecipientName") + .HasColumnType("nvarchar(max)"); + + b.Property("RedeemedAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("SourceInvoiceItemId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssuedById"); + + b.HasIndex("PurchasingCustomerId"); + + b.HasIndex("RecipientCustomerId"); + + b.HasIndex("CompanyId", "CertificateCode") + .IsUnique(); + + b.ToTable("GiftCertificates"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.GiftCertificateRedemption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AmountRedeemed") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("GiftCertificateId") + .HasColumnType("int"); + + b.Property("InvoiceId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("RedeemedById") + .HasColumnType("nvarchar(450)"); + + b.Property("RedeemedDate") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("GiftCertificateId"); + + b.HasIndex("InvoiceId"); + + b.HasIndex("RedeemedById"); + + b.ToTable("GiftCertificateRedemptions"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InAppNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("InvoiceId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsRead") + .HasColumnType("bit"); + + b.Property("Link") + .HasColumnType("nvarchar(max)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("NotificationType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("ReadAt") + .HasColumnType("datetime2"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("InvoiceId"); + + b.HasIndex("QuoteId"); + + b.ToTable("InAppNotifications"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryCategoryLookup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CategoryCode") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsCoating") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsSystemDefined") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CompanyId", "CategoryCode") + .IsUnique(); + + b.ToTable("InventoryCategoryLookups"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AverageCost") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CogsAccountId") + .HasColumnType("int"); + + b.Property("ColorCode") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorFamilies") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorName") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CoverageSqFtPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CureTemperatureF") + .HasColumnType("decimal(18,2)"); + + b.Property("CureTimeMinutes") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DiscontinuedDate") + .HasColumnType("datetime2"); + + b.Property("Finish") + .HasColumnType("nvarchar(max)"); + + b.Property("HasSamplePanel") + .HasColumnType("bit"); + + b.Property("ImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryAccountId") + .HasColumnType("int"); + + b.Property("InventoryCategoryId") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsIncoming") + .HasColumnType("bit"); + + b.Property("LastPurchaseDate") + .HasColumnType("datetime2"); + + b.Property("LastPurchasePrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Location") + .HasColumnType("nvarchar(max)"); + + b.Property("Manufacturer") + .HasColumnType("nvarchar(max)"); + + b.Property("ManufacturerPartNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("MaximumStock") + .HasColumnType("decimal(18,2)"); + + b.Property("MinimumStock") + .HasColumnType("decimal(18,2)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrimaryVendorId") + .HasColumnType("int"); + + b.Property("QuantityOnHand") + .HasColumnType("decimal(18,2)"); + + b.Property("ReorderPoint") + .HasColumnType("decimal(18,2)"); + + b.Property("ReorderQuantity") + .HasColumnType("decimal(18,2)"); + + b.Property("RequiresClearCoat") + .HasColumnType("bit"); + + b.Property("SKU") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SdsUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("SpecPageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("SpecificGravity") + .HasColumnType("decimal(18,2)"); + + b.Property("TdsUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("TransferEfficiency") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitCost") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitOfMeasure") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorPartNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CogsAccountId"); + + b.HasIndex("CompanyId"); + + b.HasIndex("InventoryAccountId"); + + b.HasIndex("InventoryCategoryId"); + + b.HasIndex("IsActive"); + + b.HasIndex("PrimaryVendorId"); + + b.HasIndex("CompanyId", "IsActive"); + + b.HasIndex("CompanyId", "SKU") + .IsUnique() + .HasDatabaseName("IX_InventoryItems_CompanyId_SKU"); + + b.HasIndex("CompanyId", "QuantityOnHand", "ReorderPoint") + .HasDatabaseName("IX_InventoryItems_CompanyId_Quantity_Reorder"); + + b.ToTable("InventoryItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BalanceAfter") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryItemId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PurchaseOrderId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Reference") + .HasColumnType("nvarchar(max)"); + + b.Property("TotalCost") + .HasColumnType("decimal(18,2)"); + + b.Property("TransactionDate") + .HasColumnType("datetime2"); + + b.Property("TransactionType") + .HasColumnType("int"); + + b.Property("UnitCost") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("InventoryItemId"); + + b.HasIndex("JobId"); + + b.HasIndex("PurchaseOrderId"); + + b.HasIndex("TransactionType", "TransactionDate"); + + b.ToTable("InventoryTransactions"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Invoice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AmountPaid") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreditApplied") + .HasColumnType("decimal(18,2)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("CustomerPO") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DiscountAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EarlyPaymentDiscountDays") + .HasColumnType("int"); + + b.Property("EarlyPaymentDiscountPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("ExternalReference") + .HasColumnType("nvarchar(450)"); + + b.Property("GiftCertificateRedeemed") + .HasColumnType("decimal(18,2)"); + + b.Property("InternalNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("InvoiceDate") + .HasColumnType("datetime2"); + + b.Property("InvoiceNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OnlineAmountPaid") + .HasColumnType("decimal(18,2)"); + + b.Property("OnlinePaymentStatus") + .HasColumnType("int"); + + b.Property("OnlineSurchargeCollected") + .HasColumnType("decimal(18,2)"); + + b.Property("PaidDate") + .HasColumnType("datetime2"); + + b.Property("PaymentLinkExpiresAt") + .HasColumnType("datetime2"); + + b.Property("PaymentLinkToken") + .HasColumnType("nvarchar(max)"); + + b.Property("PreparedById") + .HasColumnType("nvarchar(450)"); + + b.Property("SalesTaxAccountId") + .HasColumnType("int"); + + b.Property("SentDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("StripePaymentIntentId") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("TaxAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TaxPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("Terms") + .HasColumnType("nvarchar(max)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("DueDate"); + + b.HasIndex("InvoiceDate"); + + b.HasIndex("JobId") + .IsUnique() + .HasFilter("[JobId] IS NOT NULL"); + + b.HasIndex("PreparedById"); + + b.HasIndex("SalesTaxAccountId"); + + b.HasIndex("Status"); + + b.HasIndex("CompanyId", "CustomerId") + .HasDatabaseName("IX_Invoices_CompanyId_CustomerId"); + + b.HasIndex("CompanyId", "DueDate") + .HasDatabaseName("IX_Invoices_CompanyId_DueDate"); + + b.HasIndex("CompanyId", "ExternalReference") + .HasDatabaseName("IX_Invoices_CompanyId_ExternalReference"); + + b.HasIndex("CompanyId", "InvoiceNumber") + .IsUnique() + .HasDatabaseName("IX_Invoices_CompanyId_InvoiceNumber"); + + b.HasIndex("CompanyId", "IsDeleted"); + + b.HasIndex("CompanyId", "JobId") + .IsUnique() + .HasDatabaseName("IX_Invoices_CompanyId_JobId") + .HasFilter("[JobId] IS NOT NULL"); + + b.HasIndex("CompanyId", "Status") + .HasDatabaseName("IX_Invoices_CompanyId_Status"); + + b.ToTable("Invoices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InvoiceItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CatalogItemId") + .HasColumnType("int"); + + b.Property("ColorName") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("GcExpiryDate") + .HasColumnType("datetime2"); + + b.Property("GcRecipientEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("GcRecipientName") + .HasColumnType("nvarchar(max)"); + + b.Property("GeneratedGiftCertificateId") + .HasColumnType("int"); + + b.Property("InvoiceId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsGiftCertificate") + .HasColumnType("bit"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("RevenueAccountId") + .HasColumnType("int"); + + b.Property("SourceJobItemId") + .HasColumnType("int"); + + b.Property("TotalPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CatalogItemId"); + + b.HasIndex("CompanyId"); + + b.HasIndex("GeneratedGiftCertificateId"); + + b.HasIndex("InvoiceId") + .HasDatabaseName("IX_InvoiceItems_InvoiceId"); + + b.HasIndex("RevenueAccountId"); + + b.HasIndex("SourceJobItemId"); + + b.ToTable("InvoiceItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActualTimeSpentHours") + .HasColumnType("decimal(18,2)"); + + b.Property("AssignedUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompletedDate") + .HasColumnType("datetime2"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("CustomerPO") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DiscountReason") + .HasColumnType("nvarchar(max)"); + + b.Property("DiscountType") + .HasColumnType("int"); + + b.Property("DiscountValue") + .HasColumnType("decimal(18,2)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("FinalPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("IntakeCheckedByUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("IntakeConditionNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("IntakeDate") + .HasColumnType("datetime2"); + + b.Property("IntakePartCount") + .HasColumnType("int"); + + b.Property("InternalNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("IsCustomerApproved") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsReworkJob") + .HasColumnType("bit"); + + b.Property("IsRushJob") + .HasColumnType("bit"); + + b.Property("JobNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("JobPriorityId") + .HasColumnType("int"); + + b.Property("JobStatusId") + .HasColumnType("int"); + + b.Property("OriginalJobId") + .HasColumnType("int"); + + b.Property("OvenCostId") + .HasColumnType("int"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("QuoteSnapshotUpdatedAt") + .HasColumnType("datetime2"); + + b.Property("QuotedPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("RequiresCustomerApproval") + .HasColumnType("bit"); + + b.Property("ScheduledDate") + .HasColumnType("datetime2"); + + b.Property("ShopAccessCode") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier") + .HasDefaultValueSql("NEWID()"); + + b.Property("ShopSuppliesAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("ShopSuppliesPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("ShopWorkerId") + .HasColumnType("int"); + + b.Property("SpecialInstructions") + .HasColumnType("nvarchar(max)"); + + b.Property("StartedDate") + .HasColumnType("datetime2"); + + b.Property("Tags") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AssignedUserId"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CustomerId"); + + b.HasIndex("DueDate"); + + b.HasIndex("IntakeCheckedByUserId"); + + b.HasIndex("JobPriorityId"); + + b.HasIndex("JobStatusId"); + + b.HasIndex("OriginalJobId"); + + b.HasIndex("OvenCostId"); + + b.HasIndex("QuoteId") + .IsUnique() + .HasFilter("[QuoteId] IS NOT NULL"); + + b.HasIndex("ScheduledDate"); + + b.HasIndex("ShopWorkerId"); + + b.HasIndex("CompanyId", "CustomerId") + .HasDatabaseName("IX_Jobs_CompanyId_CustomerId"); + + b.HasIndex("CompanyId", "DueDate") + .HasDatabaseName("IX_Jobs_CompanyId_DueDate"); + + b.HasIndex("CompanyId", "IsDeleted"); + + b.HasIndex("CompanyId", "JobNumber") + .IsUnique() + .HasDatabaseName("IX_Jobs_CompanyId_JobNumber"); + + b.HasIndex("CompanyId", "JobPriorityId") + .HasDatabaseName("IX_Jobs_CompanyId_JobPriorityId"); + + b.HasIndex("CompanyId", "JobStatusId") + .HasDatabaseName("IX_Jobs_CompanyId_JobStatusId"); + + b.HasIndex("CompanyId", "ScheduledDate") + .HasDatabaseName("IX_Jobs_CompanyId_ScheduledDate"); + + b.HasIndex("CompanyId", "ShopAccessCode") + .IsUnique() + .HasDatabaseName("IX_Jobs_CompanyId_ShopAccessCode"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobChangeHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChangeDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ChangedAt") + .HasColumnType("datetime2"); + + b.Property("ChangedByUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FieldName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("NewValue") + .HasColumnType("nvarchar(max)"); + + b.Property("OldValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ChangedByUserId"); + + b.HasIndex("CompanyId"); + + b.HasIndex("JobId"); + + b.ToTable("JobChangeHistories"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobDailyPriority", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("ScheduledDate") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.ToTable("JobDailyPriorities"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AiPredictionId") + .HasColumnType("int"); + + b.Property("AiTags") + .HasColumnType("nvarchar(max)"); + + b.Property("CatalogItemId") + .HasColumnType("int"); + + b.Property("ColorCode") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorName") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("Complexity") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EstimatedMinutes") + .HasColumnType("int"); + + b.Property("Finish") + .HasColumnType("nvarchar(max)"); + + b.Property("IncludePrepCost") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsGenericItem") + .HasColumnType("bit"); + + b.Property("IsLaborItem") + .HasColumnType("bit"); + + b.Property("IsSalesItem") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("LaborCost") + .HasColumnType("decimal(18,2)"); + + b.Property("ManualUnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PowderCostOverride") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("RequiresMasking") + .HasColumnType("bit"); + + b.Property("RequiresSandblasting") + .HasColumnType("bit"); + + b.Property("Sku") + .HasColumnType("nvarchar(max)"); + + b.Property("SurfaceArea") + .HasColumnType("decimal(18,2)"); + + b.Property("SurfaceAreaSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AiPredictionId"); + + b.HasIndex("CatalogItemId"); + + b.HasIndex("JobId") + .HasDatabaseName("IX_JobItems_JobId"); + + b.HasIndex("JobId", "IsDeleted") + .HasDatabaseName("IX_JobItems_JobId_IsDeleted"); + + b.ToTable("JobItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobItemCoat", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActualPowderUsedLbs") + .HasColumnType("decimal(18,2)"); + + b.Property("CoatName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ColorCode") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorName") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CoverageSqFtPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Finish") + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryItemId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobItemId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PowderCostPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("PowderOrdered") + .HasColumnType("bit"); + + b.Property("PowderOrderedAt") + .HasColumnType("datetime2"); + + b.Property("PowderOrderedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("PowderReceived") + .HasColumnType("bit"); + + b.Property("PowderReceivedAt") + .HasColumnType("datetime2"); + + b.Property("PowderReceivedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("PowderReceivedLbs") + .HasColumnType("decimal(18,2)"); + + b.Property("PowderToOrder") + .HasColumnType("decimal(18,2)"); + + b.Property("Sequence") + .HasColumnType("int"); + + b.Property("TransferEfficiency") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InventoryItemId"); + + b.HasIndex("JobItemId"); + + b.HasIndex("VendorId"); + + b.ToTable("JobItemCoats"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobItemPrepService", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlastSetupId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EstimatedMinutes") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobItemId") + .HasColumnType("int"); + + b.Property("PrepServiceId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("BlastSetupId"); + + b.HasIndex("CompanyId") + .HasDatabaseName("IX_JobItemPrepServices_CompanyId"); + + b.HasIndex("JobItemId") + .HasDatabaseName("IX_JobItemPrepServices_JobItemId"); + + b.HasIndex("PrepServiceId") + .HasDatabaseName("IX_JobItemPrepServices_PrepServiceId"); + + b.ToTable("JobItemPrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsImportant") + .HasColumnType("bit"); + + b.Property("IsInternal") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Note") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JobId", "CreatedAt") + .HasDatabaseName("IX_JobNotes_JobId_CreatedAt"); + + b.ToTable("JobNotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobPhoto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Caption") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FilePath") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsAiAnalysisPhoto") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("PhotoType") + .HasColumnType("int"); + + b.Property("Tags") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UploadedById") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("UploadedDate") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("UploadedById"); + + b.HasIndex("JobId", "IsDeleted", "DisplayOrder") + .HasDatabaseName("IX_JobPhotos_JobId_IsDeleted_DisplayOrder"); + + b.ToTable("JobPhotos"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobPrepService", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("PrepServiceId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.HasIndex("PrepServiceId"); + + b.ToTable("JobPrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobPriorityLookup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ColorClass") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IconClass") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsSystemDefined") + .HasColumnType("bit"); + + b.Property("PriorityCode") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CompanyId", "PriorityCode") + .IsUnique(); + + b.ToTable("JobPriorityLookups"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobStatusHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChangedDate") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FromStatusId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("ToStatusId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("FromStatusId"); + + b.HasIndex("JobId"); + + b.HasIndex("ToStatusId"); + + b.ToTable("JobStatusHistory"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobStatusLookup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ColorClass") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IconClass") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsSystemDefined") + .HasColumnType("bit"); + + b.Property("IsTerminalStatus") + .HasColumnType("bit"); + + b.Property("IsWorkInProgressStatus") + .HasColumnType("bit"); + + b.Property("StatusCode") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("WorkflowCategory") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CompanyId", "StatusCode") + .IsUnique(); + + b.ToTable("JobStatusLookups"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SpecialInstructions") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UsageCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.ToTable("JobTemplates"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplateItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CatalogItemId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("Complexity") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("EstimatedMinutes") + .HasColumnType("int"); + + b.Property("IncludePrepCost") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsGenericItem") + .HasColumnType("bit"); + + b.Property("IsLaborItem") + .HasColumnType("bit"); + + b.Property("IsSalesItem") + .HasColumnType("bit"); + + b.Property("JobTemplateId") + .HasColumnType("int"); + + b.Property("ManualUnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("RequiresMasking") + .HasColumnType("bit"); + + b.Property("RequiresSandblasting") + .HasColumnType("bit"); + + b.Property("Sku") + .HasColumnType("nvarchar(max)"); + + b.Property("SurfaceAreaSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CatalogItemId"); + + b.HasIndex("JobTemplateId"); + + b.ToTable("JobTemplateItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplateItemCoat", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoatName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ColorCode") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorName") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CoverageSqFtPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Finish") + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryItemId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobTemplateItemId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PowderCostPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("Sequence") + .HasColumnType("int"); + + b.Property("TransferEfficiency") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InventoryItemId"); + + b.HasIndex("JobTemplateItemId"); + + b.HasIndex("VendorId"); + + b.ToTable("JobTemplateItemCoats"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplateItemPrepService", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EstimatedMinutes") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobTemplateItemId") + .HasColumnType("int"); + + b.Property("PrepServiceId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JobTemplateItemId"); + + b.HasIndex("PrepServiceId"); + + b.ToTable("JobTemplateItemPrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTimeEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("HoursWorked") + .HasColumnType("decimal(18,2)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("ShopWorkerId") + .HasColumnType("int"); + + b.Property("Stage") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UserDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("nvarchar(max)"); + + b.Property("WorkDate") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.HasIndex("ShopWorkerId"); + + b.ToTable("JobTimeEntries"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JournalEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("EntryDate") + .HasColumnType("datetime2"); + + b.Property("EntryNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsReversal") + .HasColumnType("bit"); + + b.Property("PostedAt") + .HasColumnType("datetime2"); + + b.Property("PostedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Reference") + .HasColumnType("nvarchar(max)"); + + b.Property("ReversalOfId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ReversalOfId"); + + b.ToTable("JournalEntries"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JournalEntryLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreditAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("DebitAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JournalEntryId") + .HasColumnType("int"); + + b.Property("LineOrder") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("JournalEntryId"); + + b.ToTable("JournalEntryLines"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.MaintenanceRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AssignedUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompletedDate") + .HasColumnType("datetime2"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DowntimeHours") + .HasColumnType("decimal(18,2)"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsRecurring") + .HasColumnType("bit"); + + b.Property("LaborCost") + .HasColumnType("decimal(18,2)"); + + b.Property("MaintenanceType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PartsCost") + .HasColumnType("decimal(18,2)"); + + b.Property("PartsReplaced") + .HasColumnType("nvarchar(max)"); + + b.Property("PerformedById") + .HasColumnType("nvarchar(450)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("RecurrenceEndDate") + .HasColumnType("datetime2"); + + b.Property("RecurrenceFrequency") + .HasColumnType("int"); + + b.Property("RecurrenceGroupId") + .HasColumnType("nvarchar(max)"); + + b.Property("RecurrenceParentId") + .HasColumnType("int"); + + b.Property("ScheduledDate") + .HasColumnType("datetime2"); + + b.Property("ShopWorkerId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TechnicianNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("TotalCost") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("WorkPerformed") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AssignedUserId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("PerformedById"); + + b.HasIndex("RecurrenceParentId"); + + b.HasIndex("ScheduledDate"); + + b.HasIndex("ShopWorkerId"); + + b.HasIndex("Status"); + + b.HasIndex("CompanyId", "ScheduledDate") + .HasDatabaseName("IX_MaintenanceRecords_CompanyId_ScheduledDate"); + + b.HasIndex("CompanyId", "Status") + .HasDatabaseName("IX_MaintenanceRecords_CompanyId_Status"); + + b.ToTable("MaintenanceRecords"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ManufacturerLookupPattern", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Domain") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ManufacturerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("ProductUrlTemplate") + .HasColumnType("nvarchar(max)"); + + b.Property("SlugTransform") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ManufacturerLookupPatterns"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.NotificationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Channel") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("InvoiceId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Message") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("NotificationType") + .HasColumnType("int"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RecipientName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SentAt") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("InvoiceId"); + + b.HasIndex("JobId"); + + b.HasIndex("QuoteId"); + + b.HasIndex("CompanyId", "SentAt") + .HasDatabaseName("IX_NotificationLogs_CompanyId_SentAt"); + + b.HasIndex("CompanyId", "Status") + .HasDatabaseName("IX_NotificationLogs_CompanyId_Status"); + + b.ToTable("NotificationLogs"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.NotificationTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Body") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Channel") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("NotificationType") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId", "NotificationType", "Channel") + .IsUnique() + .HasDatabaseName("IX_NotificationTemplates_Company_Type_Channel"); + + b.ToTable("NotificationTemplates"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenBatch", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActualEndTime") + .HasColumnType("datetime2"); + + b.Property("ActualStartTime") + .HasColumnType("datetime2"); + + b.Property("AiReasoningJson") + .HasColumnType("nvarchar(max)"); + + b.Property("AiSuggested") + .HasColumnType("bit"); + + b.Property("BatchNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CureTemperatureF") + .HasColumnType("decimal(18,2)"); + + b.Property("CycleMinutes") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("EstimatedEndTime") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OvenCostId") + .HasColumnType("int"); + + b.Property("PrimaryColorCode") + .HasColumnType("nvarchar(max)"); + + b.Property("PrimaryColorName") + .HasColumnType("nvarchar(max)"); + + b.Property("ScheduledDate") + .HasColumnType("datetime2"); + + b.Property("ScheduledStartTime") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TotalSurfaceAreaSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("OvenCostId"); + + b.HasIndex("ScheduledDate", "Status"); + + b.ToTable("OvenBatches"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenBatchItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoatPassNumber") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("JobItemCoatId") + .HasColumnType("int"); + + b.Property("JobItemId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OvenBatchId") + .HasColumnType("int"); + + b.Property("SortOrder") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SurfaceAreaContribution") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.HasIndex("JobItemCoatId"); + + b.HasIndex("JobItemId"); + + b.HasIndex("OvenBatchId"); + + b.ToTable("OvenBatchItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenCost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CostPerHour") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DefaultCycleMinutes") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MaxLoadSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.ToTable("OvenCosts"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("ClearedDate") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DepositAccountId") + .HasColumnType("int"); + + b.Property("InvoiceId") + .HasColumnType("int"); + + b.Property("IsCleared") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PaymentDate") + .HasColumnType("datetime2"); + + b.Property("PaymentMethod") + .HasColumnType("int"); + + b.Property("RecordedById") + .HasColumnType("nvarchar(450)"); + + b.Property("Reference") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("DepositAccountId"); + + b.HasIndex("InvoiceId") + .HasDatabaseName("IX_Payments_InvoiceId"); + + b.HasIndex("PaymentDate"); + + b.HasIndex("RecordedById"); + + b.HasIndex("CompanyId", "PaymentDate") + .HasDatabaseName("IX_Payments_CompanyId_PaymentDate"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PendingRegistrationSession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyPhone") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsAnnual") + .HasColumnType("bit"); + + b.Property("IsCompleted") + .HasColumnType("bit"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Plan") + .HasColumnType("int"); + + b.Property("Token") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("PendingRegistrationSessions"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PlatformSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("GroupName") + .HasColumnType("nvarchar(max)"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Label") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("PlatformSettings"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PowderCatalogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApplicationGuideUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorFamilies") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorName") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("CoverageSqFtPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CureTemperatureF") + .HasColumnType("decimal(18,2)"); + + b.Property("CureTimeMinutes") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Finish") + .HasColumnType("nvarchar(max)"); + + b.Property("ImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDiscontinued") + .HasColumnType("bit"); + + b.Property("IsUserContributed") + .HasColumnType("bit"); + + b.Property("LastSyncedAt") + .HasColumnType("datetime2"); + + b.Property("PriceTiersJson") + .HasColumnType("nvarchar(max)"); + + b.Property("ProductUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("RequiresClearCoat") + .HasColumnType("bit"); + + b.Property("SdsUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("Sku") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SpecificGravity") + .HasColumnType("decimal(18,2)"); + + b.Property("TdsUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("TransferEfficiency") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("VendorName") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("ColorName") + .HasDatabaseName("IX_PowderCatalogItems_ColorName"); + + b.HasIndex("VendorName", "Sku") + .IsUnique() + .HasDatabaseName("IX_PowderCatalogItems_Vendor_Sku"); + + b.ToTable("PowderCatalogItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PowderUsageLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActualLbsUsed") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EstimatedLbs") + .HasColumnType("decimal(18,2)"); + + b.Property("InventoryItemId") + .HasColumnType("int"); + + b.Property("InventoryTransactionId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("JobItemCoatId") + .HasColumnType("int"); + + b.Property("JobItemId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("RecordedAt") + .HasColumnType("datetime2"); + + b.Property("RecordedByUserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VarianceLbs") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("InventoryItemId"); + + b.HasIndex("InventoryTransactionId"); + + b.HasIndex("JobId"); + + b.HasIndex("JobItemCoatId"); + + b.HasIndex("JobItemId"); + + b.ToTable("PowderUsageLogs"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PrepService", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("RequiresBlastSetup") + .HasColumnType("bit"); + + b.Property("ServiceName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("PrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PricingTier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DiscountPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("TierName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.ToTable("PricingTiers"); + + b.HasData( + new + { + Id = 1, + CompanyId = 0, + CreatedAt = new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(966), + Description = "Standard pricing for regular customers", + DiscountPercent = 0m, + IsActive = true, + IsDeleted = false, + TierName = "Standard" + }, + new + { + Id = 2, + CompanyId = 0, + CreatedAt = new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(974), + Description = "5% discount for preferred customers", + DiscountPercent = 5m, + IsActive = true, + IsDeleted = false, + TierName = "Preferred" + }, + new + { + Id = 3, + CompanyId = 0, + CreatedAt = new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(976), + Description = "10% discount for premium customers", + DiscountPercent = 10m, + IsActive = true, + IsDeleted = false, + TierName = "Premium" + }); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PurchaseOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BillId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ExpectedDeliveryDate") + .HasColumnType("datetime2"); + + b.Property("InternalNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderDate") + .HasColumnType("datetime2"); + + b.Property("PoNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReceivedDate") + .HasColumnType("datetime2"); + + b.Property("ShippingCost") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BillId"); + + b.HasIndex("VendorId"); + + b.ToTable("PurchaseOrders"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PurchaseOrderItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryItemId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LineTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PurchaseOrderId") + .HasColumnType("int"); + + b.Property("QuantityOrdered") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityReceived") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitCost") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitOfMeasure") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("InventoryItemId"); + + b.HasIndex("PurchaseOrderId"); + + b.ToTable("PurchaseOrderItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApprovalToken") + .HasColumnType("nvarchar(450)"); + + b.Property("ApprovalTokenExpiresAt") + .HasColumnType("datetime2"); + + b.Property("ApprovalTokenUsedAt") + .HasColumnType("datetime2"); + + b.Property("ApprovedDate") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ConvertedDate") + .HasColumnType("datetime2"); + + b.Property("ConvertedToJobId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("CustomerPO") + .HasColumnType("nvarchar(max)"); + + b.Property("DeclineReason") + .HasColumnType("nvarchar(max)"); + + b.Property("DeclinedByIp") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DepositAmountPaid") + .HasColumnType("decimal(18,2)"); + + b.Property("DepositPaymentIntentId") + .HasColumnType("nvarchar(max)"); + + b.Property("DepositPaymentLinkExpiresAt") + .HasColumnType("datetime2"); + + b.Property("DepositPaymentLinkToken") + .HasColumnType("nvarchar(max)"); + + b.Property("DepositPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DiscountAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("DiscountPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("DiscountReason") + .HasColumnType("nvarchar(max)"); + + b.Property("DiscountType") + .HasColumnType("int"); + + b.Property("DiscountValue") + .HasColumnType("decimal(18,2)"); + + b.Property("EquipmentCosts") + .HasColumnType("decimal(18,2)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime2"); + + b.Property("HideDiscountFromCustomer") + .HasColumnType("bit"); + + b.Property("IsCommercial") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsRushJob") + .HasColumnType("bit"); + + b.Property("ItemsSubtotal") + .HasColumnType("decimal(18,2)"); + + b.Property("LaborCosts") + .HasColumnType("decimal(18,2)"); + + b.Property("MaterialCosts") + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OvenBatchCost") + .HasColumnType("decimal(18,2)"); + + b.Property("OvenBatches") + .HasColumnType("int"); + + b.Property("OvenCostId") + .HasColumnType("int"); + + b.Property("OvenCycleMinutes") + .HasColumnType("int"); + + b.Property("OverheadAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("OverheadPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("PreparedById") + .HasColumnType("nvarchar(450)"); + + b.Property("ProfitMargin") + .HasColumnType("decimal(18,2)"); + + b.Property("ProfitPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("ProspectAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("ProspectCity") + .HasColumnType("nvarchar(max)"); + + b.Property("ProspectCompanyName") + .HasColumnType("nvarchar(max)"); + + b.Property("ProspectContactName") + .HasColumnType("nvarchar(max)"); + + b.Property("ProspectEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("ProspectPhone") + .HasColumnType("nvarchar(max)"); + + b.Property("ProspectSmsConsent") + .HasColumnType("bit"); + + b.Property("ProspectSmsConsentedAt") + .HasColumnType("datetime2"); + + b.Property("ProspectState") + .HasColumnType("nvarchar(max)"); + + b.Property("ProspectZipCode") + .HasColumnType("nvarchar(max)"); + + b.Property("QuoteDate") + .HasColumnType("datetime2"); + + b.Property("QuoteNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("QuoteStatusId") + .HasColumnType("int"); + + b.Property("RequiresDeposit") + .HasColumnType("bit"); + + b.Property("RushFee") + .HasColumnType("decimal(18,2)"); + + b.Property("SentDate") + .HasColumnType("datetime2"); + + b.Property("ShopSuppliesAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("ShopSuppliesPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Tags") + .HasColumnType("nvarchar(max)"); + + b.Property("TaxAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TaxPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("Terms") + .HasColumnType("nvarchar(max)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovalToken") + .IsUnique() + .HasDatabaseName("IX_Quotes_ApprovalToken") + .HasFilter("[ApprovalToken] IS NOT NULL"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CustomerId"); + + b.HasIndex("ExpirationDate"); + + b.HasIndex("OvenCostId"); + + b.HasIndex("PreparedById"); + + b.HasIndex("QuoteStatusId"); + + b.HasIndex("CompanyId", "ExpirationDate") + .HasDatabaseName("IX_Quotes_CompanyId_ExpirationDate"); + + b.HasIndex("CompanyId", "IsDeleted"); + + b.HasIndex("CompanyId", "QuoteNumber") + .IsUnique() + .HasDatabaseName("IX_Quotes_CompanyId_QuoteNumber"); + + b.HasIndex("CompanyId", "QuoteStatusId") + .HasDatabaseName("IX_Quotes_CompanyId_QuoteStatusId"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteChangeHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChangeDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ChangedAt") + .HasColumnType("datetime2"); + + b.Property("ChangedByUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FieldName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("NewValue") + .HasColumnType("nvarchar(max)"); + + b.Property("OldValue") + .HasColumnType("nvarchar(max)"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ChangedByUserId"); + + b.HasIndex("CompanyId"); + + b.HasIndex("QuoteId"); + + b.ToTable("QuoteChangeHistories"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AiPredictionId") + .HasColumnType("int"); + + b.Property("AiTags") + .HasColumnType("nvarchar(max)"); + + b.Property("CatalogItemId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("Complexity") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EstimatedMinutes") + .HasColumnType("int"); + + b.Property("IncludePrepCost") + .HasColumnType("bit"); + + b.Property("IsAiItem") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsGenericItem") + .HasColumnType("bit"); + + b.Property("IsLaborItem") + .HasColumnType("bit"); + + b.Property("IsSalesItem") + .HasColumnType("bit"); + + b.Property("ItemEquipmentCost") + .HasColumnType("decimal(18,2)"); + + b.Property("ItemLaborCost") + .HasColumnType("decimal(18,2)"); + + b.Property("ItemMaterialCost") + .HasColumnType("decimal(18,2)"); + + b.Property("ManualUnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PowderCostOverride") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("RequiresMasking") + .HasColumnType("bit"); + + b.Property("RequiresSandblasting") + .HasColumnType("bit"); + + b.Property("Sku") + .HasColumnType("nvarchar(max)"); + + b.Property("SurfaceArea") + .HasColumnType("decimal(18,2)"); + + b.Property("SurfaceAreaSqFt") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AiPredictionId"); + + b.HasIndex("CatalogItemId"); + + b.HasIndex("QuoteId") + .HasDatabaseName("IX_QuoteItems_QuoteId"); + + b.ToTable("QuoteItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteItemCoat", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoatLaborCost") + .HasColumnType("decimal(18,2)"); + + b.Property("CoatMaterialCost") + .HasColumnType("decimal(18,2)"); + + b.Property("CoatName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CoatTotalCost") + .HasColumnType("decimal(18,2)"); + + b.Property("ColorCode") + .HasColumnType("nvarchar(max)"); + + b.Property("ColorName") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CoverageSqFtPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Finish") + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryItemId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PowderCostPerLb") + .HasColumnType("decimal(18,2)"); + + b.Property("PowderToOrder") + .HasColumnType("decimal(18,2)"); + + b.Property("QuoteItemId") + .HasColumnType("int"); + + b.Property("Sequence") + .HasColumnType("int"); + + b.Property("TransferEfficiency") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId") + .HasDatabaseName("IX_QuoteItemCoats_CompanyId"); + + b.HasIndex("InventoryItemId") + .HasDatabaseName("IX_QuoteItemCoats_InventoryItemId"); + + b.HasIndex("QuoteItemId") + .HasDatabaseName("IX_QuoteItemCoats_QuoteItemId"); + + b.HasIndex("VendorId"); + + b.ToTable("QuoteItemCoats"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteItemPrepService", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlastSetupId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EstimatedMinutes") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("PrepServiceId") + .HasColumnType("int"); + + b.Property("QuoteItemId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("BlastSetupId"); + + b.HasIndex("CompanyId") + .HasDatabaseName("IX_QuoteItemPrepServices_CompanyId"); + + b.HasIndex("PrepServiceId") + .HasDatabaseName("IX_QuoteItemPrepServices_PrepServiceId"); + + b.HasIndex("QuoteItemId") + .HasDatabaseName("IX_QuoteItemPrepServices_QuoteItemId"); + + b.ToTable("QuoteItemPrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuotePhoto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Caption") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FilePath") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsAiAnalysisPhoto") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("TempId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("UploadedById") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("QuoteId"); + + b.HasIndex("UploadedById"); + + b.ToTable("QuotePhotos"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuotePrepService", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("PrepServiceId") + .HasColumnType("int"); + + b.Property("QuoteId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("PrepServiceId"); + + b.HasIndex("QuoteId"); + + b.ToTable("QuotePrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteStatusLookup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ColorClass") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("IconClass") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsApprovedStatus") + .HasColumnType("bit"); + + b.Property("IsConvertedStatus") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsDraftStatus") + .HasColumnType("bit"); + + b.Property("IsRejectedStatus") + .HasColumnType("bit"); + + b.Property("IsSystemDefined") + .HasColumnType("bit"); + + b.Property("StatusCode") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CompanyId", "StatusCode") + .IsUnique(); + + b.ToTable("QuoteStatusLookups"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.RecurringTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("Frequency") + .HasColumnType("int"); + + b.Property("IntervalCount") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LastError") + .HasColumnType("nvarchar(max)"); + + b.Property("MaxOccurrences") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("NextFireDate") + .HasColumnType("datetime2"); + + b.Property("OccurrenceCount") + .HasColumnType("int"); + + b.Property("TemplateData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TemplateType") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("RecurringTemplates"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Refund", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreditMemoId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("InvoiceId") + .HasColumnType("int"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IssuedById") + .HasColumnType("nvarchar(450)"); + + b.Property("IssuedDate") + .HasColumnType("datetime2"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PaymentId") + .HasColumnType("int"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Reference") + .HasColumnType("nvarchar(max)"); + + b.Property("RefundDate") + .HasColumnType("datetime2"); + + b.Property("RefundMethod") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreditMemoId"); + + b.HasIndex("InvoiceId"); + + b.HasIndex("IssuedById"); + + b.HasIndex("PaymentId"); + + b.ToTable("Refunds"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ReleaseNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Body") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedByUserName") + .HasColumnType("nvarchar(max)"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("ReleasedAt") + .HasColumnType("datetime2"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("Version") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("ReleaseNotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ReworkRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ActualReworkCost") + .HasColumnType("decimal(18,2)"); + + b.Property("BillingNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DefectDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DiscoveredBy") + .HasColumnType("int"); + + b.Property("DiscoveredDate") + .HasColumnType("datetime2"); + + b.Property("EstimatedReworkCost") + .HasColumnType("decimal(18,2)"); + + b.Property("IsBillableToCustomer") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("JobItemId") + .HasColumnType("int"); + + b.Property("Reason") + .HasColumnType("int"); + + b.Property("ReportedByName") + .HasColumnType("nvarchar(max)"); + + b.Property("Resolution") + .HasColumnType("int"); + + b.Property("ResolutionNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("ResolvedDate") + .HasColumnType("datetime2"); + + b.Property("ReworkJobId") + .HasColumnType("int"); + + b.Property("ReworkType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.HasIndex("JobItemId"); + + b.HasIndex("ReworkJobId"); + + b.ToTable("ReworkRecords"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ShopWorker", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("Phone") + .HasColumnType("nvarchar(max)"); + + b.Property("Role") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.ToTable("ShopWorkers"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ShopWorkerRoleCost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("HourlyRate") + .HasColumnType("decimal(18,2)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Role") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId", "Role") + .IsUnique() + .HasDatabaseName("IX_ShopWorkerRoleCosts_CompanyId_Role"); + + b.ToTable("ShopWorkerRoleCosts"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.StripeWebhookEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("EventId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EventType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProcessedAt") + .HasColumnType("datetime2"); + + b.Property("RawJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReceivedAt") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("StripeWebhookEvents"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.SubscriptionPlanConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AllowAccounting") + .HasColumnType("bit"); + + b.Property("AllowAiCatalogPriceCheck") + .HasColumnType("bit"); + + b.Property("AllowAiInventoryAssist") + .HasColumnType("bit"); + + b.Property("AllowAiPhotoQuotes") + .HasColumnType("bit"); + + b.Property("AllowOnlinePayments") + .HasColumnType("bit"); + + b.Property("AllowSms") + .HasColumnType("bit"); + + b.Property("AnnualPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("MaxActiveJobs") + .HasColumnType("int"); + + b.Property("MaxAiPhotoQuotesPerMonth") + .HasColumnType("int"); + + b.Property("MaxCatalogItems") + .HasColumnType("int"); + + b.Property("MaxCustomers") + .HasColumnType("int"); + + b.Property("MaxJobPhotos") + .HasColumnType("int"); + + b.Property("MaxQuotePhotos") + .HasColumnType("int"); + + b.Property("MaxQuotes") + .HasColumnType("int"); + + b.Property("MaxUsers") + .HasColumnType("int"); + + b.Property("MonthlyPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Plan") + .HasColumnType("int"); + + b.Property("SortOrder") + .HasColumnType("int"); + + b.Property("StripePriceIdAnnual") + .HasColumnType("nvarchar(max)"); + + b.Property("StripePriceIdMonthly") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("SubscriptionPlanConfigs"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.TaxRate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDefault") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Rate") + .HasColumnType("decimal(18,2)"); + + b.Property("State") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("TaxRates"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.TermsAcceptance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AcceptedAt") + .HasColumnType("datetime2"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("IpAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("TosVersion") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserAgent") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("TermsAcceptances"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.UserPasskey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CredentialId") + .IsRequired() + .HasColumnType("varbinary(900)"); + + b.Property("DeviceFriendlyName") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUsedAt") + .HasColumnType("datetime2"); + + b.Property("PublicKey") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("SignCount") + .HasColumnType("bigint"); + + b.Property("UserHandle") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CredentialId") + .IsUnique(); + + b.ToTable("UserPasskeys"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Vendor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("City") + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ContactName") + .HasColumnType("nvarchar(max)"); + + b.Property("Country") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreditLimit") + .HasColumnType("decimal(18,2)"); + + b.Property("CurrentBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("DefaultExpenseAccountId") + .HasColumnType("int"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("Is1099Vendor") + .HasColumnType("bit"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsPreferred") + .HasColumnType("bit"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OpeningBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("OpeningBalanceDate") + .HasColumnType("datetime2"); + + b.Property("PaymentTerms") + .HasColumnType("nvarchar(max)"); + + b.Property("Phone") + .HasColumnType("nvarchar(max)"); + + b.Property("State") + .HasColumnType("nvarchar(max)"); + + b.Property("TaxId") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Website") + .HasColumnType("nvarchar(max)"); + + b.Property("ZipCode") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.HasIndex("DefaultExpenseAccountId"); + + b.ToTable("Vendors"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.VendorCredit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("APAccountId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreditDate") + .HasColumnType("datetime2"); + + b.Property("CreditNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Memo") + .HasColumnType("nvarchar(max)"); + + b.Property("RemainingAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("APAccountId"); + + b.HasIndex("VendorId"); + + b.ToTable("VendorCredits"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.VendorCreditApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("AppliedDate") + .HasColumnType("datetime2"); + + b.Property("BillId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorCreditId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BillId"); + + b.HasIndex("VendorCreditId"); + + b.ToTable("VendorCreditApplications"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.VendorCreditLineItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("VendorCreditId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("VendorCreditId"); + + b.ToTable("VendorCreditLineItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.YearEndClose", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClosedAt") + .HasColumnType("datetime2"); + + b.Property("ClosedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ClosedYear") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JournalEntryId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JournalEntryId"); + + b.ToTable("YearEndCloses"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Account", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "ParentAccount") + .WithMany("SubAccounts") + .HasForeignKey("ParentAccountId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ParentAccount"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AiUsageLog", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AnnouncementDismissal", b => + { + b.HasOne("PowderCoating.Core.Entities.Announcement", "Announcement") + .WithMany("Dismissals") + .HasForeignKey("AnnouncementId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Announcement"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ApplicationUser", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", "Company") + .WithMany("Users") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Appointment", b => + { + b.HasOne("PowderCoating.Core.Entities.AppointmentStatusLookup", "AppointmentStatus") + .WithMany("Appointments") + .HasForeignKey("AppointmentStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.AppointmentTypeLookup", "AppointmentType") + .WithMany("Appointments") + .HasForeignKey("AppointmentTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "AssignedUser") + .WithMany() + .HasForeignKey("AssignedUserId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId"); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId"); + + b.Navigation("AppointmentStatus"); + + b.Navigation("AppointmentType"); + + b.Navigation("AssignedUser"); + + b.Navigation("Customer"); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BankReconciliation", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Bill", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "APAccount") + .WithMany("Bills") + .HasForeignKey("APAccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany("Bills") + .HasForeignKey("VendorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("APAccount"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BillLineItem", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "Account") + .WithMany("BillLineItems") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.Bill", "Bill") + .WithMany("LineItems") + .HasForeignKey("BillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId"); + + b.Navigation("Account"); + + b.Navigation("Bill"); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BillPayment", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "BankAccount") + .WithMany("BillPayments") + .HasForeignKey("BankAccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Bill", "Bill") + .WithMany("Payments") + .HasForeignKey("BillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany("BillPayments") + .HasForeignKey("VendorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("BankAccount"); + + b.Navigation("Bill"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BudgetLine", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Budget", "Budget") + .WithMany("Lines") + .HasForeignKey("BudgetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Budget"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BugReportAttachment", b => + { + b.HasOne("PowderCoating.Core.Entities.BugReport", "BugReport") + .WithMany("Attachments") + .HasForeignKey("BugReportId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BugReport"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CatalogCategory", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.CatalogCategory", "ParentCategory") + .WithMany("SubCategories") + .HasForeignKey("ParentCategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ParentCategory"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CatalogItem", b => + { + b.HasOne("PowderCoating.Core.Entities.CatalogCategory", "Category") + .WithMany("Items") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Account", "CogsAccount") + .WithMany() + .HasForeignKey("CogsAccountId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.InventoryItem", "InventoryItem") + .WithMany() + .HasForeignKey("InventoryItemId"); + + b.HasOne("PowderCoating.Core.Entities.Account", "RevenueAccount") + .WithMany() + .HasForeignKey("RevenueAccountId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Category"); + + b.Navigation("CogsAccount"); + + b.Navigation("InventoryItem"); + + b.Navigation("RevenueAccount"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CompanyBlastSetup", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CompanyOperatingCosts", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", "Company") + .WithOne("OperatingCosts") + .HasForeignKey("PowderCoating.Core.Entities.CompanyOperatingCosts", "CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CompanyPreferences", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", "Company") + .WithOne("Preferences") + .HasForeignKey("PowderCoating.Core.Entities.CompanyPreferences", "CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CreditMemo", b => + { + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "IssuedBy") + .WithMany() + .HasForeignKey("IssuedById"); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "OriginalInvoice") + .WithMany() + .HasForeignKey("OriginalInvoiceId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.ReworkRecord", "ReworkRecord") + .WithMany() + .HasForeignKey("ReworkRecordId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Customer"); + + b.Navigation("IssuedBy"); + + b.Navigation("OriginalInvoice"); + + b.Navigation("ReworkRecord"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CreditMemoApplication", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "AppliedBy") + .WithMany() + .HasForeignKey("AppliedById"); + + b.HasOne("PowderCoating.Core.Entities.CreditMemo", "CreditMemo") + .WithMany("Applications") + .HasForeignKey("CreditMemoId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "Invoice") + .WithMany("CreditApplications") + .HasForeignKey("InvoiceId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("AppliedBy"); + + b.Navigation("CreditMemo"); + + b.Navigation("Invoice"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Customer", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("Customers") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.PricingTier", "PricingTier") + .WithMany("Customers") + .HasForeignKey("PricingTierId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("PricingTier"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CustomerNote", b => + { + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany("CustomerNotes") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Deposit", b => + { + b.HasOne("PowderCoating.Core.Entities.Invoice", "AppliedToInvoice") + .WithMany() + .HasForeignKey("AppliedToInvoiceId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId"); + + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithMany() + .HasForeignKey("QuoteId"); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "RecordedBy") + .WithMany() + .HasForeignKey("RecordedById"); + + b.Navigation("AppliedToInvoice"); + + b.Navigation("Customer"); + + b.Navigation("Job"); + + b.Navigation("Quote"); + + b.Navigation("RecordedBy"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Equipment", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("Equipment") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Expense", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "ExpenseAccount") + .WithMany("Expenses") + .HasForeignKey("ExpenseAccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId"); + + b.HasOne("PowderCoating.Core.Entities.Account", "PaymentAccount") + .WithMany("ExpensePaymentAccounts") + .HasForeignKey("PaymentAccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany("Expenses") + .HasForeignKey("VendorId"); + + b.Navigation("ExpenseAccount"); + + b.Navigation("Job"); + + b.Navigation("PaymentAccount"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.FixedAsset", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "AccumDepreciationAccount") + .WithMany() + .HasForeignKey("AccumDepreciationAccountId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.Account", "AssetAccount") + .WithMany() + .HasForeignKey("AssetAccountId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.Account", "DepreciationExpenseAccount") + .WithMany() + .HasForeignKey("DepreciationExpenseAccountId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("AccumDepreciationAccount"); + + b.Navigation("AssetAccount"); + + b.Navigation("DepreciationExpenseAccount"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.FixedAssetDepreciationEntry", b => + { + b.HasOne("PowderCoating.Core.Entities.FixedAsset", "FixedAsset") + .WithMany("DepreciationEntries") + .HasForeignKey("FixedAssetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JournalEntry", "JournalEntry") + .WithMany() + .HasForeignKey("JournalEntryId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("FixedAsset"); + + b.Navigation("JournalEntry"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.GiftCertificate", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "IssuedBy") + .WithMany() + .HasForeignKey("IssuedById"); + + b.HasOne("PowderCoating.Core.Entities.Customer", "PurchasingCustomer") + .WithMany() + .HasForeignKey("PurchasingCustomerId"); + + b.HasOne("PowderCoating.Core.Entities.Customer", "RecipientCustomer") + .WithMany() + .HasForeignKey("RecipientCustomerId"); + + b.Navigation("IssuedBy"); + + b.Navigation("PurchasingCustomer"); + + b.Navigation("RecipientCustomer"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.GiftCertificateRedemption", b => + { + b.HasOne("PowderCoating.Core.Entities.GiftCertificate", "GiftCertificate") + .WithMany("Redemptions") + .HasForeignKey("GiftCertificateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "Invoice") + .WithMany("GiftCertificateRedemptions") + .HasForeignKey("InvoiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "RedeemedBy") + .WithMany() + .HasForeignKey("RedeemedById"); + + b.Navigation("GiftCertificate"); + + b.Navigation("Invoice"); + + b.Navigation("RedeemedBy"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InAppNotification", b => + { + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId"); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "Invoice") + .WithMany() + .HasForeignKey("InvoiceId"); + + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithMany() + .HasForeignKey("QuoteId"); + + b.Navigation("Customer"); + + b.Navigation("Invoice"); + + b.Navigation("Quote"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryCategoryLookup", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryItem", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "CogsAccount") + .WithMany() + .HasForeignKey("CogsAccountId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("InventoryItems") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Account", "InventoryAccount") + .WithMany() + .HasForeignKey("InventoryAccountId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.InventoryCategoryLookup", "InventoryCategory") + .WithMany("InventoryItems") + .HasForeignKey("InventoryCategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "PrimaryVendor") + .WithMany("InventoryItems") + .HasForeignKey("PrimaryVendorId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("CogsAccount"); + + b.Navigation("InventoryAccount"); + + b.Navigation("InventoryCategory"); + + b.Navigation("PrimaryVendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryTransaction", b => + { + b.HasOne("PowderCoating.Core.Entities.InventoryItem", "InventoryItem") + .WithMany("Transactions") + .HasForeignKey("InventoryItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.PurchaseOrder", "PurchaseOrder") + .WithMany() + .HasForeignKey("PurchaseOrderId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("InventoryItem"); + + b.Navigation("Job"); + + b.Navigation("PurchaseOrder"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Invoice", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany("Invoices") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithOne("Invoice") + .HasForeignKey("PowderCoating.Core.Entities.Invoice", "JobId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "PreparedBy") + .WithMany() + .HasForeignKey("PreparedById") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Account", "SalesTaxAccount") + .WithMany() + .HasForeignKey("SalesTaxAccountId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Customer"); + + b.Navigation("Job"); + + b.Navigation("PreparedBy"); + + b.Navigation("SalesTaxAccount"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InvoiceItem", b => + { + b.HasOne("PowderCoating.Core.Entities.CatalogItem", "CatalogItem") + .WithMany() + .HasForeignKey("CatalogItemId"); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.GiftCertificate", "GeneratedGiftCertificate") + .WithMany() + .HasForeignKey("GeneratedGiftCertificateId"); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "Invoice") + .WithMany("InvoiceItems") + .HasForeignKey("InvoiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Account", "RevenueAccount") + .WithMany() + .HasForeignKey("RevenueAccountId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.JobItem", "SourceJobItem") + .WithMany() + .HasForeignKey("SourceJobItemId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("CatalogItem"); + + b.Navigation("GeneratedGiftCertificate"); + + b.Navigation("Invoice"); + + b.Navigation("RevenueAccount"); + + b.Navigation("SourceJobItem"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Job", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "AssignedUser") + .WithMany() + .HasForeignKey("AssignedUserId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("Jobs") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany("Jobs") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "IntakeCheckedBy") + .WithMany() + .HasForeignKey("IntakeCheckedByUserId"); + + b.HasOne("PowderCoating.Core.Entities.JobPriorityLookup", "JobPriority") + .WithMany("Jobs") + .HasForeignKey("JobPriorityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobStatusLookup", "JobStatus") + .WithMany("Jobs") + .HasForeignKey("JobStatusId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "OriginalJob") + .WithMany() + .HasForeignKey("OriginalJobId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.OvenCost", "OvenCost") + .WithMany("Jobs") + .HasForeignKey("OvenCostId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithOne("ConvertedToJob") + .HasForeignKey("PowderCoating.Core.Entities.Job", "QuoteId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.ShopWorker", null) + .WithMany("AssignedJobs") + .HasForeignKey("ShopWorkerId"); + + b.Navigation("AssignedUser"); + + b.Navigation("Customer"); + + b.Navigation("IntakeCheckedBy"); + + b.Navigation("JobPriority"); + + b.Navigation("JobStatus"); + + b.Navigation("OriginalJob"); + + b.Navigation("OvenCost"); + + b.Navigation("Quote"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobChangeHistory", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "ChangedBy") + .WithMany() + .HasForeignKey("ChangedByUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChangedBy"); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobDailyPriority", b => + { + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobItem", b => + { + b.HasOne("PowderCoating.Core.Entities.AiItemPrediction", "AiPrediction") + .WithMany() + .HasForeignKey("AiPredictionId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.CatalogItem", "CatalogItem") + .WithMany() + .HasForeignKey("CatalogItemId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany("JobItems") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AiPrediction"); + + b.Navigation("CatalogItem"); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobItemCoat", b => + { + b.HasOne("PowderCoating.Core.Entities.InventoryItem", "InventoryItem") + .WithMany() + .HasForeignKey("InventoryItemId"); + + b.HasOne("PowderCoating.Core.Entities.JobItem", "JobItem") + .WithMany("Coats") + .HasForeignKey("JobItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany() + .HasForeignKey("VendorId"); + + b.Navigation("InventoryItem"); + + b.Navigation("JobItem"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobItemPrepService", b => + { + b.HasOne("PowderCoating.Core.Entities.CompanyBlastSetup", "BlastSetup") + .WithMany() + .HasForeignKey("BlastSetupId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobItem", "JobItem") + .WithMany("PrepServices") + .HasForeignKey("JobItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.PrepService", "PrepService") + .WithMany() + .HasForeignKey("PrepServiceId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("BlastSetup"); + + b.Navigation("JobItem"); + + b.Navigation("PrepService"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobNote", b => + { + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany("Notes") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobPhoto", b => + { + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany("Photos") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobPrepService", b => + { + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany("JobPrepServices") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.PrepService", "PrepService") + .WithMany() + .HasForeignKey("PrepServiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("PrepService"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobPriorityLookup", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobStatusHistory", b => + { + b.HasOne("PowderCoating.Core.Entities.JobStatusLookup", "FromStatus") + .WithMany("FromStatusHistory") + .HasForeignKey("FromStatusId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany("StatusHistory") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobStatusLookup", "ToStatus") + .WithMany("ToStatusHistory") + .HasForeignKey("ToStatusId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("FromStatus"); + + b.Navigation("Job"); + + b.Navigation("ToStatus"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobStatusLookup", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplate", b => + { + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId"); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplateItem", b => + { + b.HasOne("PowderCoating.Core.Entities.CatalogItem", "CatalogItem") + .WithMany() + .HasForeignKey("CatalogItemId"); + + b.HasOne("PowderCoating.Core.Entities.JobTemplate", "JobTemplate") + .WithMany("Items") + .HasForeignKey("JobTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CatalogItem"); + + b.Navigation("JobTemplate"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplateItemCoat", b => + { + b.HasOne("PowderCoating.Core.Entities.InventoryItem", "InventoryItem") + .WithMany() + .HasForeignKey("InventoryItemId"); + + b.HasOne("PowderCoating.Core.Entities.JobTemplateItem", "JobTemplateItem") + .WithMany("Coats") + .HasForeignKey("JobTemplateItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany() + .HasForeignKey("VendorId"); + + b.Navigation("InventoryItem"); + + b.Navigation("JobTemplateItem"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplateItemPrepService", b => + { + b.HasOne("PowderCoating.Core.Entities.JobTemplateItem", "JobTemplateItem") + .WithMany("PrepServices") + .HasForeignKey("JobTemplateItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.PrepService", "PrepService") + .WithMany() + .HasForeignKey("PrepServiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JobTemplateItem"); + + b.Navigation("PrepService"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTimeEntry", b => + { + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany("TimeEntries") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ShopWorker", "Worker") + .WithMany("TimeEntries") + .HasForeignKey("ShopWorkerId"); + + b.Navigation("Job"); + + b.Navigation("Worker"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JournalEntry", b => + { + b.HasOne("PowderCoating.Core.Entities.JournalEntry", "ReversalOf") + .WithMany() + .HasForeignKey("ReversalOfId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ReversalOf"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JournalEntryLine", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JournalEntry", "JournalEntry") + .WithMany("Lines") + .HasForeignKey("JournalEntryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("JournalEntry"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.MaintenanceRecord", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "AssignedUser") + .WithMany() + .HasForeignKey("AssignedUserId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Equipment", "Equipment") + .WithMany("MaintenanceRecords") + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "PerformedBy") + .WithMany("PerformedMaintenances") + .HasForeignKey("PerformedById") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.MaintenanceRecord", "RecurrenceParent") + .WithMany() + .HasForeignKey("RecurrenceParentId"); + + b.HasOne("PowderCoating.Core.Entities.ShopWorker", null) + .WithMany("AssignedMaintenanceTasks") + .HasForeignKey("ShopWorkerId"); + + b.Navigation("AssignedUser"); + + b.Navigation("Equipment"); + + b.Navigation("PerformedBy"); + + b.Navigation("RecurrenceParent"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.NotificationLog", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany("NotificationLogs") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "Invoice") + .WithMany() + .HasForeignKey("InvoiceId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithMany() + .HasForeignKey("QuoteId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Customer"); + + b.Navigation("Invoice"); + + b.Navigation("Job"); + + b.Navigation("Quote"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.NotificationTemplate", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenBatch", b => + { + b.HasOne("PowderCoating.Core.Entities.Equipment", "Equipment") + .WithMany("OvenBatches") + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.OvenCost", "OvenCost") + .WithMany() + .HasForeignKey("OvenCostId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Equipment"); + + b.Navigation("OvenCost"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenBatchItem", b => + { + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobItemCoat", "JobItemCoat") + .WithMany() + .HasForeignKey("JobItemCoatId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobItem", "JobItem") + .WithMany() + .HasForeignKey("JobItemId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.OvenBatch", "Batch") + .WithMany("Items") + .HasForeignKey("OvenBatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Batch"); + + b.Navigation("Job"); + + b.Navigation("JobItem"); + + b.Navigation("JobItemCoat"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenCost", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Payment", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Account", "DepositAccount") + .WithMany() + .HasForeignKey("DepositAccountId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "Invoice") + .WithMany("Payments") + .HasForeignKey("InvoiceId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "RecordedBy") + .WithMany() + .HasForeignKey("RecordedById") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("DepositAccount"); + + b.Navigation("Invoice"); + + b.Navigation("RecordedBy"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PowderUsageLog", b => + { + b.HasOne("PowderCoating.Core.Entities.InventoryItem", "InventoryItem") + .WithMany() + .HasForeignKey("InventoryItemId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.InventoryTransaction", "InventoryTransaction") + .WithMany() + .HasForeignKey("InventoryTransactionId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobItemCoat", "JobItemCoat") + .WithMany() + .HasForeignKey("JobItemCoatId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobItem", "JobItem") + .WithMany() + .HasForeignKey("JobItemId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("InventoryItem"); + + b.Navigation("InventoryTransaction"); + + b.Navigation("Job"); + + b.Navigation("JobItem"); + + b.Navigation("JobItemCoat"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PricingTier", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("PricingTiers") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PurchaseOrder", b => + { + b.HasOne("PowderCoating.Core.Entities.Bill", "Bill") + .WithMany() + .HasForeignKey("BillId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany() + .HasForeignKey("VendorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Bill"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PurchaseOrderItem", b => + { + b.HasOne("PowderCoating.Core.Entities.InventoryItem", "InventoryItem") + .WithMany() + .HasForeignKey("InventoryItemId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.PurchaseOrder", "PurchaseOrder") + .WithMany("Items") + .HasForeignKey("PurchaseOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InventoryItem"); + + b.Navigation("PurchaseOrder"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Quote", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("Quotes") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Customer", "Customer") + .WithMany("Quotes") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.OvenCost", "OvenCost") + .WithMany("Quotes") + .HasForeignKey("OvenCostId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "PreparedBy") + .WithMany("PreparedQuotes") + .HasForeignKey("PreparedById") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.QuoteStatusLookup", "QuoteStatus") + .WithMany("Quotes") + .HasForeignKey("QuoteStatusId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("OvenCost"); + + b.Navigation("PreparedBy"); + + b.Navigation("QuoteStatus"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteChangeHistory", b => + { + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "ChangedBy") + .WithMany() + .HasForeignKey("ChangedByUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithMany() + .HasForeignKey("QuoteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChangedBy"); + + b.Navigation("Quote"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteItem", b => + { + b.HasOne("PowderCoating.Core.Entities.AiItemPrediction", "AiPrediction") + .WithMany() + .HasForeignKey("AiPredictionId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.CatalogItem", "CatalogItem") + .WithMany() + .HasForeignKey("CatalogItemId"); + + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithMany("QuoteItems") + .HasForeignKey("QuoteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AiPrediction"); + + b.Navigation("CatalogItem"); + + b.Navigation("Quote"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteItemCoat", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.InventoryItem", "InventoryItem") + .WithMany() + .HasForeignKey("InventoryItemId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.QuoteItem", "QuoteItem") + .WithMany("Coats") + .HasForeignKey("QuoteItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany() + .HasForeignKey("VendorId"); + + b.Navigation("InventoryItem"); + + b.Navigation("QuoteItem"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteItemPrepService", b => + { + b.HasOne("PowderCoating.Core.Entities.CompanyBlastSetup", "BlastSetup") + .WithMany() + .HasForeignKey("BlastSetupId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.PrepService", "PrepService") + .WithMany() + .HasForeignKey("PrepServiceId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.QuoteItem", "QuoteItem") + .WithMany("PrepServices") + .HasForeignKey("QuoteItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BlastSetup"); + + b.Navigation("PrepService"); + + b.Navigation("QuoteItem"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuotePhoto", b => + { + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithMany("QuotePhotos") + .HasForeignKey("QuoteId"); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Quote"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuotePrepService", b => + { + b.HasOne("PowderCoating.Core.Entities.PrepService", "PrepService") + .WithMany() + .HasForeignKey("PrepServiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Quote", "Quote") + .WithMany("QuotePrepServices") + .HasForeignKey("QuoteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PrepService"); + + b.Navigation("Quote"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteStatusLookup", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Refund", b => + { + b.HasOne("PowderCoating.Core.Entities.CreditMemo", "CreditMemo") + .WithMany() + .HasForeignKey("CreditMemoId"); + + b.HasOne("PowderCoating.Core.Entities.Invoice", "Invoice") + .WithMany("Refunds") + .HasForeignKey("InvoiceId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.ApplicationUser", "IssuedBy") + .WithMany() + .HasForeignKey("IssuedById"); + + b.HasOne("PowderCoating.Core.Entities.Payment", "Payment") + .WithMany() + .HasForeignKey("PaymentId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("CreditMemo"); + + b.Navigation("Invoice"); + + b.Navigation("IssuedBy"); + + b.Navigation("Payment"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ReworkRecord", b => + { + b.HasOne("PowderCoating.Core.Entities.Job", "Job") + .WithMany("ReworkRecords") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.JobItem", "JobItem") + .WithMany() + .HasForeignKey("JobItemId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PowderCoating.Core.Entities.Job", "ReworkJob") + .WithMany() + .HasForeignKey("ReworkJobId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Job"); + + b.Navigation("JobItem"); + + b.Navigation("ReworkJob"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ShopWorker", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("ShopWorkers") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Vendor", b => + { + b.HasOne("PowderCoating.Core.Entities.Company", null) + .WithMany("Vendors") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Account", "DefaultExpenseAccount") + .WithMany() + .HasForeignKey("DefaultExpenseAccountId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("DefaultExpenseAccount"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.VendorCredit", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "APAccount") + .WithMany() + .HasForeignKey("APAccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Vendor", "Vendor") + .WithMany() + .HasForeignKey("VendorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("APAccount"); + + b.Navigation("Vendor"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.VendorCreditApplication", b => + { + b.HasOne("PowderCoating.Core.Entities.Bill", "Bill") + .WithMany() + .HasForeignKey("BillId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.VendorCredit", "VendorCredit") + .WithMany("Applications") + .HasForeignKey("VendorCreditId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Bill"); + + b.Navigation("VendorCredit"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.VendorCreditLineItem", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PowderCoating.Core.Entities.VendorCredit", "VendorCredit") + .WithMany("LineItems") + .HasForeignKey("VendorCreditId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("VendorCredit"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.YearEndClose", b => + { + b.HasOne("PowderCoating.Core.Entities.JournalEntry", "JournalEntry") + .WithMany() + .HasForeignKey("JournalEntryId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("JournalEntry"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Account", b => + { + b.Navigation("BillLineItems"); + + b.Navigation("BillPayments"); + + b.Navigation("Bills"); + + b.Navigation("ExpensePaymentAccounts"); + + b.Navigation("Expenses"); + + b.Navigation("SubAccounts"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Announcement", b => + { + b.Navigation("Dismissals"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ApplicationUser", b => + { + b.Navigation("PerformedMaintenances"); + + b.Navigation("PreparedQuotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AppointmentStatusLookup", b => + { + b.Navigation("Appointments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.AppointmentTypeLookup", b => + { + b.Navigation("Appointments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Bill", b => + { + b.Navigation("LineItems"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Budget", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BugReport", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CatalogCategory", b => + { + b.Navigation("Items"); + + b.Navigation("SubCategories"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Company", b => + { + b.Navigation("Customers"); + + b.Navigation("Equipment"); + + b.Navigation("InventoryItems"); + + b.Navigation("Jobs"); + + b.Navigation("OperatingCosts"); + + b.Navigation("Preferences"); + + b.Navigation("PricingTiers"); + + b.Navigation("Quotes"); + + b.Navigation("ShopWorkers"); + + b.Navigation("Users"); + + b.Navigation("Vendors"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.CreditMemo", b => + { + b.Navigation("Applications"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Customer", b => + { + b.Navigation("CustomerNotes"); + + b.Navigation("Invoices"); + + b.Navigation("Jobs"); + + b.Navigation("NotificationLogs"); + + b.Navigation("Quotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Equipment", b => + { + b.Navigation("MaintenanceRecords"); + + b.Navigation("OvenBatches"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.FixedAsset", b => + { + b.Navigation("DepreciationEntries"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.GiftCertificate", b => + { + b.Navigation("Redemptions"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryCategoryLookup", b => + { + b.Navigation("InventoryItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.InventoryItem", b => + { + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Invoice", b => + { + b.Navigation("CreditApplications"); + + b.Navigation("GiftCertificateRedemptions"); + + b.Navigation("InvoiceItems"); + + b.Navigation("Payments"); + + b.Navigation("Refunds"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Job", b => + { + b.Navigation("Invoice"); + + b.Navigation("JobItems"); + + b.Navigation("JobPrepServices"); + + b.Navigation("Notes"); + + b.Navigation("Photos"); + + b.Navigation("ReworkRecords"); + + b.Navigation("StatusHistory"); + + b.Navigation("TimeEntries"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobItem", b => + { + b.Navigation("Coats"); + + b.Navigation("PrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobPriorityLookup", b => + { + b.Navigation("Jobs"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobStatusLookup", b => + { + b.Navigation("FromStatusHistory"); + + b.Navigation("Jobs"); + + b.Navigation("ToStatusHistory"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplate", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JobTemplateItem", b => + { + b.Navigation("Coats"); + + b.Navigation("PrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.JournalEntry", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenBatch", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.OvenCost", b => + { + b.Navigation("Jobs"); + + b.Navigation("Quotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PricingTier", b => + { + b.Navigation("Customers"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.PurchaseOrder", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Quote", b => + { + b.Navigation("ConvertedToJob"); + + b.Navigation("QuoteItems"); + + b.Navigation("QuotePhotos"); + + b.Navigation("QuotePrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteItem", b => + { + b.Navigation("Coats"); + + b.Navigation("PrepServices"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.QuoteStatusLookup", b => + { + b.Navigation("Quotes"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.ShopWorker", b => + { + b.Navigation("AssignedJobs"); + + b.Navigation("AssignedMaintenanceTasks"); + + b.Navigation("TimeEntries"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.Vendor", b => + { + b.Navigation("BillPayments"); + + b.Navigation("Bills"); + + b.Navigation("Expenses"); + + b.Navigation("InventoryItems"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.VendorCredit", b => + { + b.Navigation("Applications"); + + b.Navigation("LineItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/PowderCoating.Infrastructure/Migrations/20260510165511_AddBudgetsAndYearEndClose.cs b/src/PowderCoating.Infrastructure/Migrations/20260510165511_AddBudgetsAndYearEndClose.cs new file mode 100644 index 0000000..a86b861 --- /dev/null +++ b/src/PowderCoating.Infrastructure/Migrations/20260510165511_AddBudgetsAndYearEndClose.cs @@ -0,0 +1,185 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PowderCoating.Infrastructure.Migrations +{ + /// + public partial class AddBudgetsAndYearEndClose : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Budgets", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(max)", nullable: false), + FiscalYear = table.Column(type: "int", nullable: false), + Notes = table.Column(type: "nvarchar(max)", nullable: true), + IsDefault = table.Column(type: "bit", nullable: false), + CompanyId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false), + DeletedAt = table.Column(type: "datetime2", nullable: true), + DeletedBy = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Budgets", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "YearEndCloses", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ClosedYear = table.Column(type: "int", nullable: false), + ClosedAt = table.Column(type: "datetime2", nullable: false), + ClosedBy = table.Column(type: "nvarchar(max)", nullable: true), + JournalEntryId = table.Column(type: "int", nullable: false), + CompanyId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false), + DeletedAt = table.Column(type: "datetime2", nullable: true), + DeletedBy = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_YearEndCloses", x => x.Id); + table.ForeignKey( + name: "FK_YearEndCloses_JournalEntries_JournalEntryId", + column: x => x.JournalEntryId, + principalTable: "JournalEntries", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "BudgetLines", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + BudgetId = table.Column(type: "int", nullable: false), + AccountId = table.Column(type: "int", nullable: false), + Jan = table.Column(type: "decimal(18,2)", nullable: false), + Feb = table.Column(type: "decimal(18,2)", nullable: false), + Mar = table.Column(type: "decimal(18,2)", nullable: false), + Apr = table.Column(type: "decimal(18,2)", nullable: false), + May = table.Column(type: "decimal(18,2)", nullable: false), + Jun = table.Column(type: "decimal(18,2)", nullable: false), + Jul = table.Column(type: "decimal(18,2)", nullable: false), + Aug = table.Column(type: "decimal(18,2)", nullable: false), + Sep = table.Column(type: "decimal(18,2)", nullable: false), + Oct = table.Column(type: "decimal(18,2)", nullable: false), + Nov = table.Column(type: "decimal(18,2)", nullable: false), + Dec = table.Column(type: "decimal(18,2)", nullable: false), + CompanyId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false), + DeletedAt = table.Column(type: "datetime2", nullable: true), + DeletedBy = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BudgetLines", x => x.Id); + table.ForeignKey( + name: "FK_BudgetLines_Accounts_AccountId", + column: x => x.AccountId, + principalTable: "Accounts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_BudgetLines_Budgets_BudgetId", + column: x => x.BudgetId, + principalTable: "Budgets", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.UpdateData( + table: "PricingTiers", + keyColumn: "Id", + keyValue: 1, + column: "CreatedAt", + value: new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(966)); + + migrationBuilder.UpdateData( + table: "PricingTiers", + keyColumn: "Id", + keyValue: 2, + column: "CreatedAt", + value: new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(974)); + + migrationBuilder.UpdateData( + table: "PricingTiers", + keyColumn: "Id", + keyValue: 3, + column: "CreatedAt", + value: new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(976)); + + migrationBuilder.CreateIndex( + name: "IX_BudgetLines_AccountId", + table: "BudgetLines", + column: "AccountId"); + + migrationBuilder.CreateIndex( + name: "IX_BudgetLines_BudgetId", + table: "BudgetLines", + column: "BudgetId"); + + migrationBuilder.CreateIndex( + name: "IX_YearEndCloses_JournalEntryId", + table: "YearEndCloses", + column: "JournalEntryId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "BudgetLines"); + + migrationBuilder.DropTable( + name: "YearEndCloses"); + + migrationBuilder.DropTable( + name: "Budgets"); + + migrationBuilder.UpdateData( + table: "PricingTiers", + keyColumn: "Id", + keyValue: 1, + column: "CreatedAt", + value: new DateTime(2026, 5, 10, 16, 0, 49, 626, DateTimeKind.Utc).AddTicks(4004)); + + migrationBuilder.UpdateData( + table: "PricingTiers", + keyColumn: "Id", + keyValue: 2, + column: "CreatedAt", + value: new DateTime(2026, 5, 10, 16, 0, 49, 626, DateTimeKind.Utc).AddTicks(4009)); + + migrationBuilder.UpdateData( + table: "PricingTiers", + keyColumn: "Id", + keyValue: 3, + column: "CreatedAt", + value: new DateTime(2026, 5, 10, 16, 0, 49, 626, DateTimeKind.Utc).AddTicks(4011)); + } + } +} diff --git a/src/PowderCoating.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs b/src/PowderCoating.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs index 5f654ec..381b29b 100644 --- a/src/PowderCoating.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/PowderCoating.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1269,6 +1269,139 @@ namespace PowderCoating.Infrastructure.Migrations b.ToTable("BillPayments"); }); + modelBuilder.Entity("PowderCoating.Core.Entities.Budget", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FiscalYear") + .HasColumnType("int"); + + b.Property("IsDefault") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Budgets"); + }); + + modelBuilder.Entity("PowderCoating.Core.Entities.BudgetLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("Apr") + .HasColumnType("decimal(18,2)"); + + b.Property("Aug") + .HasColumnType("decimal(18,2)"); + + b.Property("BudgetId") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Dec") + .HasColumnType("decimal(18,2)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Feb") + .HasColumnType("decimal(18,2)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Jan") + .HasColumnType("decimal(18,2)"); + + b.Property("Jul") + .HasColumnType("decimal(18,2)"); + + b.Property("Jun") + .HasColumnType("decimal(18,2)"); + + b.Property("Mar") + .HasColumnType("decimal(18,2)"); + + b.Property("May") + .HasColumnType("decimal(18,2)"); + + b.Property("Nov") + .HasColumnType("decimal(18,2)"); + + b.Property("Oct") + .HasColumnType("decimal(18,2)"); + + b.Property("Sep") + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("BudgetId"); + + b.ToTable("BudgetLines"); + }); + modelBuilder.Entity("PowderCoating.Core.Entities.BugReport", b => { b.Property("Id") @@ -6432,7 +6565,7 @@ namespace PowderCoating.Infrastructure.Migrations { Id = 1, CompanyId = 0, - CreatedAt = new DateTime(2026, 5, 10, 16, 0, 49, 626, DateTimeKind.Utc).AddTicks(4004), + CreatedAt = new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(966), Description = "Standard pricing for regular customers", DiscountPercent = 0m, IsActive = true, @@ -6443,7 +6576,7 @@ namespace PowderCoating.Infrastructure.Migrations { Id = 2, CompanyId = 0, - CreatedAt = new DateTime(2026, 5, 10, 16, 0, 49, 626, DateTimeKind.Utc).AddTicks(4009), + CreatedAt = new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(974), Description = "5% discount for preferred customers", DiscountPercent = 5m, IsActive = true, @@ -6454,7 +6587,7 @@ namespace PowderCoating.Infrastructure.Migrations { Id = 3, CompanyId = 0, - CreatedAt = new DateTime(2026, 5, 10, 16, 0, 49, 626, DateTimeKind.Utc).AddTicks(4011), + CreatedAt = new DateTime(2026, 5, 10, 16, 55, 8, 322, DateTimeKind.Utc).AddTicks(976), Description = "10% discount for premium customers", DiscountPercent = 10m, IsActive = true, @@ -8376,6 +8509,57 @@ namespace PowderCoating.Infrastructure.Migrations b.ToTable("VendorCreditLineItems"); }); + modelBuilder.Entity("PowderCoating.Core.Entities.YearEndClose", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClosedAt") + .HasColumnType("datetime2"); + + b.Property("ClosedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("ClosedYear") + .HasColumnType("int"); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JournalEntryId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("JournalEntryId"); + + b.ToTable("YearEndCloses"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) @@ -8589,6 +8773,25 @@ namespace PowderCoating.Infrastructure.Migrations b.Navigation("Vendor"); }); + modelBuilder.Entity("PowderCoating.Core.Entities.BudgetLine", b => + { + b.HasOne("PowderCoating.Core.Entities.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PowderCoating.Core.Entities.Budget", "Budget") + .WithMany("Lines") + .HasForeignKey("BudgetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Budget"); + }); + modelBuilder.Entity("PowderCoating.Core.Entities.BugReportAttachment", b => { b.HasOne("PowderCoating.Core.Entities.BugReport", "BugReport") @@ -10090,6 +10293,17 @@ namespace PowderCoating.Infrastructure.Migrations b.Navigation("VendorCredit"); }); + modelBuilder.Entity("PowderCoating.Core.Entities.YearEndClose", b => + { + b.HasOne("PowderCoating.Core.Entities.JournalEntry", "JournalEntry") + .WithMany() + .HasForeignKey("JournalEntryId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("JournalEntry"); + }); + modelBuilder.Entity("PowderCoating.Core.Entities.Account", b => { b.Navigation("BillLineItems"); @@ -10134,6 +10348,11 @@ namespace PowderCoating.Infrastructure.Migrations b.Navigation("Payments"); }); + modelBuilder.Entity("PowderCoating.Core.Entities.Budget", b => + { + b.Navigation("Lines"); + }); + modelBuilder.Entity("PowderCoating.Core.Entities.BugReport", b => { b.Navigation("Attachments"); diff --git a/src/PowderCoating.Infrastructure/Repositories/UnitOfWork.cs b/src/PowderCoating.Infrastructure/Repositories/UnitOfWork.cs index 86a190a..4eb5742 100644 --- a/src/PowderCoating.Infrastructure/Repositories/UnitOfWork.cs +++ b/src/PowderCoating.Infrastructure/Repositories/UnitOfWork.cs @@ -161,6 +161,9 @@ public class UnitOfWork : IUnitOfWork private IRepository? _recurringTemplates; private IRepository? _fixedAssets; private IRepository? _fixedAssetDepreciationEntries; + private IRepository? _budgets; + private IRepository? _budgetLines; + private IRepository? _yearEndCloses; /// /// Initialises the unit of work with the scoped . @@ -573,6 +576,12 @@ public class UnitOfWork : IUnitOfWork _fixedAssets ??= new Repository(_context); public IRepository FixedAssetDepreciationEntries => _fixedAssetDepreciationEntries ??= new Repository(_context); + public IRepository Budgets => + _budgets ??= new Repository(_context); + public IRepository BudgetLines => + _budgetLines ??= new Repository(_context); + public IRepository YearEndCloses => + _yearEndCloses ??= new Repository(_context); /// /// Flushes all pending changes in the EF Core change tracker to the database. diff --git a/src/PowderCoating.Web/Controllers/AccountsController.cs b/src/PowderCoating.Web/Controllers/AccountsController.cs index 7e7d018..b97608c 100644 --- a/src/PowderCoating.Web/Controllers/AccountsController.cs +++ b/src/PowderCoating.Web/Controllers/AccountsController.cs @@ -427,6 +427,186 @@ public class AccountsController : Controller return View(ledger); } + // ── Year-End Close ──────────────────────────────────────────────────────── + + /// + /// GET: landing page showing close history and a form to initiate the current year close. + /// Companyid is resolved from tenant context; year defaults to the prior fiscal year + /// (the most common use case — close last year after final entries are posted). + /// + [HttpGet] + [Authorize(Policy = AppConstants.Policies.CompanyAdminOnly)] + public async Task YearEndClose() + { + var companyId = _tenantContext.GetCurrentCompanyId() ?? 0; + var history = (await _unitOfWork.YearEndCloses.FindAsync(y => true, false, y => y.JournalEntry)) + .OrderByDescending(y => y.ClosedYear) + .ToList(); + + ViewBag.History = history; + ViewBag.SuggestedYear = DateTime.Now.Year - 1; + ViewBag.ClosedYears = history.Select(y => y.ClosedYear).ToHashSet(); + + return View(); + } + + /// + /// POST: executes the year-end close for the specified fiscal year. + /// Sums all Revenue account balances (credit-normal) and all Expense/COGS balances + /// (debit-normal), computes net income, posts a JE that zeroes them into Retained + /// Earnings, then records a YearEndClose audit entry. Idempotency: a year that has + /// already been closed is rejected. + /// + [HttpPost, ValidateAntiForgeryToken] + [Authorize(Policy = AppConstants.Policies.CompanyAdminOnly)] + public async Task CloseYear(int year) + { + var companyId = _tenantContext.GetCurrentCompanyId() ?? 0; + + // Idempotency check + var existing = (await _unitOfWork.YearEndCloses.FindAsync(y => y.ClosedYear == year)).FirstOrDefault(); + if (existing != null) + { + TempData["Error"] = $"{year} has already been closed (JE {existing.JournalEntryId})."; + return RedirectToAction(nameof(YearEndClose)); + } + + // Load all active accounts with balances + var accounts = (await _unitOfWork.Accounts.FindAsync(a => a.IsActive)).ToList(); + + var revenueAccounts = accounts.Where(a => a.AccountType == AccountType.Revenue).ToList(); + var expenseAccounts = accounts.Where(a => + a.AccountType == AccountType.Expense || + a.AccountSubType == AccountSubType.CostOfGoodsSold).ToList(); + + // Find or locate the Retained Earnings account + var retainedEarnings = accounts.FirstOrDefault(a => + a.AccountSubType == AccountSubType.RetainedEarnings); + + if (retainedEarnings == null) + { + TempData["Error"] = "No Retained Earnings account found. Create an Equity account with the 'Retained Earnings' sub-type first."; + return RedirectToAction(nameof(YearEndClose)); + } + + // Net income = total revenue credits − total expense debits + var totalRevenue = revenueAccounts.Sum(a => a.CurrentBalance); + var totalExpenses = expenseAccounts.Sum(a => a.CurrentBalance); + var netIncome = totalRevenue - totalExpenses; + + if (totalRevenue == 0 && totalExpenses == 0) + { + TempData["Error"] = $"No revenue or expense balances found for {year}. Nothing to close."; + return RedirectToAction(nameof(YearEndClose)); + } + + int newJeId = 0; + + await _unitOfWork.ExecuteInTransactionAsync(async () => + { + var lines = new List(); + + // Zero out Revenue accounts: DR each revenue account (reduces credit balance to 0) + foreach (var acct in revenueAccounts.Where(a => a.CurrentBalance != 0)) + { + lines.Add(new JournalEntryLine + { + AccountId = acct.Id, + DebitAmount = acct.CurrentBalance > 0 ? acct.CurrentBalance : 0, + CreditAmount = acct.CurrentBalance < 0 ? Math.Abs(acct.CurrentBalance) : 0, + Description = $"Close {year} — {acct.Name}", + CompanyId = companyId, CreatedAt = DateTime.UtcNow + }); + await _accountBalanceService.DebitAsync(acct.Id, acct.CurrentBalance > 0 ? acct.CurrentBalance : 0); + if (acct.CurrentBalance < 0) + await _accountBalanceService.CreditAsync(acct.Id, Math.Abs(acct.CurrentBalance)); + } + + // Zero out Expense/COGS accounts: CR each expense account (reduces debit balance to 0) + foreach (var acct in expenseAccounts.Where(a => a.CurrentBalance != 0)) + { + lines.Add(new JournalEntryLine + { + AccountId = acct.Id, + DebitAmount = acct.CurrentBalance < 0 ? Math.Abs(acct.CurrentBalance) : 0, + CreditAmount = acct.CurrentBalance > 0 ? acct.CurrentBalance : 0, + Description = $"Close {year} — {acct.Name}", + CompanyId = companyId, CreatedAt = DateTime.UtcNow + }); + await _accountBalanceService.CreditAsync(acct.Id, acct.CurrentBalance > 0 ? acct.CurrentBalance : 0); + if (acct.CurrentBalance < 0) + await _accountBalanceService.DebitAsync(acct.Id, Math.Abs(acct.CurrentBalance)); + } + + // Plug the net into Retained Earnings: CR if profit, DR if loss + if (netIncome > 0) + { + lines.Add(new JournalEntryLine + { + AccountId = retainedEarnings.Id, + CreditAmount = netIncome, + Description = $"Net income {year} → Retained Earnings", + CompanyId = companyId, CreatedAt = DateTime.UtcNow + }); + await _accountBalanceService.CreditAsync(retainedEarnings.Id, netIncome); + } + else if (netIncome < 0) + { + lines.Add(new JournalEntryLine + { + AccountId = retainedEarnings.Id, + DebitAmount = Math.Abs(netIncome), + Description = $"Net loss {year} → Retained Earnings", + CompanyId = companyId, CreatedAt = DateTime.UtcNow + }); + await _accountBalanceService.DebitAsync(retainedEarnings.Id, Math.Abs(netIncome)); + } + + // Post the JE + var prefix = $"JE-{year % 100:D2}12-"; + var existing2 = await _unitOfWork.JournalEntries.FindAsync( + je => je.CompanyId == companyId && je.EntryNumber.StartsWith(prefix), + ignoreQueryFilters: true); + int next = existing2.Any() + ? existing2.Select(je => je.EntryNumber[prefix.Length..]).Select(s => int.TryParse(s, out int n) ? n : 0).Max() + 1 + : 1; + + var je = new JournalEntry + { + EntryNumber = $"{prefix}{next:D4}", + EntryDate = new DateTime(year, 12, 31, 0, 0, 0, DateTimeKind.Utc), + Description = $"Year-end close — {year}", + Reference = $"CLOSE-{year}", + Status = JournalEntryStatus.Posted, + PostedBy = User.Identity?.Name, + PostedAt = DateTime.UtcNow, + CompanyId = companyId, + CreatedAt = DateTime.UtcNow, + Lines = lines + }; + await _unitOfWork.JournalEntries.AddAsync(je); + await _unitOfWork.CompleteAsync(); + + // Record the close + var close = new YearEndClose + { + ClosedYear = year, + ClosedAt = DateTime.UtcNow, + ClosedBy = User.Identity?.Name, + JournalEntryId = je.Id, + CompanyId = companyId, + CreatedAt = DateTime.UtcNow + }; + await _unitOfWork.YearEndCloses.AddAsync(close); + await _unitOfWork.CompleteAsync(); + newJeId = je.Id; + }); + + TempData["Success"] = $"Year {year} closed. Net income {netIncome:C} transferred to Retained Earnings. " + + $"See Journal Entry for details."; + return RedirectToAction(nameof(YearEndClose)); + } + // ── Helpers ────────────────────────────────────────────────────────────── /// diff --git a/src/PowderCoating.Web/Controllers/BudgetsController.cs b/src/PowderCoating.Web/Controllers/BudgetsController.cs new file mode 100644 index 0000000..45ca7c0 --- /dev/null +++ b/src/PowderCoating.Web/Controllers/BudgetsController.cs @@ -0,0 +1,302 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using PowderCoating.Core.Entities; +using PowderCoating.Core.Enums; +using PowderCoating.Core.Interfaces; +using PowderCoating.Shared.Constants; + +namespace PowderCoating.Web.Controllers; + +/// +/// Manages annual budgets. Each budget has one BudgetLine per active GL account with +/// monthly amounts (Jan–Dec). The Budget vs. Actual report compares these to real activity. +/// Only one budget per year is marked IsDefault — that one feeds the variance report automatically. +/// +[Authorize(Policy = AppConstants.Policies.CompanyAdminOnly)] +public class BudgetsController : Controller +{ + private readonly IUnitOfWork _unitOfWork; + private readonly ITenantContext _tenantContext; + + public BudgetsController(IUnitOfWork unitOfWork, ITenantContext tenantContext) + { + _unitOfWork = unitOfWork; + _tenantContext = tenantContext; + } + + // ── Index ───────────────────────────────────────────────────────────────── + + /// Lists all budgets for the current company ordered by fiscal year descending. + public async Task Index() + { + var budgets = (await _unitOfWork.Budgets.FindAsync(b => true, false, b => b.Lines)) + .OrderByDescending(b => b.FiscalYear) + .ThenBy(b => b.Name) + .ToList(); + + return View(budgets); + } + + // ── Create ──────────────────────────────────────────────────────────────── + + [HttpGet] + public async Task Create() + { + var accounts = await GetBudgetableAccountsAsync(); + return View(new BudgetCreateVm + { + FiscalYear = DateTime.Now.Year, + Lines = accounts.Select(a => new BudgetLineVm { AccountId = a.Id, AccountNumber = a.AccountNumber, AccountName = a.Name, AccountType = a.AccountType }).ToList() + }); + } + + [HttpPost, ValidateAntiForgeryToken] + public async Task Create(BudgetCreateVm vm) + { + if (!ModelState.IsValid) return View(vm); + + var companyId = _tenantContext.GetCurrentCompanyId() ?? 0; + + // If this is marked default, clear the flag on other budgets for the same year + if (vm.IsDefault) + await ClearDefaultFlagAsync(companyId, vm.FiscalYear, excludeId: null); + + var budget = new Budget + { + Name = vm.Name, + FiscalYear = vm.FiscalYear, + Notes = vm.Notes, + IsDefault = vm.IsDefault, + CompanyId = companyId, + CreatedAt = DateTime.UtcNow, + Lines = vm.Lines + .Where(l => l.HasAnyAmount) + .Select(l => new BudgetLine + { + AccountId = l.AccountId, + Jan = l.Jan, Feb = l.Feb, Mar = l.Mar, Apr = l.Apr, + May = l.May, Jun = l.Jun, Jul = l.Jul, Aug = l.Aug, + Sep = l.Sep, Oct = l.Oct, Nov = l.Nov, Dec = l.Dec, + CompanyId = companyId, CreatedAt = DateTime.UtcNow + }).ToList() + }; + + await _unitOfWork.Budgets.AddAsync(budget); + await _unitOfWork.CompleteAsync(); + + TempData["Success"] = $"Budget \"{budget.Name}\" created for {budget.FiscalYear}."; + return RedirectToAction(nameof(Edit), new { id = budget.Id }); + } + + // ── Edit ────────────────────────────────────────────────────────────────── + + [HttpGet] + public async Task Edit(int id) + { + var budget = await _unitOfWork.Budgets.GetByIdAsync(id, false, b => b.Lines); + if (budget == null) return NotFound(); + + var accounts = await GetBudgetableAccountsAsync(); + var lineMap = budget.Lines.ToDictionary(l => l.AccountId); + + var vm = new BudgetCreateVm + { + Id = budget.Id, + Name = budget.Name, + FiscalYear = budget.FiscalYear, + Notes = budget.Notes, + IsDefault = budget.IsDefault, + Lines = accounts.Select(a => + { + lineMap.TryGetValue(a.Id, out var existing); + return new BudgetLineVm + { + AccountId = a.Id, + AccountNumber = a.AccountNumber, + AccountName = a.Name, + AccountType = a.AccountType, + Jan = existing?.Jan ?? 0, Feb = existing?.Feb ?? 0, Mar = existing?.Mar ?? 0, + Apr = existing?.Apr ?? 0, May = existing?.May ?? 0, Jun = existing?.Jun ?? 0, + Jul = existing?.Jul ?? 0, Aug = existing?.Aug ?? 0, Sep = existing?.Sep ?? 0, + Oct = existing?.Oct ?? 0, Nov = existing?.Nov ?? 0, Dec = existing?.Dec ?? 0 + }; + }).ToList() + }; + + return View(vm); + } + + [HttpPost, ValidateAntiForgeryToken] + public async Task Edit(int id, BudgetCreateVm vm) + { + if (id != vm.Id) return BadRequest(); + if (!ModelState.IsValid) return View(vm); + + var budget = await _unitOfWork.Budgets.GetByIdAsync(id, false, b => b.Lines); + if (budget == null) return NotFound(); + + var companyId = _tenantContext.GetCurrentCompanyId() ?? 0; + + if (vm.IsDefault && !budget.IsDefault) + await ClearDefaultFlagAsync(companyId, vm.FiscalYear, excludeId: id); + + budget.Name = vm.Name; + budget.Notes = vm.Notes; + budget.IsDefault = vm.IsDefault; + budget.UpdatedAt = DateTime.UtcNow; + + // Delete old lines and replace with new set (simpler than merge) + foreach (var line in budget.Lines.ToList()) + await _unitOfWork.BudgetLines.SoftDeleteAsync(line.Id); + + budget.Lines = vm.Lines + .Where(l => l.HasAnyAmount) + .Select(l => new BudgetLine + { + AccountId = l.AccountId, + Jan = l.Jan, Feb = l.Feb, Mar = l.Mar, Apr = l.Apr, + May = l.May, Jun = l.Jun, Jul = l.Jul, Aug = l.Aug, + Sep = l.Sep, Oct = l.Oct, Nov = l.Nov, Dec = l.Dec, + CompanyId = companyId, CreatedAt = DateTime.UtcNow + }).ToList(); + + await _unitOfWork.CompleteAsync(); + + TempData["Success"] = $"Budget \"{budget.Name}\" saved."; + return RedirectToAction(nameof(Edit), new { id }); + } + + // ── Copy ───────────────────────────────────────────────────────────────── + + /// + /// Creates a copy of an existing budget for a new fiscal year — common workflow for + /// rolling forward last year's budget as a starting point. + /// + [HttpPost, ValidateAntiForgeryToken] + public async Task Copy(int id, int newYear) + { + var source = await _unitOfWork.Budgets.GetByIdAsync(id, false, b => b.Lines); + if (source == null) return NotFound(); + + var companyId = _tenantContext.GetCurrentCompanyId() ?? 0; + var copy = new Budget + { + Name = $"{source.Name} ({newYear})", + FiscalYear = newYear, + Notes = source.Notes, + IsDefault = false, + CompanyId = companyId, + CreatedAt = DateTime.UtcNow, + Lines = source.Lines.Select(l => new BudgetLine + { + AccountId = l.AccountId, + Jan = l.Jan, Feb = l.Feb, Mar = l.Mar, Apr = l.Apr, + May = l.May, Jun = l.Jun, Jul = l.Jul, Aug = l.Aug, + Sep = l.Sep, Oct = l.Oct, Nov = l.Nov, Dec = l.Dec, + CompanyId = companyId, CreatedAt = DateTime.UtcNow + }).ToList() + }; + + await _unitOfWork.Budgets.AddAsync(copy); + await _unitOfWork.CompleteAsync(); + + TempData["Success"] = $"Budget copied to {newYear}."; + return RedirectToAction(nameof(Edit), new { id = copy.Id }); + } + + // ── SetDefault ──────────────────────────────────────────────────────────── + + [HttpPost, ValidateAntiForgeryToken] + public async Task SetDefault(int id) + { + var budget = await _unitOfWork.Budgets.GetByIdAsync(id); + if (budget == null) return NotFound(); + + var companyId = _tenantContext.GetCurrentCompanyId() ?? 0; + await ClearDefaultFlagAsync(companyId, budget.FiscalYear, excludeId: null); + + budget.IsDefault = true; + budget.UpdatedAt = DateTime.UtcNow; + await _unitOfWork.CompleteAsync(); + + TempData["Success"] = $"\"{budget.Name}\" is now the default budget for {budget.FiscalYear}."; + return RedirectToAction(nameof(Index)); + } + + // ── Delete ──────────────────────────────────────────────────────────────── + + [HttpPost, ValidateAntiForgeryToken] + public async Task Delete(int id) + { + var budget = await _unitOfWork.Budgets.GetByIdAsync(id, false, b => b.Lines); + if (budget == null) return NotFound(); + + foreach (var line in budget.Lines.ToList()) + await _unitOfWork.BudgetLines.SoftDeleteAsync(line.Id); + + await _unitOfWork.Budgets.SoftDeleteAsync(id); + await _unitOfWork.CompleteAsync(); + + TempData["Success"] = $"Budget \"{budget.Name}\" deleted."; + return RedirectToAction(nameof(Index)); + } + + // ── Helpers ─────────────────────────────────────────────────────────────── + + private async Task> GetBudgetableAccountsAsync() + { + var accounts = await _unitOfWork.Accounts.FindAsync( + a => a.IsActive && (a.AccountType == AccountType.Revenue || a.AccountType == AccountType.Expense)); + return accounts.OrderBy(a => a.AccountNumber).ToList(); + } + + private async Task ClearDefaultFlagAsync(int companyId, int fiscalYear, int? excludeId) + { + var others = await _unitOfWork.Budgets.FindAsync( + b => b.IsDefault && b.FiscalYear == fiscalYear && b.Id != (excludeId ?? 0)); + foreach (var b in others) + { + b.IsDefault = false; + b.UpdatedAt = DateTime.UtcNow; + } + if (others.Any()) + await _unitOfWork.CompleteAsync(); + } +} + +// ── View Models ─────────────────────────────────────────────────────────────── + +public class BudgetCreateVm +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + public int FiscalYear { get; set; } = DateTime.Now.Year; + public string? Notes { get; set; } + public bool IsDefault { get; set; } = true; + public List Lines { get; set; } = new(); +} + +public class BudgetLineVm +{ + public int AccountId { get; set; } + public string AccountNumber { get; set; } = string.Empty; + public string AccountName { get; set; } = string.Empty; + public AccountType AccountType { get; set; } + + public decimal Jan { get; set; } + public decimal Feb { get; set; } + public decimal Mar { get; set; } + public decimal Apr { get; set; } + public decimal May { get; set; } + public decimal Jun { get; set; } + public decimal Jul { get; set; } + public decimal Aug { get; set; } + public decimal Sep { get; set; } + public decimal Oct { get; set; } + public decimal Nov { get; set; } + public decimal Dec { get; set; } + + public decimal Annual => Jan + Feb + Mar + Apr + May + Jun + Jul + Aug + Sep + Oct + Nov + Dec; + public bool HasAnyAmount => Annual != 0; +} diff --git a/src/PowderCoating.Web/Controllers/ReportsController.cs b/src/PowderCoating.Web/Controllers/ReportsController.cs index 2c54bd8..8747bc8 100644 --- a/src/PowderCoating.Web/Controllers/ReportsController.cs +++ b/src/PowderCoating.Web/Controllers/ReportsController.cs @@ -2118,6 +2118,91 @@ public class ReportsController : Controller } } + // GET: /Reports/BudgetVsActual + /// + /// Budget vs. Actual report: compares a budget's monthly line amounts against real P&L activity + /// for the same period. Actual figures come from the same GL queries used by the P&L report. + /// If no budgetId is specified, the default budget for the selected year is used automatically. + /// + public async Task BudgetVsActual(int? budgetId, int? year) + { + if (!AllowAccounting()) return RedirectToAction(nameof(Landing)); + + var companyId = int.TryParse(User.FindFirst("CompanyId")?.Value, out var _bvaid) ? _bvaid : 0; + var reportYear = year ?? DateTime.Now.Year; + + // Load all budgets for the year for the selector + var allBudgets = (await _unitOfWork.Budgets.FindAsync(b => b.FiscalYear == reportYear)) + .OrderBy(b => b.Name).ToList(); + + Core.Entities.Budget? budget = null; + if (budgetId.HasValue) + budget = await _unitOfWork.Budgets.GetByIdAsync(budgetId.Value, false, b => b.Lines); + + budget ??= (await _unitOfWork.Budgets.FindAsync( + b => b.FiscalYear == reportYear && b.IsDefault, false, b => b.Lines)).FirstOrDefault(); + + budget ??= (await _unitOfWork.Budgets.FindAsync( + b => b.FiscalYear == reportYear, false, b => b.Lines)).FirstOrDefault(); + + ViewBag.ReportYear = reportYear; + ViewBag.Budget = budget; + ViewBag.AllBudgets = allBudgets; + ViewBag.AvailableYears = Enumerable.Range(DateTime.Now.Year - 4, 6).OrderDescending().ToList(); + + if (budget == null) + { + ViewBag.NoBudget = true; + return View(new List()); + } + + // Fetch one P&L per month (12 calls); build a flat dict: accountId → decimal[12] + var actualByAccount = new Dictionary(); + for (int m = 1; m <= 12; m++) + { + var mFrom = new DateTime(reportYear, m, 1); + var mTo = new DateTime(reportYear, m, DateTime.DaysInMonth(reportYear, m)); + var mpl = await _financialReports.GetProfitAndLossAsync(companyId, mFrom, mTo); + + var allPLLines = mpl.RevenueLines + .Concat(mpl.CogsLines) + .Concat(mpl.ExpenseLines); + + foreach (var pll in allPLLines) + { + if (!actualByAccount.ContainsKey(pll.AccountId)) + actualByAccount[pll.AccountId] = new decimal[12]; + actualByAccount[pll.AccountId][m - 1] = pll.Amount; + } + } + + // Load account metadata for budget lines + var accountIds = budget.Lines.Select(l => l.AccountId).Distinct().ToList(); + var accounts = (await _unitOfWork.Accounts.FindAsync(a => accountIds.Contains(a.Id))) + .ToDictionary(a => a.Id); + + var rows = new List(); + foreach (var line in budget.Lines) + { + if (!accounts.TryGetValue(line.AccountId, out var acct)) continue; + + actualByAccount.TryGetValue(line.AccountId, out var monthlyActuals); + monthlyActuals ??= new decimal[12]; + + rows.Add(new BudgetVsActualRow + { + AccountId = acct.Id, + AccountNumber = acct.AccountNumber, + AccountName = acct.Name, + AccountType = acct.AccountType, + BudgetMonths = new[] { line.Jan, line.Feb, line.Mar, line.Apr, line.May, line.Jun, line.Jul, line.Aug, line.Sep, line.Oct, line.Nov, line.Dec }, + ActualMonths = monthlyActuals + }); + } + + return View(rows.OrderBy(r => r.AccountNumber).ToList()); + } + // GET: /Reports/TaxReporting1099 /// /// 1099-NEC report: sums all bill payments + expenses paid to vendors marked Is1099Vendor=true @@ -2307,6 +2392,20 @@ public class AnalyticsDashboardViewModel public int SelectedMonths { get; set; } = 6; } +public class BudgetVsActualRow +{ + public int AccountId { get; set; } + public string AccountNumber { get; set; } = string.Empty; + public string AccountName { get; set; } = string.Empty; + public AccountType AccountType { get; set; } + public decimal[] BudgetMonths { get; set; } = new decimal[12]; + public decimal[] ActualMonths { get; set; } = new decimal[12]; + + public decimal BudgetAnnual => BudgetMonths.Sum(); + public decimal ActualAnnual => ActualMonths.Sum(); + public decimal VarianceAnnual => ActualAnnual - BudgetAnnual; +} + public class Vendor1099Row { public int VendorId { get; set; } diff --git a/src/PowderCoating.Web/Views/Accounts/YearEndClose.cshtml b/src/PowderCoating.Web/Views/Accounts/YearEndClose.cshtml new file mode 100644 index 0000000..144ac24 --- /dev/null +++ b/src/PowderCoating.Web/Views/Accounts/YearEndClose.cshtml @@ -0,0 +1,124 @@ +@using PowderCoating.Core.Entities +@{ + ViewData["Title"] = "Year-End Close"; + ViewData["PageIcon"] = "bi-calendar-check"; + var history = ViewBag.History as List ?? new(); + var suggested = (int)ViewBag.SuggestedYear; + var closedYears = ViewBag.ClosedYears as HashSet ?? new(); +} + +
+
+ + @if (TempData["Success"] != null) + { + + } + @if (TempData["Error"] != null) + { + + } + +
+
+
Close a Fiscal Year
+
+
+
+ + What this does: Posts a Journal Entry dated December 31 that zeroes all Revenue + and Expense account balances into Retained Earnings — the standard accounting close. + Run this after all entries for the year are posted and the period is locked. + A year can only be closed once. +
+ +
+ @Html.AntiForgeryToken() +
+
+ + +
All entries for this year should be finalized before closing.
+
+
+ +
+
+
+ +
+
Pre-close checklist:
+
    +
  • All invoices for the year are sent and collected (or written off)
  • +
  • All vendor bills are entered and paid
  • +
  • Bank reconciliation is complete through December
  • +
  • Depreciation is posted for all 12 months
  • +
  • Trial Balance is in balance (debits = credits)
  • +
  • Period is locked through December 31 in Company Settings
  • +
+
+
+
+ + +
+
+
Close History
+
+
+ @if (!history.Any()) + { +
+

No years have been closed yet.

+
+ } + else + { + + + + + + + + + + + @foreach (var c in history) + { + + + + + + + } + +
Fiscal YearClosed OnClosed ByJournal Entry
@c.ClosedYear@c.ClosedAt.ToLocalTime().ToString("MM/dd/yyyy h:mm tt")@(c.ClosedBy ?? "—") + @if (c.JournalEntry != null) + { + + @c.JournalEntry.EntryNumber + + } + else + { + #@c.JournalEntryId + } +
+ } +
+
+ +
+
diff --git a/src/PowderCoating.Web/Views/Budgets/Create.cshtml b/src/PowderCoating.Web/Views/Budgets/Create.cshtml new file mode 100644 index 0000000..546189a --- /dev/null +++ b/src/PowderCoating.Web/Views/Budgets/Create.cshtml @@ -0,0 +1,118 @@ +@using PowderCoating.Web.Controllers +@model BudgetCreateVm + +@{ + ViewData["Title"] = "New Budget"; + ViewData["PageIcon"] = "bi-plus-circle"; + var months = new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +} + + + +
+ @Html.AntiForgeryToken() + +
+
+
Budget Details
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+
+ +
+
+
Monthly Amounts by Account
+
+ +
+
+
+
+ + + + + + @foreach (var m in months) + { + + } + + + + @for (int i = 0; i < Model.Lines.Count; i++) + { + var line = Model.Lines[i]; + + + + @{ + var fieldNames = new[] { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; + var values = new decimal[] { line.Jan, line.Feb, line.Mar, line.Apr, line.May, line.Jun, line.Jul, line.Aug, line.Sep, line.Oct, line.Nov, line.Dec }; + } + @for (int m = 0; m < 12; m++) + { + + } + + } + +
AccountAnnual@m
+ + + + + @line.AccountNumber + @line.AccountName + + 0.00 + + +
+
+
+
+ +
+ + Cancel +
+
+ +@section Scripts { + +} diff --git a/src/PowderCoating.Web/Views/Budgets/Edit.cshtml b/src/PowderCoating.Web/Views/Budgets/Edit.cshtml new file mode 100644 index 0000000..61487a0 --- /dev/null +++ b/src/PowderCoating.Web/Views/Budgets/Edit.cshtml @@ -0,0 +1,164 @@ +@using PowderCoating.Web.Controllers +@model BudgetCreateVm + +@{ + ViewData["Title"] = $"Edit Budget — {Model.Name}"; + ViewData["PageIcon"] = "bi-pencil"; + var months = new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +} + + + +
+ @Html.AntiForgeryToken() + + + +
+
+
+ @Model.Name — @Model.FiscalYear +
+
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+
+ +
+
+
Monthly Amounts by Account
+
+ +
+
+
+ + Enter monthly amounts for each Revenue and Expense account. Leave a row at zero to exclude that account from the budget. Amounts represent expected activity for the period (not running totals). +
+
+
+ + + + + + @foreach (var m in months) + { + + } + + + + @{ + var revLines = Model.Lines.Where(l => l.AccountType == PowderCoating.Core.Enums.AccountType.Revenue).ToList(); + var expLines = Model.Lines.Where(l => l.AccountType != PowderCoating.Core.Enums.AccountType.Revenue).ToList(); + var fieldNames = new[] { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; + } + + @if (revLines.Any()) + { + + + + @for (int i = 0; i < Model.Lines.Count; i++) + { + var line = Model.Lines[i]; + if (line.AccountType != PowderCoating.Core.Enums.AccountType.Revenue) continue; + var values = new decimal[] { line.Jan, line.Feb, line.Mar, line.Apr, line.May, line.Jun, line.Jul, line.Aug, line.Sep, line.Oct, line.Nov, line.Dec }; + + + + @for (int m = 0; m < 12; m++) + { + + } + + } + } + + @if (expLines.Any()) + { + + + + @for (int i = 0; i < Model.Lines.Count; i++) + { + var line = Model.Lines[i]; + if (line.AccountType == PowderCoating.Core.Enums.AccountType.Revenue) continue; + var values = new decimal[] { line.Jan, line.Feb, line.Mar, line.Apr, line.May, line.Jun, line.Jul, line.Aug, line.Sep, line.Oct, line.Nov, line.Dec }; + + + + @for (int m = 0; m < 12; m++) + { + + } + + } + } + +
AccountAnnual@m
REVENUE
+ + + + + @line.AccountNumber + @line.AccountName + @line.Annual.ToString("N2") + +
EXPENSE
+ + + + + @line.AccountNumber + @line.AccountName + @line.Annual.ToString("N2") + +
+
+
+
+ +
+ + Cancel +
+
+ +@section Scripts { + +} diff --git a/src/PowderCoating.Web/Views/Budgets/Index.cshtml b/src/PowderCoating.Web/Views/Budgets/Index.cshtml new file mode 100644 index 0000000..484ea50 --- /dev/null +++ b/src/PowderCoating.Web/Views/Budgets/Index.cshtml @@ -0,0 +1,152 @@ +@using PowderCoating.Core.Entities +@model List + +@{ + ViewData["Title"] = "Budgets"; + ViewData["PageIcon"] = "bi-pie-chart"; + var byYear = Model.GroupBy(b => b.FiscalYear).OrderByDescending(g => g.Key).ToList(); +} + + + +@if (TempData["Success"] != null) +{ + +} +@if (TempData["Error"] != null) +{ + +} + +@if (!Model.Any()) +{ +
+
+ +

No budgets yet. Create your first budget to start tracking variance against actual results.

+
+
+} +else +{ + @foreach (var group in byYear) + { +
+
+
Fiscal Year @group.Key
+
+
+ + + + + + + + + + + + + @foreach (var b in group.OrderBy(b => b.Name)) + { + var revLines = b.Lines.Where(l => l.Account?.AccountType == PowderCoating.Core.Enums.AccountType.Revenue); + var expLines = b.Lines.Where(l => l.Account?.AccountType == PowderCoating.Core.Enums.AccountType.Expense); + + + + + + + + + } + +
Budget NameLinesTotal Revenue BudgetTotal Expense BudgetDefault
+ @b.Name + @if (!string.IsNullOrWhiteSpace(b.Notes)) + { +
@b.Notes
+ } +
@b.Lines.Count@b.Lines.Sum(l => l.Annual).ToString("C") + @if (b.IsDefault) + { + Default + } + else + { +
+ @Html.AntiForgeryToken() + +
+ } +
+
+ + + + +
+ @Html.AntiForgeryToken() + +
+
+
+
+
+ } +} + + + + +@section Scripts { + +} diff --git a/src/PowderCoating.Web/Views/Reports/BudgetVsActual.cshtml b/src/PowderCoating.Web/Views/Reports/BudgetVsActual.cshtml new file mode 100644 index 0000000..60a1c8d --- /dev/null +++ b/src/PowderCoating.Web/Views/Reports/BudgetVsActual.cshtml @@ -0,0 +1,235 @@ +@using PowderCoating.Web.Controllers +@using PowderCoating.Core.Enums +@model List + +@{ + ViewData["Title"] = "Budget vs. Actual"; + ViewData["PageIcon"] = "bi-bar-chart-line"; + var reportYear = (int)ViewBag.ReportYear; + var budget = ViewBag.Budget as PowderCoating.Core.Entities.Budget; + var allBudgets = ViewBag.AllBudgets as List ?? new(); + var noBudget = ViewBag.NoBudget == true; + var availYears = ViewBag.AvailableYears as List ?? new(); + var months = new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +} + +
+
+ + @if (allBudgets.Count > 1) + { + + } +
+ +
+ +@if (noBudget || budget == null) +{ +
+
+ +

No budget found for @reportYear.

+ + Create Budget for @reportYear + +
+
+} +else +{ + var revRows = Model.Where(r => r.AccountType == AccountType.Revenue).ToList(); + var expRows = Model.Where(r => r.AccountType != AccountType.Revenue).ToList(); + var totalBudgetRev = revRows.Sum(r => r.BudgetAnnual); + var totalActualRev = revRows.Sum(r => r.ActualAnnual); + var totalBudgetExp = expRows.Sum(r => r.BudgetAnnual); + var totalActualExp = expRows.Sum(r => r.ActualAnnual); + var budgetNetIncome = totalBudgetRev - totalBudgetExp; + var actualNetIncome = totalActualRev - totalActualExp; + + +
+
+
+
+
Budget Revenue
+
@totalBudgetRev.ToString("C")
+
+
+
+
+
+
+
Actual Revenue
+
@totalActualRev.ToString("C")
+
+
+
+
+
+
+
Budget Net Income
+
@budgetNetIncome.ToString("C")
+
+
+
+
+
+
+
Actual Net Income
+
@actualNetIncome.ToString("C")
+
+
+
+
+ +
+
+
+ @budget.Name — @reportYear +
+
+
+
+ + + + + + + + @foreach (var m in months) + { + + } + + + + @if (revRows.Any()) + { + + + + @foreach (var row in revRows) + { + var varA = row.VarianceAnnual; + + + + + + @for (int m = 0; m < 12; m++) + { + var varM = row.ActualMonths[m] - row.BudgetMonths[m]; + + } + + } + + + + + + @for (int m = 0; m < 12; m++) + { + + } + + } + @if (expRows.Any()) + { + + + + @foreach (var row in expRows) + { + var varA = row.BudgetAnnual - row.ActualAnnual; // favorable if under budget + + + + + + @for (int m = 0; m < 12; m++) + { + var varM = row.BudgetMonths[m] - row.ActualMonths[m]; + + } + + } + + + + + + @for (int m = 0; m < 12; m++) + { + + } + + } + + + + + + + @for (int m = 0; m < 12; m++) + { + var mActualNet = revRows.Sum(r => r.ActualMonths[m]) - expRows.Sum(r => r.ActualMonths[m]); + + } + + +
AccountBudget AnnualActual AnnualVariance@m
REVENUE
+ @row.AccountNumber + @row.AccountName + @row.BudgetAnnual.ToString("C")@row.ActualAnnual.ToString("C") + @(varA >= 0 ? "+" : "")@varA.ToString("C") + + @row.ActualMonths[m].ToString("N0") +
Total Revenue@totalBudgetRev.ToString("C")@totalActualRev.ToString("C") + @{var revVar = totalActualRev - totalBudgetRev;} + @(revVar >= 0 ? "+" : "")@revVar.ToString("C") + @revRows.Sum(r => r.ActualMonths[m]).ToString("N0")
EXPENSE
+ @row.AccountNumber + @row.AccountName + @row.BudgetAnnual.ToString("C")@row.ActualAnnual.ToString("C") + @(varA >= 0 ? "+" : "")@varA.ToString("C") + + @row.ActualMonths[m].ToString("N0") +
Total Expenses@totalBudgetExp.ToString("C")@totalActualExp.ToString("C") + @{var expVar = totalBudgetExp - totalActualExp;} + @(expVar >= 0 ? "+" : "")@expVar.ToString("C") + @expRows.Sum(r => r.ActualMonths[m]).ToString("N0")
Net Income@budgetNetIncome.ToString("C")@actualNetIncome.ToString("C") + @{var netVar = actualNetIncome - budgetNetIncome;} + @(netVar >= 0 ? "+" : "")@netVar.ToString("C") + @mActualNet.ToString("N0")
+
+
+
+ +
+ + Variance is shown as favorable (positive) when revenue exceeds budget or expenses are under budget. + Actual figures reflect the P&L for each calendar month. +
+} diff --git a/src/PowderCoating.Web/Views/Reports/Landing.cshtml b/src/PowderCoating.Web/Views/Reports/Landing.cshtml index 3090db7..786d09d 100644 --- a/src/PowderCoating.Web/Views/Reports/Landing.cshtml +++ b/src/PowderCoating.Web/Views/Reports/Landing.cshtml @@ -220,6 +220,14 @@

Payments to 1099-eligible vendors by calendar year — flags those exceeding the $600 reporting threshold.

Open report
+ +
+ +
+
Budget vs. Actual
+

Compare monthly budgeted amounts against real P&L activity — revenue, expenses, and net income variance.

+
Open report
+
} diff --git a/src/PowderCoating.Web/Views/Shared/_Layout.cshtml b/src/PowderCoating.Web/Views/Shared/_Layout.cshtml index 2110669..b8fdcdd 100644 --- a/src/PowderCoating.Web/Views/Shared/_Layout.cshtml +++ b/src/PowderCoating.Web/Views/Shared/_Layout.cshtml @@ -1150,6 +1150,14 @@ Fixed Assets + + + Budgets + + + + Year-End Close + Recurring Transactions diff --git a/src/PowderCoating.Web/wwwroot/js/budget-edit.js b/src/PowderCoating.Web/wwwroot/js/budget-edit.js new file mode 100644 index 0000000..9a3d031 --- /dev/null +++ b/src/PowderCoating.Web/wwwroot/js/budget-edit.js @@ -0,0 +1,32 @@ +document.addEventListener('DOMContentLoaded', function () { + // Update row annual totals as cells change + function updateRowTotal(rowIdx) { + var cells = document.querySelectorAll('.budget-cell[data-row="' + rowIdx + '"]'); + var sum = 0; + cells.forEach(function (c) { sum += parseFloat(c.value) || 0; }); + var span = document.querySelector('.annual-total[data-row="' + rowIdx + '"]'); + if (span) span.textContent = sum.toFixed(2); + } + + document.querySelectorAll('.budget-cell').forEach(function (input) { + var row = input.getAttribute('data-row'); + updateRowTotal(row); + input.addEventListener('input', function () { updateRowTotal(row); }); + }); + + // "Spread Annual Evenly" — prompts annual amount and distributes equally across 12 months + var fillBtn = document.getElementById('fillEvenlyBtn'); + if (fillBtn) { + fillBtn.addEventListener('click', function () { + var annual = parseFloat(prompt('Enter the annual amount to spread evenly across all months for ALL rows (overwrites existing):')); + if (isNaN(annual)) return; + var monthly = (annual / 12).toFixed(2); + var allRows = new Set(); + document.querySelectorAll('.budget-cell').forEach(function (c) { + c.value = monthly; + allRows.add(c.getAttribute('data-row')); + }); + allRows.forEach(function (r) { updateRowTotal(r); }); + }); + } +}); diff --git a/src/PowderCoating.Web/wwwroot/js/budget-index.js b/src/PowderCoating.Web/wwwroot/js/budget-index.js new file mode 100644 index 0000000..89229f3 --- /dev/null +++ b/src/PowderCoating.Web/wwwroot/js/budget-index.js @@ -0,0 +1,10 @@ +document.addEventListener('DOMContentLoaded', function () { + var copyModal = document.getElementById('copyModal'); + if (copyModal) { + copyModal.addEventListener('show.bs.modal', function (e) { + var btn = e.relatedTarget; + document.getElementById('copyBudgetId').value = btn.getAttribute('data-budget-id'); + document.getElementById('copyBudgetName').textContent = btn.getAttribute('data-budget-name'); + }); + } +});