Initial commit
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
using PowderCoating.Core.Entities;
|
||||
|
||||
namespace PowderCoating.Web.ViewModels;
|
||||
|
||||
public class OnlinePaymentsViewModel
|
||||
{
|
||||
public DateTime From { get; set; }
|
||||
public DateTime To { get; set; }
|
||||
public decimal TotalCollected { get; set; }
|
||||
public decimal TotalRefunded { get; set; }
|
||||
public decimal SurchargesCollected { get; set; }
|
||||
public decimal NetRevenue => TotalCollected - TotalRefunded;
|
||||
public List<Invoice> Invoices { get; set; } = new();
|
||||
public List<Refund> Refunds { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
namespace PowderCoating.Web.ViewModels;
|
||||
|
||||
public class QuoteApprovalViewModel
|
||||
{
|
||||
public string Token { get; set; } = string.Empty;
|
||||
public string QuoteNumber { get; set; } = string.Empty;
|
||||
public string CompanyName { get; set; } = string.Empty;
|
||||
public string? CompanyPhone { get; set; }
|
||||
public string? CompanyEmail { get; set; }
|
||||
public bool CompanyHasLogo { get; set; }
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public string? CustomerEmail { get; set; }
|
||||
public DateTime? ExpirationDate { get; set; }
|
||||
public DateTime? ApprovalTokenExpiresAt { get; set; }
|
||||
public decimal SubTotal { get; set; }
|
||||
public decimal DiscountAmount { get; set; }
|
||||
public bool HideDiscountFromCustomer { get; set; }
|
||||
public decimal RushFee { get; set; }
|
||||
public decimal TaxAmount { get; set; }
|
||||
public decimal Total { get; set; }
|
||||
public string? Terms { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? SpecialInstructions { get; set; }
|
||||
public List<QuoteApprovalItemViewModel> Items { get; set; } = new();
|
||||
public string? DeclineError { get; set; }
|
||||
// For AlreadyActed view
|
||||
public string? CurrentStatus { get; set; }
|
||||
public string? DeclineReason { get; set; }
|
||||
|
||||
// Deposit payment link (shown on Confirmation page after approval)
|
||||
public bool RequiresDeposit { get; set; }
|
||||
public decimal DepositPercent { get; set; }
|
||||
public decimal DepositAmount { get; set; } // pre-calculated: Total * DepositPercent/100
|
||||
public string? DepositPaymentLinkToken { get; set; }
|
||||
public decimal DepositAmountPaid { get; set; }
|
||||
|
||||
// Prospect details collection
|
||||
public bool IsProspect { get; set; }
|
||||
public string? ProspectContactName { get; set; }
|
||||
public string? ProspectEmail { get; set; }
|
||||
public string? ProspectPhone { get; set; }
|
||||
public string? ProspectCompanyName { get; set; }
|
||||
public string? ProspectAddress { get; set; }
|
||||
public string? ProspectCity { get; set; }
|
||||
public string? ProspectState { get; set; }
|
||||
public string? ProspectZipCode { get; set; }
|
||||
}
|
||||
|
||||
public class QuoteApprovalItemViewModel
|
||||
{
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public decimal Quantity { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
public decimal TotalPrice { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class CustomerOverviewViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<string> MonthLabels { get; set; } = new();
|
||||
public List<int> NewCustomersPerMonth { get; set; } = new();
|
||||
public decimal CustomerRetentionRate { get; set; }
|
||||
public int ActiveCustomersCount { get; set; }
|
||||
public List<CustomerLifetimeValueItem> CustomerLifetimeValue { get; set; } = new();
|
||||
public Dictionary<string, int> QuotesByStatus { get; set; } = new();
|
||||
public QuoteConversionFunnel QuoteFunnel { get; set; } = new();
|
||||
public Dictionary<string, int> CatalogByCategory { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class CustomerRetentionViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<CustomerRetentionItem> Items { get; set; } = new();
|
||||
public int ActiveCount { get; set; }
|
||||
public int AtRiskCount { get; set; }
|
||||
public int LapsingCount { get; set; }
|
||||
public int ChurnedCount { get; set; }
|
||||
public int NeverOrderedCount { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class ExpensesApViewModel : ReportViewModelBase
|
||||
{
|
||||
public decimal TotalBilled { get; set; }
|
||||
public decimal TotalBillsPaid { get; set; }
|
||||
public decimal TotalApOutstanding { get; set; }
|
||||
public decimal TotalDirectExpenses { get; set; }
|
||||
public List<string> MonthLabels { get; set; } = new();
|
||||
public List<AgingBucketItem> ApAgingBuckets { get; set; } = new();
|
||||
public List<VendorSpendItem> VendorSpend { get; set; } = new();
|
||||
public List<ExpenseByAccountItem> ExpensesByAccount { get; set; } = new();
|
||||
public List<decimal> MonthlyBillsPaid { get; set; } = new();
|
||||
public List<decimal> MonthlyDirectExpenses { get; set; } = new();
|
||||
public List<decimal> PlRevenue { get; set; } = new();
|
||||
public List<decimal> PlExpenses { get; set; } = new();
|
||||
public List<decimal> PlNetIncome { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class FinancialSummaryViewModel : ReportViewModelBase
|
||||
{
|
||||
public decimal TotalInvoiced { get; set; }
|
||||
public decimal TotalCollected { get; set; }
|
||||
public decimal TotalOutstanding { get; set; }
|
||||
public decimal TotalOverdue { get; set; }
|
||||
public int InvoicesOverdueCount { get; set; }
|
||||
public int InvoicesDraftCount { get; set; }
|
||||
public int InvoicesPaidCount { get; set; }
|
||||
public double AvgDaysToPayment { get; set; }
|
||||
public List<string> MonthLabels { get; set; } = new();
|
||||
public List<decimal> MonthlyInvoiced { get; set; } = new();
|
||||
public List<decimal> MonthlyCollected { get; set; } = new();
|
||||
public List<AgingBucketItem> AgingBuckets { get; set; } = new();
|
||||
public List<RecentPaymentItem> RecentPayments { get; set; } = new();
|
||||
public List<OutstandingCustomerItem> TopOutstandingCustomers { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class InventoryTurnoverViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<InventoryTurnoverItem> Items { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class InvoiceAgingDetailViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<InvoiceAgingDetailItem> Items { get; set; } = new();
|
||||
public decimal TotalBalance { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class JobCycleTimeViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<JobCycleTimeItem> Items { get; set; } = new();
|
||||
public double OverallAvgCycleDays { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class JobStatusAgingViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<JobStatusAgingItem> Items { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class KpiDashboardViewModel : ReportViewModelBase
|
||||
{
|
||||
public decimal TotalRevenue { get; set; }
|
||||
public int ActiveJobsCount { get; set; }
|
||||
public int ActiveCustomersCount { get; set; }
|
||||
public decimal QuoteWinRate { get; set; }
|
||||
public int TotalQuotes { get; set; }
|
||||
public int CompletedJobsThisMonth { get; set; }
|
||||
public decimal AverageJobValue { get; set; }
|
||||
public int AppointmentsThisMonth { get; set; }
|
||||
public double AverageJobDuration { get; set; }
|
||||
public decimal MonthOverMonthGrowth { get; set; }
|
||||
public decimal CustomerRetentionRate { get; set; }
|
||||
public decimal AppointmentCompletionRate { get; set; }
|
||||
public int LowStockCount { get; set; }
|
||||
|
||||
public List<string> MonthLabels { get; set; } = new();
|
||||
public List<decimal> MonthlyRevenue { get; set; } = new();
|
||||
public Dictionary<string, int> JobsByStatus { get; set; } = new();
|
||||
public List<TopCustomerItem> TopCustomers { get; set; } = new();
|
||||
public Dictionary<string, int> EquipmentByStatus { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class OperationsReportViewModel : ReportViewModelBase
|
||||
{
|
||||
public Dictionary<string, int> JobsByStatus { get; set; } = new();
|
||||
public Dictionary<string, int> ActiveJobsByPriority { get; set; } = new();
|
||||
public Dictionary<string, int> AppointmentsByType { get; set; } = new();
|
||||
public Dictionary<string, int> AppointmentsByStatus { get; set; } = new();
|
||||
public decimal AppointmentCompletionRate { get; set; }
|
||||
public Dictionary<string, int> AppointmentsByDayOfWeek { get; set; } = new();
|
||||
public List<WorkerStatsItem> WorkerStats { get; set; } = new();
|
||||
public Dictionary<string, int> EquipmentByStatus { get; set; } = new();
|
||||
public List<LowStockItem> LowStockItems { get; set; } = new();
|
||||
public int ActiveJobsCount { get; set; }
|
||||
public int TotalAppointments { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class PowderConsumptionViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<PowderConsumptionItem> Items { get; set; } = new();
|
||||
public decimal TotalPurchasedLbs { get; set; }
|
||||
public decimal TotalConsumedLbs { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class PowderUsageViewModel : ReportViewModelBase
|
||||
{
|
||||
public decimal TotalPowderUsedLbs { get; set; }
|
||||
public decimal TotalPowderCost { get; set; }
|
||||
public int TotalJobsWithPowderUsage { get; set; }
|
||||
public int ColorsUsedCount { get; set; }
|
||||
public List<string> MonthLabels { get; set; } = new();
|
||||
public List<decimal> MonthlyPowderUsageLbs { get; set; } = new();
|
||||
public List<decimal> MonthlyPowderUsageCost { get; set; } = new();
|
||||
public List<PowderUsageByColorItem> TopColorsByUsage { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
// ── Shared item types used across analytics reports ─────────────────────────
|
||||
|
||||
public class TopCustomerItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public decimal Revenue { get; set; }
|
||||
public int JobCount { get; set; }
|
||||
}
|
||||
|
||||
public class LowStockItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? ColorName { get; set; }
|
||||
public decimal QuantityOnHand { get; set; }
|
||||
public decimal ReorderPoint { get; set; }
|
||||
public string UnitOfMeasure { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class WorkerStatsItem
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Role { get; set; } = string.Empty;
|
||||
public int JobsAssigned { get; set; }
|
||||
public int JobsCompleted { get; set; }
|
||||
public int AppointmentsAssigned { get; set; }
|
||||
public decimal CompletionRate => JobsAssigned > 0 ? Math.Round((decimal)JobsCompleted / JobsAssigned * 100, 1) : 0;
|
||||
}
|
||||
|
||||
public class CustomerLifetimeValueItem
|
||||
{
|
||||
public string? CustomerName { get; set; }
|
||||
public decimal TotalRevenue { get; set; }
|
||||
public int JobCount { get; set; }
|
||||
public decimal AvgOrderValue { get; set; }
|
||||
public DateTime FirstJobDate { get; set; }
|
||||
public DateTime LastJobDate { get; set; }
|
||||
}
|
||||
|
||||
public class QuoteConversionFunnel
|
||||
{
|
||||
public int Draft { get; set; }
|
||||
public int Sent { get; set; }
|
||||
public int Approved { get; set; }
|
||||
public int Converted { get; set; }
|
||||
public int Rejected { get; set; }
|
||||
public int Expired { get; set; }
|
||||
public int Total => Draft + Sent + Approved + Converted + Rejected + Expired;
|
||||
public decimal ConversionRate => Total > 0 ? Math.Round((decimal)(Approved + Converted) / Total * 100, 1) : 0;
|
||||
}
|
||||
|
||||
public class AgingBucketItem
|
||||
{
|
||||
public string Label { get; set; } = string.Empty;
|
||||
public decimal Amount { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
public class RecentPaymentItem
|
||||
{
|
||||
public string InvoiceNumber { get; set; } = string.Empty;
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public decimal Amount { get; set; }
|
||||
public string PaymentMethod { get; set; } = string.Empty;
|
||||
public DateTime PaymentDate { get; set; }
|
||||
}
|
||||
|
||||
public class OutstandingCustomerItem
|
||||
{
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public decimal OutstandingBalance { get; set; }
|
||||
public int OpenInvoiceCount { get; set; }
|
||||
}
|
||||
|
||||
public class VendorSpendItem
|
||||
{
|
||||
public string VendorName { get; set; } = string.Empty;
|
||||
public decimal TotalBilled { get; set; }
|
||||
public decimal TotalPaid { get; set; }
|
||||
public int BillCount { get; set; }
|
||||
public decimal BalanceDue => TotalBilled - TotalPaid;
|
||||
}
|
||||
|
||||
public class ExpenseByAccountItem
|
||||
{
|
||||
public string AccountName { get; set; } = string.Empty;
|
||||
public decimal Amount { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
public class PowderUsageByColorItem
|
||||
{
|
||||
public int InventoryItemId { get; set; }
|
||||
public string ColorName { get; set; } = string.Empty;
|
||||
public string? ColorCode { get; set; }
|
||||
public string? SKU { get; set; }
|
||||
public string? Manufacturer { get; set; }
|
||||
public decimal TotalLbsUsed { get; set; }
|
||||
public decimal TotalCost { get; set; }
|
||||
public int JobCount { get; set; }
|
||||
public string DisplayLabel => string.IsNullOrWhiteSpace(ColorCode)
|
||||
? ColorName
|
||||
: $"{ColorName} ({ColorCode})";
|
||||
}
|
||||
|
||||
public class SalesByCustomerItem
|
||||
{
|
||||
public int CustomerId { get; set; }
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public bool IsCommercial { get; set; }
|
||||
public int InvoiceCount { get; set; }
|
||||
public decimal TotalInvoiced { get; set; }
|
||||
public decimal TotalPaid { get; set; }
|
||||
public decimal BalanceDue => TotalInvoiced - TotalPaid;
|
||||
public decimal AvgInvoiceValue => InvoiceCount > 0 ? Math.Round(TotalInvoiced / InvoiceCount, 2) : 0;
|
||||
public DateTime? LastInvoiceDate { get; set; }
|
||||
}
|
||||
|
||||
public class CustomerRetentionItem
|
||||
{
|
||||
public int CustomerId { get; set; }
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public int TotalJobs { get; set; }
|
||||
public decimal LifetimeRevenue { get; set; }
|
||||
public DateTime? LastJobDate { get; set; }
|
||||
public int DaysSinceLastJob { get; set; }
|
||||
public string RetentionStatus { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class JobCycleTimeItem
|
||||
{
|
||||
public string StatusCode { get; set; } = string.Empty;
|
||||
public string StatusName { get; set; } = string.Empty;
|
||||
public int DisplayOrder { get; set; }
|
||||
public double AvgDays { get; set; }
|
||||
public double MinDays { get; set; }
|
||||
public double MaxDays { get; set; }
|
||||
public int JobCount { get; set; }
|
||||
}
|
||||
|
||||
public class JobStatusAgingItem
|
||||
{
|
||||
public int JobId { get; set; }
|
||||
public string JobNumber { get; set; } = string.Empty;
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public string StatusName { get; set; } = string.Empty;
|
||||
public string StatusCode { get; set; } = string.Empty;
|
||||
public string PriorityName { get; set; } = string.Empty;
|
||||
public string PriorityCode { get; set; } = string.Empty;
|
||||
public int DaysInCurrentStatus { get; set; }
|
||||
public DateTime? DueDate { get; set; }
|
||||
public bool IsOverdue { get; set; }
|
||||
}
|
||||
|
||||
public class InvoiceAgingDetailItem
|
||||
{
|
||||
public int InvoiceId { get; set; }
|
||||
public string InvoiceNumber { get; set; } = string.Empty;
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public string? CustomerEmail { get; set; }
|
||||
public string? CustomerPhone { get; set; }
|
||||
public DateTime InvoiceDate { get; set; }
|
||||
public DateTime? DueDate { get; set; }
|
||||
public decimal Total { get; set; }
|
||||
public decimal AmountPaid { get; set; }
|
||||
public decimal BalanceDue { get; set; }
|
||||
public int DaysOverdue { get; set; }
|
||||
public string AgingBucket { get; set; } = string.Empty;
|
||||
public string StatusDisplay { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class PowderConsumptionItem
|
||||
{
|
||||
public int InventoryItemId { get; set; }
|
||||
public string ItemName { get; set; } = string.Empty;
|
||||
public string? SKU { get; set; }
|
||||
public string? ColorName { get; set; }
|
||||
public string? ColorCode { get; set; }
|
||||
public string? Manufacturer { get; set; }
|
||||
public decimal TotalPurchasedLbs { get; set; }
|
||||
public decimal TotalConsumedLbs { get; set; }
|
||||
public decimal VarianceLbs => TotalPurchasedLbs - TotalConsumedLbs;
|
||||
public int PurchaseCount { get; set; }
|
||||
public int UsageJobCount { get; set; }
|
||||
}
|
||||
|
||||
public class InventoryTurnoverItem
|
||||
{
|
||||
public int InventoryItemId { get; set; }
|
||||
public string ItemName { get; set; } = string.Empty;
|
||||
public string? SKU { get; set; }
|
||||
public string? ColorName { get; set; }
|
||||
public decimal CurrentStockLbs { get; set; }
|
||||
public decimal TotalConsumedLbs { get; set; }
|
||||
public decimal TotalPurchasedLbs { get; set; }
|
||||
public decimal DailyConsumptionLbs { get; set; }
|
||||
public double DaysToStockout { get; set; }
|
||||
public double TurnoverRate { get; set; }
|
||||
public string StockStatus { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public abstract class ReportViewModelBase
|
||||
{
|
||||
public int SelectedMonths { get; set; } = 6;
|
||||
public string ReportTitle { get; set; } = string.Empty;
|
||||
public string ReportDescription { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class RevenueTrendsViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<string> MonthLabels { get; set; } = new();
|
||||
public List<decimal> MonthlyRevenue { get; set; } = new();
|
||||
public List<int> MonthlyJobCount { get; set; } = new();
|
||||
public List<decimal> AverageOrderValueTrend { get; set; } = new();
|
||||
public Dictionary<string, decimal> RevenueByCustomerType { get; set; } = new();
|
||||
public Dictionary<string, decimal> RevenueByPriority { get; set; } = new();
|
||||
public List<TopCustomerItem> TopCustomers { get; set; } = new();
|
||||
public decimal TotalRevenue { get; set; }
|
||||
public int TotalCompletedJobs { get; set; }
|
||||
public decimal AverageJobValue { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace PowderCoating.Web.ViewModels.Reports;
|
||||
|
||||
public class SalesByCustomerViewModel : ReportViewModelBase
|
||||
{
|
||||
public List<SalesByCustomerItem> Items { get; set; } = new();
|
||||
public decimal TotalInvoiced { get; set; }
|
||||
public decimal TotalPaid { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user