using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace MoneyMap.Models; public enum ReceiptParseStatus { NotRequested = 0, Queued = 1, Parsing = 2, Completed = 3, Failed = 4 } [Index(nameof(TransactionId), nameof(FileHashSha256), IsUnique = true)] public class Receipt { [Key] public long Id { get; set; } // Link to transaction (nullable to support unmapped receipts) public long? TransactionId { get; set; } public Transaction? Transaction { get; set; } // File metadata [MaxLength(260)] public string FileName { get; set; } = string.Empty; [MaxLength(100)] public string ContentType { get; set; } = "application/octet-stream"; [MaxLength(1024)] public string StoragePath { get; set; } = string.Empty; // \\barge.lan\receipts\...\ or blob key public long FileSizeBytes { get; set; } [MaxLength(64)] public string FileHashSha256 { get; set; } = string.Empty; // for dedupe public DateTime UploadedAtUtc { get; set; } = DateTime.UtcNow; // Parsed header fields (optional, set by parser job) [MaxLength(200)] public string? Merchant { get; set; } public DateTime? ReceiptDate { get; set; } public DateTime? DueDate { get; set; } // For bills - payment due date [Column(TypeName = "decimal(18,2)")] public decimal? Subtotal { get; set; } [Column(TypeName = "decimal(18,2)")] public decimal? Tax { get; set; } [Column(TypeName = "decimal(18,2)")] public decimal? Total { get; set; } [MaxLength(8)] public string? Currency { get; set; } // User notes provided to AI parser [MaxLength(2000)] public string? ParsingNotes { get; set; } // Parse queue status public ReceiptParseStatus ParseStatus { get; set; } = ReceiptParseStatus.NotRequested; // One receipt -> many parse attempts + many line items public ICollection ParseLogs { get; set; } = new List(); public ICollection LineItems { get; set; } = new List(); }