Implement bidirectional customer conversations with customer-based grouping and order tagging

This commit is contained in:
sysadmin
2025-08-27 19:18:46 +01:00
parent 3f4789730c
commit 027a3fd0c4
25 changed files with 794 additions and 70 deletions

View File

@@ -30,18 +30,8 @@ public class CustomerMessageService : ICustomerMessageService
message.Status = MessageStatus.Pending;
message.Platform = "Telegram";
// Generate thread ID if this is a new conversation
if (message.ParentMessageId == null)
{
message.ThreadId = Guid.NewGuid();
}
else
{
// Get parent message's thread ID
var parentMessage = await _context.CustomerMessages
.FirstOrDefaultAsync(m => m.Id == message.ParentMessageId);
message.ThreadId = parentMessage?.ThreadId ?? Guid.NewGuid();
}
// Use customer-based threading - all messages for a customer are in one conversation
message.ThreadId = message.CustomerId;
_context.CustomerMessages.Add(message);
await _context.SaveChangesAsync();
@@ -161,28 +151,29 @@ public class CustomerMessageService : ICustomerMessageService
return true;
}
public async Task<MessageThreadDto?> GetMessageThreadAsync(Guid threadId)
public async Task<MessageThreadDto?> GetMessageThreadAsync(Guid customerId)
{
// Get all messages for this customer (customer-based conversation)
var messages = await _context.CustomerMessages
.Include(m => m.Customer)
.Include(m => m.Order)
.Include(m => m.AdminUser)
.Where(m => m.ThreadId == threadId)
.Where(m => m.CustomerId == customerId && !m.IsArchived)
.OrderBy(m => m.CreatedAt)
.ToListAsync();
if (!messages.Any()) return null;
var firstMessage = messages.First();
var customer = messages.First().Customer;
var thread = new MessageThreadDto
{
ThreadId = threadId,
Subject = firstMessage.Subject,
CustomerId = firstMessage.CustomerId,
CustomerName = firstMessage.Customer?.DisplayName ?? "Unknown",
OrderId = firstMessage.OrderId,
OrderReference = firstMessage.Order?.Id.ToString().Substring(0, 8),
StartedAt = firstMessage.CreatedAt,
ThreadId = customerId, // Use CustomerId as thread identifier
Subject = customer?.DisplayName ?? "Unknown Customer", // Customer name as subject
CustomerId = customerId,
CustomerName = customer?.DisplayName ?? "Unknown",
OrderId = null, // No single order - conversation spans multiple orders
OrderReference = null, // No single order reference
StartedAt = messages.Min(m => m.CreatedAt),
LastMessageAt = messages.Max(m => m.CreatedAt),
MessageCount = messages.Count,
HasUnreadMessages = messages.Any(m => m.Direction == MessageDirection.CustomerToAdmin && m.Status != MessageStatus.Read),
@@ -195,19 +186,20 @@ public class CustomerMessageService : ICustomerMessageService
public async Task<IEnumerable<MessageThreadDto>> GetActiveThreadsAsync()
{
// Group by Customer instead of ThreadId for customer-based conversations
var threads = await _context.CustomerMessages
.Include(m => m.Customer)
.Include(m => m.Order)
.Where(m => !m.IsArchived)
.GroupBy(m => m.ThreadId)
.GroupBy(m => m.CustomerId)
.Select(g => new MessageThreadDto
{
ThreadId = g.Key ?? Guid.Empty,
Subject = g.First().Subject,
ThreadId = g.First().CustomerId, // Use CustomerId as conversation identifier
Subject = g.First().Customer != null ? g.First().Customer.DisplayName : "Unknown Customer",
CustomerId = g.First().CustomerId,
CustomerName = g.First().Customer != null ? g.First().Customer.DisplayName : "Unknown",
OrderId = g.First().OrderId,
OrderReference = g.First().Order != null ? g.First().Order.Id.ToString().Substring(0, 8) : null,
OrderId = null, // No single order - will show multiple orders in thread
OrderReference = null, // No single order reference
StartedAt = g.Min(m => m.CreatedAt),
LastMessageAt = g.Max(m => m.CreatedAt),
MessageCount = g.Count(),
@@ -230,4 +222,26 @@ public class CustomerMessageService : ICustomerMessageService
{
return await _context.Orders.AnyAsync(o => o.Id == orderId && o.CustomerId == customerId);
}
public async Task<bool> CreateCustomerToAdminMessageAsync(CustomerMessage message)
{
try
{
// Use customer-based threading for all messages
message.ThreadId = message.CustomerId;
_context.CustomerMessages.Add(message);
await _context.SaveChangesAsync();
_logger.LogInformation("Created customer message {MessageId} from customer {CustomerId}",
message.Id, message.CustomerId);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating customer message from customer {CustomerId}", message.CustomerId);
return false;
}
}
}

View File

@@ -17,4 +17,5 @@ public interface ICustomerMessageService
Task<IEnumerable<MessageThreadDto>> GetActiveThreadsAsync();
Task<bool> ValidateCustomerExistsAsync(Guid customerId);
Task<bool> ValidateOrderBelongsToCustomerAsync(Guid orderId, Guid customerId);
Task<bool> CreateCustomerToAdminMessageAsync(CustomerMessage message);
}