Fix: Add TeleBot integration and expired payment handling

TeleBot Configuration:
- Added TeleBot API URL and API key to docker-compose.yml
- Configured to connect to telebot-service:5000 internally
- Enables customer notifications via Telegram bot

Expired Payment Handling:
- Auto-cancel orders when payment status is Expired
- Only cancels orders in PendingPayment status
- Logs cancellation for audit trail

Customer View Improvements:
- Hide cancelled orders from customer order lists
- Filters applied to both GetOrdersByIdentityAsync and GetOrdersByCustomerIdAsync
- Prevents confusion from displaying cancelled/expired orders

This resolves:
- No notifications to customers (TeleBot not configured)
- No notifications to admin (TeleBot connection failed)
- Expired orders remaining visible to customers
- Orders not auto-cancelled when payment expires

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
SysAdmin 2025-10-06 16:55:19 +01:00
parent cede0e7c47
commit 6c95ed3145
3 changed files with 23 additions and 13 deletions

View File

@ -139,25 +139,33 @@ public class CryptoPaymentService : ICryptoPaymentService
payment.PaidAmount = amount; payment.PaidAmount = amount;
payment.TransactionHash = transactionHash; payment.TransactionHash = transactionHash;
// Load order for status updates
var order = await _context.Orders
.Include(o => o.Customer)
.FirstOrDefaultAsync(o => o.Id == payment.OrderId);
// Handle expired payments - auto-cancel the order
if (status == PaymentStatus.Expired && order != null)
{
if (order.Status == OrderStatus.PendingPayment)
{
order.Status = OrderStatus.Cancelled;
order.UpdatedAt = DateTime.UtcNow;
_logger.LogInformation("Auto-cancelled order {OrderId} due to payment expiration", orderId);
}
}
// Determine if payment is confirmed (ready to fulfill order) // Determine if payment is confirmed (ready to fulfill order)
var isPaymentConfirmed = status == PaymentStatus.Paid || var isPaymentConfirmed = status == PaymentStatus.Paid ||
status == PaymentStatus.Overpaid || status == PaymentStatus.Overpaid ||
(status == PaymentStatus.Completed && confirmations >= 3); (status == PaymentStatus.Completed && confirmations >= 3);
if (isPaymentConfirmed) if (isPaymentConfirmed && order != null)
{ {
payment.PaidAt = DateTime.UtcNow; payment.PaidAt = DateTime.UtcNow;
// Update order status
var order = await _context.Orders
.Include(o => o.Customer)
.FirstOrDefaultAsync(o => o.Id == payment.OrderId);
if (order != null)
{
order.Status = OrderStatus.PaymentReceived; order.Status = OrderStatus.PaymentReceived;
order.PaidAt = DateTime.UtcNow; order.PaidAt = DateTime.UtcNow;
} }
}
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();

View File

@ -51,7 +51,7 @@ public class OrderService : IOrderService
.Include(o => o.Items) .Include(o => o.Items)
.ThenInclude(oi => oi.ProductVariant) .ThenInclude(oi => oi.ProductVariant)
.Include(o => o.Payments) .Include(o => o.Payments)
.Where(o => o.IdentityReference == identityReference) .Where(o => o.IdentityReference == identityReference && o.Status != OrderStatus.Cancelled)
.OrderByDescending(o => o.CreatedAt) .OrderByDescending(o => o.CreatedAt)
.ToListAsync(); .ToListAsync();
@ -69,7 +69,7 @@ public class OrderService : IOrderService
.Include(o => o.Items) .Include(o => o.Items)
.ThenInclude(oi => oi.ProductVariant) .ThenInclude(oi => oi.ProductVariant)
.Include(o => o.Payments) .Include(o => o.Payments)
.Where(o => o.CustomerId == customerId) .Where(o => o.CustomerId == customerId && o.Status != OrderStatus.Cancelled)
.OrderByDescending(o => o.CreatedAt) .OrderByDescending(o => o.CreatedAt)
.ToListAsync(); .ToListAsync();

View File

@ -24,6 +24,8 @@ services:
- WebPush__VapidPublicKey=BDJtQu7zV0H3KF4FkrZ8nPwP3YD_3cEz3hqJvQ6L_gvNpG8ANksQB-FZy2-PDmFAu6duiN4p3mkcNAGnN4YRbws - WebPush__VapidPublicKey=BDJtQu7zV0H3KF4FkrZ8nPwP3YD_3cEz3hqJvQ6L_gvNpG8ANksQB-FZy2-PDmFAu6duiN4p3mkcNAGnN4YRbws
- WebPush__VapidPrivateKey=Hm_ttUKUqoLn5R8WQP5O1SIGxm0kVJXMZGCPMD1tUDY - WebPush__VapidPrivateKey=Hm_ttUKUqoLn5R8WQP5O1SIGxm0kVJXMZGCPMD1tUDY
- WebPush__VapidSubject=mailto:admin@littleshop.local - WebPush__VapidSubject=mailto:admin@littleshop.local
- TeleBot__ApiUrl=${TELEBOT_API_URL:-http://telebot-service:5000}
- TeleBot__ApiKey=${TELEBOT_API_KEY:-littleshop-internal-api-key}
volumes: volumes:
- littleshop_data:/app/data - littleshop_data:/app/data
- littleshop_uploads:/app/wwwroot/uploads - littleshop_uploads:/app/wwwroot/uploads