From f4400422046254677c6d4d5a58136597a4e21ed4 Mon Sep 17 00:00:00 2001 From: SysAdmin Date: Mon, 6 Oct 2025 04:19:47 +0100 Subject: [PATCH] Feature: Complete order management for pending orders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added delete order functionality with identity verification - OrderDetailsMenu now shows conditional buttons based on order/payment state - Retry payment if no payments exist - View payment details if payment pending - Delete order option for all pending orders - Full client SDK implementation for CancelOrderAsync 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- LittleShop.Client/Services/IOrderService.cs | 1 + LittleShop.Client/Services/OrderService.cs | 25 ++++++++++- TeleBot/TeleBot/Handlers/CallbackHandler.cs | 41 +++++++++++++++++++ TeleBot/TeleBot/Services/LittleShopService.cs | 26 ++++++++++++ TeleBot/TeleBot/UI/MenuBuilder.cs | 24 +++++++++-- 5 files changed, 113 insertions(+), 4 deletions(-) diff --git a/LittleShop.Client/Services/IOrderService.cs b/LittleShop.Client/Services/IOrderService.cs index 04200e8..a8dd7d2 100644 --- a/LittleShop.Client/Services/IOrderService.cs +++ b/LittleShop.Client/Services/IOrderService.cs @@ -11,4 +11,5 @@ public interface IOrderService Task> GetOrderByCustomerIdAsync(Guid customerId, Guid orderId); Task> CreatePaymentAsync(Guid orderId, int currency); Task>> GetOrderPaymentsAsync(Guid orderId); + Task> CancelOrderAsync(Guid orderId, string identityReference); } \ No newline at end of file diff --git a/LittleShop.Client/Services/OrderService.cs b/LittleShop.Client/Services/OrderService.cs index 0328bd8..417709b 100644 --- a/LittleShop.Client/Services/OrderService.cs +++ b/LittleShop.Client/Services/OrderService.cs @@ -185,8 +185,31 @@ public class OrderService : IOrderService { _logger.LogError(ex, "Failed to get payments for order {OrderId}", orderId); return ApiResponse>.Failure( - ex.Message, + ex.Message, System.Net.HttpStatusCode.InternalServerError); } } + + public async Task> CancelOrderAsync(Guid orderId, string identityReference) + { + try + { + var response = await _httpClient.PostAsJsonAsync( + $"api/orders/{orderId}/cancel", + new { IdentityReference = identityReference } + ); + + if (response.IsSuccessStatusCode) + { + return ApiResponse.Success(true, response.StatusCode); + } + + return ApiResponse.Failure("Failed to cancel order", response.StatusCode); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error cancelling order {OrderId}", orderId); + return ApiResponse.Failure($"Error: {ex.Message}", System.Net.HttpStatusCode.InternalServerError); + } + } } \ No newline at end of file diff --git a/TeleBot/TeleBot/Handlers/CallbackHandler.cs b/TeleBot/TeleBot/Handlers/CallbackHandler.cs index 3a60717..6c3812d 100644 --- a/TeleBot/TeleBot/Handlers/CallbackHandler.cs +++ b/TeleBot/TeleBot/Handlers/CallbackHandler.cs @@ -180,6 +180,10 @@ namespace TeleBot.Handlers await HandleRetryPayment(bot, callbackQuery.Message, session, Guid.Parse(data[1])); break; + case "delete_order": + await HandleDeleteOrder(bot, callbackQuery, session, Guid.Parse(data[1]), callbackQuery.From); + break; + case "reviews": await HandleViewReviews(bot, callbackQuery.Message, session); break; @@ -1215,6 +1219,43 @@ namespace TeleBot.Handlers ); } + private async Task HandleDeleteOrder(ITelegramBotClient bot, CallbackQuery callbackQuery, UserSession session, Guid orderId, User telegramUser) + { + // Build identity reference from telegram user + var identityReference = $"telegram:{telegramUser.Id}:{telegramUser.Username ?? ""}"; + + var success = await _shopService.CancelOrderAsync(orderId, identityReference); + + if (success) + { + await bot.EditMessageTextAsync( + callbackQuery.Message!.Chat.Id, + callbackQuery.Message.MessageId, + "✅ *Order Deleted*\n\n" + + $"Order #{orderId.ToString().Substring(orderId.ToString().Length - 8).ToUpper()} has been cancelled and removed.", + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: new InlineKeyboardMarkup(new[] + { + new[] + { + InlineKeyboardButton.WithCallbackData("⬅️ Back to Orders", "orders"), + InlineKeyboardButton.WithCallbackData("🏠 Main Menu", "menu") + } + }) + ); + + await bot.AnswerCallbackQueryAsync(callbackQuery.Id, "Order deleted successfully"); + } + else + { + await bot.AnswerCallbackQueryAsync( + callbackQuery.Id, + "Failed to delete order. It may have already been processed.", + showAlert: true + ); + } + } + private async Task HandleViewPayment(ITelegramBotClient bot, Message message, UserSession session, Guid orderId, User telegramUser) { var order = await _shopService.GetCustomerOrderAsync( diff --git a/TeleBot/TeleBot/Services/LittleShopService.cs b/TeleBot/TeleBot/Services/LittleShopService.cs index 1075867..d29f4a4 100644 --- a/TeleBot/TeleBot/Services/LittleShopService.cs +++ b/TeleBot/TeleBot/Services/LittleShopService.cs @@ -24,6 +24,7 @@ namespace TeleBot.Services Task GetOrderAsync(Guid orderId); Task GetCustomerOrderAsync(Guid orderId, long telegramUserId, string telegramUsername, string displayName, string firstName, string lastName); Task CreatePaymentAsync(Guid orderId, string currency); + Task CancelOrderAsync(Guid orderId, string identityReference); Task?> GetPendingMessagesAsync(); Task MarkMessageAsSentAsync(Guid messageId, string? platformMessageId = null); Task MarkMessageAsFailedAsync(Guid messageId, string reason); @@ -358,6 +359,31 @@ namespace TeleBot.Services } } + public async Task CancelOrderAsync(Guid orderId, string identityReference) + { + try + { + if (!await AuthenticateAsync()) + return false; + + var result = await _client.Orders.CancelOrderAsync(orderId, identityReference); + + if (result.IsSuccess) + { + _logger.LogInformation("Order {OrderId} cancelled for customer {Identity}", orderId, identityReference); + return true; + } + + _logger.LogWarning("Failed to cancel order {OrderId}: {Error}", orderId, result.ErrorMessage); + return false; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error cancelling order {OrderId}", orderId); + return false; + } + } + public async Task?> GetPendingMessagesAsync() { try diff --git a/TeleBot/TeleBot/UI/MenuBuilder.cs b/TeleBot/TeleBot/UI/MenuBuilder.cs index 259fc42..ee8bbaf 100644 --- a/TeleBot/TeleBot/UI/MenuBuilder.cs +++ b/TeleBot/TeleBot/UI/MenuBuilder.cs @@ -209,12 +209,30 @@ namespace TeleBot.UI { var buttons = new List(); - // If order has pending payment, show payment details button - if (order.Status == 0 && order.Payments.Any(p => p.Status == 0)) // PendingPayment order with pending payment + // Order management based on status and payment state + if (order.Status == 0) // Pending Payment { + if (!order.Payments.Any()) + { + // No payment created - offer retry + buttons.Add(new[] + { + InlineKeyboardButton.WithCallbackData("🔄 Retry Payment", $"retry_payment:{order.Id}") + }); + } + else if (order.Payments.Any(p => p.Status == 0)) // Has pending payment + { + // Show payment details + buttons.Add(new[] + { + InlineKeyboardButton.WithCallbackData("💳 View Payment Details", $"payment:{order.Id}") + }); + } + + // Allow deleting pending orders buttons.Add(new[] { - InlineKeyboardButton.WithCallbackData("💳 View Payment Details", $"payment:{order.Id}") + InlineKeyboardButton.WithCallbackData("🗑️ Delete Order", $"delete_order:{order.Id}") }); }