using eprintServer.Data; using eprintServer.Entities; using eprintServer.Requests; using eprintServer.Responses; using eprintServer.Enums; using Microsoft.EntityFrameworkCore; namespace eprintServer.Services; public class PaymentService : IPaymentService { private readonly DataContext _context; private readonly ThawaniServices _thawani; public PaymentService(DataContext context, ThawaniServices thawani) { _context = context; _thawani = thawani; } /* public async Task AddPaymentToOrder(long orderId, decimal amount, decimal discount, string currency) { var payment = new PaymentModel { OrderId = orderId, Amount = amount, Discount = discount, Currency = currency, Status = PaymentStatus.Submitted }; _context.Payments.Add(payment); await _context.SaveChangesAsync(); return payment; } */ public async Task AddPaymentToOrder(long orderId, decimal amount, decimal discount, string currency) { // 1. Fetch the existing order from the DB var order = await _context.Orders.FirstOrDefaultAsync(o => o.Id == orderId); if (order == null) { // This is why the FK fails. If this triggers, the ID from the frontend is wrong. throw new Exception($"Order #{orderId} does not exist in the database. Check if the ID is correct."); } // 2. Create the payment record var payment = new PaymentModel { Order = order, // Link the object directly OrderId = order.Id, // Link the ID Amount = amount, Discount = discount, Currency = currency, Status = PaymentStatus.Submitted, CreatedAt = DateTime.UtcNow }; // 3. Add and Save _context.Payments.Add(payment); try { await _context.SaveChangesAsync(); } catch (DbUpdateException ex) { // If it still fails here, the database schema has a type mismatch throw new Exception($"Database rejected the payment: {ex.InnerException?.Message}"); } return payment; } public async Task UpdatePaymentStatus(long paymentId, PaymentStatus status) { var payment = await _context.Payments.FindAsync(paymentId); if (payment == null) return null; payment.Status = status; await _context.SaveChangesAsync(); return payment; } public async Task DeletePayment(long paymentId) { var payment = await _context.Payments.FindAsync(paymentId); if (payment == null) return false; _context.Payments.Remove(payment); await _context.SaveChangesAsync(); return true; } public async Task GetPaymentById(long paymentId) => await _context.Payments.Include(p => p.Order).FirstOrDefaultAsync(p => p.Id == paymentId); public async Task> GetAllPayments() => await _context.Payments.ToListAsync(); public async Task> GetPaymentsByOrderId(long orderId) => await _context.Payments.Where(p => p.OrderId == orderId).ToListAsync(); public async Task UpdateStatus(long paymentId, PaymentStatus newStatus) { var payment = await _context.Payments.FindAsync(paymentId); if (payment == null) { return null; } payment.Status = newStatus; // Optional: If payment is marked as PAID, you might want to update the Order status too // var order = await _context.Orders.FindAsync(payment.OrderId); // if (newStatus == PaymentStatus.Paid) order.Status = OrderStatus.COMPLETED; await _context.SaveChangesAsync(); return payment; } public async Task PayOrderWithThawani(long orderId,decimal unitAmount, string successUrl, string cancelUrl) { // 1. Get the Order var order = await _context.Orders.FirstOrDefaultAsync(o => o.Id == orderId); if (order == null) throw new Exception("Order not found"); // 2. Prepare Payload (1000 Baisas = 1 OMR) var payload = new { client_reference_id = order.Id.ToString(), mode = "payment", products = new[] { new { name = $"Order Payment {order.Id}", quantity = 1, unit_amount = (int)Math.Round(unitAmount * 1000) } }, success_url = successUrl, cancel_url = cancelUrl }; string sessionId = await _thawani.InitiatePayment(payload); order.ThawaniSessionId = sessionId; var payment = new PaymentModel { OrderId = order.Id, Amount = order.TotalAmount, Status = PaymentStatus.Submitted, CreatedAt = DateTime.UtcNow, Currency = "OMR" }; _context.Payments.Add(payment); await _context.SaveChangesAsync(); // 5. Get the final URL return await _thawani.BuildRedirectUrl(sessionId); } public async Task CheckAndUpdatePaymentStatus(string sessionId) { // 1. Get Session details from Thawani var thawaniSession = await _thawani.GetSession(sessionId); // 2. Check if payment was successful in Thawani if (thawaniSession != null && thawaniSession.Data.PaymentStatus == "paid") { // 3. Extract Order ID from the client_reference_id if (long.TryParse(thawaniSession.Data.ClientReferenceId, out long orderId)) { var order = await _context.Orders .Include(o => o.Payments) .FirstOrDefaultAsync(o => o.Id == orderId); if (order != null) { // 4. Update Order Status to PAID (Enum value 1) order.Status = OrderStatus.PAID; // 5. Update the most recent Payment record to Paid var payment = order.Payments .OrderByDescending(p => p.CreatedAt) .FirstOrDefault(); if (payment != null) { payment.Status = PaymentStatus.Paid; } await _context.SaveChangesAsync(); return true; } } } return false; } }