using System.ComponentModel.DataAnnotations; namespace ROLAC.API.DTOs.Expense; public class ExpenseLineItemDto { public int Id { get; set; } public int CategoryGroupId { get; set; } public string CategoryGroupName { get; set; } = ""; public int SubCategoryId { get; set; } public string SubCategoryName { get; set; } = ""; public string? FunctionalClass { get; set; } public decimal Amount { get; set; } public string? Description { get; set; } } public class ExpenseListItemDto { public int Id { get; set; } public string Type { get; set; } = ""; public string Status { get; set; } = ""; public decimal Amount { get; set; } // header total = sum of line amounts public string Description { get; set; } = ""; public int MinistryId { get; set; } public string MinistryName { get; set; } = ""; public int LineCount { get; set; } public string PrimaryCategoryName { get; set; } = ""; // first line's category (list hint; full breakdown via detail) public string? VendorName { get; set; } public int? MemberId { get; set; } public string? MemberName { get; set; } // legal name "FirstName_en LastName_en" (used on the printed check) public string? MemberNickName { get; set; } // "NickName LastName_en"; null when the member has no distinct nickname public string ExpenseDate { get; set; } = ""; // yyyy-MM-dd public bool HasReceipt { get; set; } public string? CheckNumber { get; set; } // Review outcome — surfaced on the list so the Status column can show "Approved/Rejected by X · date". public string? ReviewedByName { get; set; } // resolved Member full name, email fallback public DateTimeOffset? ReviewedAt { get; set; } public string? ReviewNotes { get; set; } // reject reason (or approval note) public int? PayeeId { get; set; } } public class ExpenseDto : ExpenseListItemDto { public string? Notes { get; set; } public string? SubmittedBy { get; set; } public DateTimeOffset? SubmittedAt { get; set; } public DateTimeOffset? PaidAt { get; set; } public List Lines { get; set; } = new(); } public class ExpenseLineInput { [Required] public int CategoryGroupId { get; set; } [Required] public int SubCategoryId { get; set; } [Range(0.01, 9_999_999)] public decimal Amount { get; set; } [MaxLength(20)] public string? FunctionalClass { get; set; } [MaxLength(500)] public string? Description { get; set; } } public class CreateExpenseRequest { [Required] public string Type { get; set; } = "StaffReimbursement"; // VendorPayment|StaffReimbursement [Required] public int MinistryId { get; set; } [Required, MinLength(1)] public List Lines { get; set; } = new(); [Required, MaxLength(500)] public string Description { get; set; } = ""; [MaxLength(200)] public string? VendorName { get; set; } public int? MemberId { get; set; } // ignored for self-service (server uses caller) [MaxLength(50)] public string? CheckNumber { get; set; } [Required] public DateOnly ExpenseDate { get; set; } public string? Notes { get; set; } public int? PayeeId { get; set; } } public class UpdateExpenseRequest : CreateExpenseRequest { } public class RejectExpenseRequest { [MaxLength(500)] public string? ReviewNotes { get; set; } } public class PayExpenseRequest { [MaxLength(50)] public string? CheckNumber { get; set; } public DateOnly? PaidAt { get; set; } }