Files
PowderCoatingLogix/src/PowderCoating.Core/Entities/CompanyOperatingCosts.cs
T
spouliot 1a44133a63 Remove ShopWorker entity and migrate worker identity to ApplicationUser
Removes the ShopWorker and ShopWorkerRoleCost entities, all related DTOs,
mappings, controllers, views, and import/export paths. Worker identity is
now handled entirely through ApplicationUser with per-user LaborCostPerHour.
ShopWorkerRoleCosts table remains in production pending manual data migration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 20:32:32 -04:00

159 lines
6.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.ComponentModel.DataAnnotations;
using PowderCoating.Core.Enums;
namespace PowderCoating.Core.Entities
{
public class CompanyOperatingCosts : BaseEntity
{
// Navigation
public new int CompanyId { get; set; }
public virtual Company Company { get; set; } = null!;
// Labor Rates (per hour, in currency)
[Range(0, 10000)]
public decimal StandardLaborRate { get; set; }
/// <summary>
/// Actual labor cost per hour (wages + burden) used exclusively for internal job costing and profit/margin display.
/// This is NOT the billing rate — it should reflect what you actually pay workers.
/// When null, the costing engine defaults to 20% of StandardLaborRate.
/// </summary>
[Range(0, 10000)]
public decimal? LaborCostPerHour { get; set; }
// Additional Coat Labor Percentage (percentage of base labor for each additional coat beyond the first)
[Range(0, 100)]
public decimal AdditionalCoatLaborPercent { get; set; } = 30m;
// Equipment Operating Costs (per hour)
[Range(0, 10000)]
public decimal OvenOperatingCostPerHour { get; set; }
[Range(0, 10000)]
public decimal SandblasterCostPerHour { get; set; }
[Range(0, 10000)]
public decimal CoatingBoothCostPerHour { get; set; }
// Material Costs
[Range(0, 1000)]
public decimal PowderCoatingCostPerSqFt { get; set; } // per square foot
// Markup / Margin
/// <summary>Whether markup is applied to material only, or margin is applied to total item cost.</summary>
public PricingMode PricingMode { get; set; } = PricingMode.MarkupOnMaterial;
/// <summary>Markup % added on top of material costs (used when PricingMode = MarkupOnMaterial).</summary>
[Range(0, 100)]
public decimal GeneralMarkupPercentage { get; set; }
/// <summary>Target gross margin % applied to total item cost (used when PricingMode = MarginOnTotalCost).</summary>
[Range(0, 99)]
public decimal TargetMarginPercent { get; set; }
// Tax Percentage
[Range(0, 100)]
public decimal TaxPercent { get; set; }
// Shop Supplies Rate (percentage applied to materials/labor)
[Range(0, 100)]
public decimal ShopSuppliesRate { get; set; }
// Oven batch defaults
[Range(1, 1440)]
public int DefaultOvenCycleMinutes { get; set; } = 45;
// Rush Charge
public string RushChargeType { get; set; } = "Percentage"; // "Percentage" or "FixedAmount"
[Range(0, 100)]
public decimal RushChargePercentage { get; set; }
[Range(0, 100000)]
public decimal RushChargeFixedAmount { get; set; }
// Shop Minimum
[Range(0, 100000)]
public decimal ShopMinimumCharge { get; set; }
// Part Complexity Multipliers (% added to calculated item price)
[Range(0, 500)]
public decimal ComplexitySimplePercent { get; set; } = 0m;
[Range(0, 500)]
public decimal ComplexityModeratePercent { get; set; } = 5m;
[Range(0, 500)]
public decimal ComplexityComplexPercent { get; set; } = 15m;
[Range(0, 500)]
public decimal ComplexityExtremePercent { get; set; } = 25m;
/// <summary>
/// Free-text description of this shop's specialties, typical item types, and pricing style.
/// Injected into the AI system prompt so the model can calibrate estimates for this company.
/// Example: "We specialize in automotive restoration parts — wheels, frames, brackets.
/// We charge premium rates and rarely work on items over 20 sqft."
/// </summary>
[StringLength(2000)]
public string? AiContextProfile { get; set; }
// ── Shop Capability / Quoting Calibration ─────────────────────────────────────
// These fields drive the derived BlastRateSqFtPerHour used in AI photo quoting
// and calculated item time suggestions. The Override field lets a shop bypass the
// formula and enter their real-world number directly.
/// <summary>Broad capability tier chosen in Setup Wizard; sets sensible defaults for all fields below.</summary>
public ShopCapabilityTier ShopCapabilityTier { get; set; } = ShopCapabilityTier.Small;
/// <summary>Type of blasting setup — biggest single factor in blast throughput.</summary>
public BlastSetupType BlastSetupType { get; set; } = BlastSetupType.SiphonCabinet;
/// <summary>Compressor CFM available for the blast setup.</summary>
[Range(0, 2000)]
public decimal CompressorCfm { get; set; } = 0m;
/// <summary>Blast nozzle size (#3 #8). Larger nozzle = more media flow.</summary>
[Range(3, 8)]
public int BlastNozzleSize { get; set; } = 4;
/// <summary>Primary substrate being removed; affects passes required per sqft.</summary>
public BlastSubstrateType PrimaryBlastSubstrate { get; set; } = BlastSubstrateType.Mixed;
/// <summary>
/// Manual blast rate override (sqft/hr). When set, the formula is bypassed entirely.
/// Useful for dialed-in shops who know their exact throughput.
/// </summary>
[Range(0, 5000)]
public decimal? BlastRateSqFtPerHourOverride { get; set; }
/// <summary>Coating gun technology — affects application speed on complex parts.</summary>
public CoatingGunType CoatingGunType { get; set; } = CoatingGunType.Corona;
/// <summary>
/// Manual coating application rate override (sqft/hr). When set, bypasses the formula.
/// </summary>
[Range(0, 5000)]
public decimal? CoatingRateSqFtPerHourOverride { get; set; }
// ── Facility Overhead ─────────────────────────────────────────────────────
// Monthly fixed costs divided by billable hours to derive a per-hour overhead
// rate, which is then applied to each quote based on estimated labor time.
/// <summary>Monthly shop lease / rent payment.</summary>
[Range(0, 1000000)]
public decimal MonthlyRent { get; set; } = 0m;
/// <summary>Monthly utilities combined (electricity, gas, water, internet).</summary>
[Range(0, 1000000)]
public decimal MonthlyUtilities { get; set; } = 0m;
/// <summary>
/// Estimated billable shop hours per month used to amortise facility overhead.
/// Defaults to 160 (4 weeks × 40 hrs). Must be at least 1 to avoid division by zero.
/// </summary>
[Range(1, 10000)]
public int MonthlyBillableHours { get; set; } = 160;
}
}