185 lines
5.6 KiB
C#
185 lines
5.6 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
|
|
namespace LittleShop.Models;
|
|
|
|
public enum MessageDirection
|
|
{
|
|
AdminToCustomer = 0,
|
|
CustomerToAdmin = 1
|
|
}
|
|
|
|
public enum MessageStatus
|
|
{
|
|
Pending = 0, // Message created, waiting to be sent
|
|
Sent = 1, // Message delivered to customer
|
|
Delivered = 2, // Message acknowledged by bot/platform
|
|
Read = 3, // Customer has read the message
|
|
Failed = 4 // Delivery failed
|
|
}
|
|
|
|
public enum MessageType
|
|
{
|
|
OrderUpdate = 0, // Status update about an order
|
|
PaymentReminder = 1, // Payment reminder
|
|
ShippingInfo = 2, // Tracking/shipping information
|
|
CustomerService = 3, // General customer service
|
|
Marketing = 4, // Marketing/promotional (requires consent)
|
|
SystemAlert = 5 // System-generated alerts
|
|
}
|
|
|
|
public class CustomerMessage
|
|
{
|
|
[Key]
|
|
public Guid Id { get; set; }
|
|
|
|
// Relationships
|
|
[Required]
|
|
public Guid CustomerId { get; set; }
|
|
|
|
public Guid? OrderId { get; set; } // Optional - message may not be about specific order
|
|
|
|
public Guid? AdminUserId { get; set; } // Which admin sent the message (null for system messages or unidentified admins)
|
|
|
|
// Message Details
|
|
[Required]
|
|
public MessageDirection Direction { get; set; }
|
|
|
|
[Required]
|
|
public MessageType Type { get; set; }
|
|
|
|
[Required]
|
|
[StringLength(100)]
|
|
public string Subject { get; set; } = string.Empty;
|
|
|
|
[Required]
|
|
[StringLength(4000)] // Telegram message limit is ~4096 characters
|
|
public string Content { get; set; } = string.Empty;
|
|
|
|
public MessageStatus Status { get; set; } = MessageStatus.Pending;
|
|
|
|
// Delivery Information
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
|
|
public DateTime? SentAt { get; set; }
|
|
|
|
public DateTime? DeliveredAt { get; set; }
|
|
|
|
public DateTime? ReadAt { get; set; }
|
|
|
|
public DateTime? FailedAt { get; set; }
|
|
|
|
[StringLength(500)]
|
|
public string? FailureReason { get; set; }
|
|
|
|
public int RetryCount { get; set; } = 0;
|
|
|
|
public DateTime? NextRetryAt { get; set; }
|
|
|
|
// Message Threading (for conversations)
|
|
public Guid? ParentMessageId { get; set; } // Reply to another message
|
|
|
|
public Guid? ThreadId { get; set; } // Conversation thread identifier
|
|
|
|
// Platform-specific Information
|
|
[StringLength(100)]
|
|
public string Platform { get; set; } = "Telegram"; // Telegram, Email, SMS, etc.
|
|
|
|
[StringLength(200)]
|
|
public string? PlatformMessageId { get; set; } // Telegram message ID, email message ID, etc.
|
|
|
|
// Priority and Scheduling
|
|
public int Priority { get; set; } = 5; // 1-10, 1 = highest priority
|
|
|
|
public DateTime? ScheduledFor { get; set; } // For scheduled messages
|
|
|
|
public DateTime? ExpiresAt { get; set; } // Message expires if not delivered
|
|
|
|
// Customer Preferences
|
|
public bool RequiresResponse { get; set; } = false;
|
|
|
|
public bool IsUrgent { get; set; } = false;
|
|
|
|
public bool IsMarketing { get; set; } = false;
|
|
|
|
// Auto-generated flags
|
|
public bool IsAutoGenerated { get; set; } = false;
|
|
|
|
[StringLength(100)]
|
|
public string? AutoGenerationTrigger { get; set; } // e.g., "OrderStatusChanged", "PaymentOverdue"
|
|
|
|
// Data retention
|
|
public bool IsArchived { get; set; } = false;
|
|
|
|
public DateTime? ArchivedAt { get; set; }
|
|
|
|
// Navigation properties
|
|
public virtual Customer Customer { get; set; } = null!;
|
|
public virtual Order? Order { get; set; }
|
|
public virtual User? AdminUser { get; set; }
|
|
public virtual CustomerMessage? ParentMessage { get; set; }
|
|
public virtual ICollection<CustomerMessage> Replies { get; set; } = new List<CustomerMessage>();
|
|
|
|
// Helper methods
|
|
public bool CanRetry()
|
|
{
|
|
return Status == MessageStatus.Failed &&
|
|
RetryCount < 3 &&
|
|
(NextRetryAt == null || DateTime.UtcNow >= NextRetryAt) &&
|
|
(ExpiresAt == null || DateTime.UtcNow < ExpiresAt);
|
|
}
|
|
|
|
public void MarkAsSent()
|
|
{
|
|
Status = MessageStatus.Sent;
|
|
SentAt = DateTime.UtcNow;
|
|
}
|
|
|
|
public void MarkAsDelivered(string? platformMessageId = null)
|
|
{
|
|
Status = MessageStatus.Delivered;
|
|
DeliveredAt = DateTime.UtcNow;
|
|
if (!string.IsNullOrEmpty(platformMessageId))
|
|
{
|
|
PlatformMessageId = platformMessageId;
|
|
}
|
|
}
|
|
|
|
public void MarkAsRead()
|
|
{
|
|
Status = MessageStatus.Read;
|
|
ReadAt = DateTime.UtcNow;
|
|
}
|
|
|
|
public void MarkAsFailed(string reason)
|
|
{
|
|
Status = MessageStatus.Failed;
|
|
FailedAt = DateTime.UtcNow;
|
|
FailureReason = reason;
|
|
RetryCount++;
|
|
|
|
// Exponential backoff for retries
|
|
if (RetryCount <= 3)
|
|
{
|
|
var delayMinutes = Math.Pow(2, RetryCount) * 5; // 10, 20, 40 minutes
|
|
NextRetryAt = DateTime.UtcNow.AddMinutes(delayMinutes);
|
|
}
|
|
}
|
|
|
|
public string GetDisplayTitle()
|
|
{
|
|
var prefix = Direction == MessageDirection.AdminToCustomer ? "→" : "←";
|
|
var typeStr = Type switch
|
|
{
|
|
MessageType.OrderUpdate => "Order Update",
|
|
MessageType.PaymentReminder => "Payment",
|
|
MessageType.ShippingInfo => "Shipping",
|
|
MessageType.CustomerService => "Support",
|
|
MessageType.Marketing => "Marketing",
|
|
MessageType.SystemAlert => "System",
|
|
_ => "Message"
|
|
};
|
|
|
|
return $"{prefix} {typeStr}: {Subject}";
|
|
}
|
|
} |