Files
PowderCoatingLogix/src/PowderCoating.Core/Entities/QuoteItemCoat.cs
T
spouliot 2bf8871892 Fix NoExtraLayerCharge persistence, appointment reminders, coat notes display, scroll restoration, and invoice Send dead-button
- Appointment reminders: add AppointmentReminderBackgroundService (60s poll), ReminderSentAt
  dedup stamp, NotifyAppointmentReminderAsync sends both customer email and creator staff email;
  AppointmentReminderStaff notification type + default template added; DateTime.Now used instead
  of UtcNow to match locally-stored ScheduledStartTime; ToLocalTime() double-conversion removed

- NoExtraLayerCharge not persisted: flag existed on CreateQuoteItemCoatDto and was used by
  pricing engine but never written to JobItemCoat/QuoteItemCoat entities — every edit reset it
  to false and re-applied the extra layer charge; added column to both entities (migration
  AddNoExtraLayerChargeToCoats), both read DTOs, all 3 JobItemAssemblyService overloads,
  JobItemCoatSeed inner class, and existingItemsData JSON in all 5 wizard views; fixed JS
  template path that hard-coded noExtraLayerCharge: false

- Coat notes not visible: notes were rendered in desktop job details but missing from the wizard
  item card summary and the mobile card view; both fixed

- Scroll position lost on item save: sessionStorage save/restore added to item-wizard.js owner
  form submit handler; path-keyed so cross-page navigation does not restore stale position;
  requestAnimationFrame used for reliable mobile scroll restoration

- Invoice Send dead button: #sendChannelModal was gated inside @if (isDraft) but the button
  targeting it fires for Sent/Overdue invoices too when customer has both email and SMS; modal
  moved outside the Draft guard

- InitialCreate migration added for fresh database installs; Baseline migration guarded with
  IF OBJECT_ID check so it no-ops on fresh DBs; Razor scoping bug fixed in Customers/Index.cshtml

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

51 lines
2.0 KiB
C#

namespace PowderCoating.Core.Entities;
/// <summary>
/// Represents a single coating layer applied to a quote item.
/// Supports multi-coat configurations (primer, base coat, top coat, clear coat, etc.)
/// </summary>
public class QuoteItemCoat : BaseEntity
{
// Parent relationship
public int QuoteItemId { get; set; }
// Coat identification (user-defined)
public string CoatName { get; set; } = string.Empty; // "Primer", "Base Coat", "Top Coat", etc.
public int Sequence { get; set; } // 1, 2, 3... for ordering
// Powder selection (same pattern as current QuoteItem)
public int? InventoryItemId { get; set; } // In-stock powder
public string? ColorName { get; set; } // Color name
public int? VendorId { get; set; } // Vendor for custom powder
public string? ColorCode { get; set; } // RAL code, etc.
public string? Finish { get; set; } // Gloss, Matte, Textured, etc.
// Coverage parameters (defaults from inventory or user-specified)
public decimal CoverageSqFtPerLb { get; set; } = 30m;
public decimal TransferEfficiency { get; set; } = 65m;
// Cost override for custom powder
public decimal? PowderCostPerLb { get; set; } // $/lb for custom orders
public decimal? PowderToOrder { get; set; } // Pounds to order (rounded up from needed)
// Calculated costs (stored for audit trail)
public decimal CoatMaterialCost { get; set; }
public decimal CoatLaborCost { get; set; }
public decimal CoatTotalCost { get; set; }
// Pricing flags
/// <summary>
/// When true, the additional layer labor charge is not applied for this coat even if it is
/// not the first coat in the sequence. Used for clear coats, sealers, etc.
/// </summary>
public bool NoExtraLayerCharge { get; set; }
// Notes
public string? Notes { get; set; }
// Navigation properties
public virtual QuoteItem QuoteItem { get; set; } = null!;
public virtual InventoryItem? InventoryItem { get; set; }
public virtual Vendor? Vendor { get; set; }
}