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; }
///
/// 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.
///
[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
/// Whether markup is applied to material only, or margin is applied to total item cost.
public PricingMode PricingMode { get; set; } = PricingMode.MarkupOnMaterial;
/// Markup % added on top of material costs (used when PricingMode = MarkupOnMaterial).
[Range(0, 100)]
public decimal GeneralMarkupPercentage { get; set; }
/// Target gross margin % applied to total item cost (used when PricingMode = MarginOnTotalCost).
[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;
///
/// 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."
///
[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.
/// Broad capability tier chosen in Setup Wizard; sets sensible defaults for all fields below.
public ShopCapabilityTier ShopCapabilityTier { get; set; } = ShopCapabilityTier.Small;
/// Type of blasting setup — biggest single factor in blast throughput.
public BlastSetupType BlastSetupType { get; set; } = BlastSetupType.SiphonCabinet;
/// Compressor CFM available for the blast setup.
[Range(0, 2000)]
public decimal CompressorCfm { get; set; } = 0m;
/// Blast nozzle size (#3 – #8). Larger nozzle = more media flow.
[Range(3, 8)]
public int BlastNozzleSize { get; set; } = 4;
/// Primary substrate being removed; affects passes required per sqft.
public BlastSubstrateType PrimaryBlastSubstrate { get; set; } = BlastSubstrateType.Mixed;
///
/// Manual blast rate override (sqft/hr). When set, the formula is bypassed entirely.
/// Useful for dialed-in shops who know their exact throughput.
///
[Range(0, 5000)]
public decimal? BlastRateSqFtPerHourOverride { get; set; }
/// Coating gun technology — affects application speed on complex parts.
public CoatingGunType CoatingGunType { get; set; } = CoatingGunType.Corona;
///
/// Manual coating application rate override (sqft/hr). When set, bypasses the formula.
///
[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.
/// Monthly shop lease / rent payment.
[Range(0, 1000000)]
public decimal MonthlyRent { get; set; } = 0m;
/// Monthly utilities combined (electricity, gas, water, internet).
[Range(0, 1000000)]
public decimal MonthlyUtilities { get; set; } = 0m;
///
/// 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.
///
[Range(1, 10000)]
public int MonthlyBillableHours { get; set; } = 160;
}
}