diff --git a/BookingMicroservice/BookingMicroservice.csproj b/BookingMicroservice/BookingMicroservice.csproj index aac30ec61683d673dfb036a93dd6bf5fc43013a9..b0dc1629551990500350dfd58d6f748d3ebf057a 100644 --- a/BookingMicroservice/BookingMicroservice.csproj +++ b/BookingMicroservice/BookingMicroservice.csproj @@ -18,6 +18,7 @@ </PackageReference> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /> + <PackageReference Include="Stripe.net" Version="44.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> </ItemGroup> diff --git a/BookingMicroservice/Controllers/BookingController.cs b/BookingMicroservice/Controllers/BookingController.cs index de800b69a4e0fbdae5b598ed496a012cddd9d6ed..1ca7bc7456ab5e2d2da1deb68121ffd8fe91c3be 100644 --- a/BookingMicroservice/Controllers/BookingController.cs +++ b/BookingMicroservice/Controllers/BookingController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; + namespace BookingMicroservice.Controllers { [ApiController] @@ -13,11 +14,13 @@ namespace BookingMicroservice.Controllers { private readonly IReservationComplianceService reservationComplianceService; private readonly IBookingService bookingService; + private readonly IStripeService stripeService; - public BookingController(IReservationComplianceService reservationComplianceService, IBookingService bookingService) + public BookingController(IReservationComplianceService reservationComplianceService, IBookingService bookingService, IStripeService stripeService) { this.reservationComplianceService = reservationComplianceService; this.bookingService = bookingService; + this.stripeService = stripeService; } [Authorize] @@ -46,14 +49,20 @@ namespace BookingMicroservice.Controllers [HttpPost()] public async Task<IActionResult> MakeBooking([FromBody] BookingCreation bookingCreationModel) { - // TODO: add stripe handling + string? userIdValue = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (!int.TryParse(userIdValue, out int userId)) return BadRequest("Unable to get User Id from Token"); try { - Booking? booking = await reservationComplianceService.TryCreateBookingAsync(bookingCreationModel.FlightId, userId, bookingCreationModel.BookingClass, bookingCreationModel.SeatId); + bool isPaymentSuccessful = await stripeService.VerifyPaymentIntent(bookingCreationModel.PaymentIntentId); + if (!isPaymentSuccessful) + { + return BadRequest("Payment verification failed."); + } + + Booking? booking = await reservationComplianceService.TryCreateBookingAsync(bookingCreationModel.FlightId, userId, bookingCreationModel.BookingClass, bookingCreationModel.SeatId, bookingCreationModel.PaymentIntentId); if (booking == null) return BadRequest("Error in creating booking"); diff --git a/BookingMicroservice/Models/BookingCreation.cs b/BookingMicroservice/Models/BookingCreation.cs index 0e398b9d3e6c6e9eff874335902c683ccaf1f42c..976fd9bd604fe9e832c575afa6aed22129088f32 100644 --- a/BookingMicroservice/Models/BookingCreation.cs +++ b/BookingMicroservice/Models/BookingCreation.cs @@ -5,5 +5,6 @@ public required int FlightId { get; set; } public required BookingClass BookingClass { get; set; } public int? SeatId { get; set; } + public required string PaymentIntentId { get; set; } } } diff --git a/BookingMicroservice/Program.cs b/BookingMicroservice/Program.cs index 74cabbd729d2e59148649da179c50c918bf9dc0d..c2aa2c1631803da388913b75b1d2f611c8940046 100644 --- a/BookingMicroservice/Program.cs +++ b/BookingMicroservice/Program.cs @@ -13,6 +13,7 @@ builder.Services.AddHttpContextAccessor(); builder.Services.AddTransient<RequestCookieHandler>(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddLogging(); builder.Services.AddSwaggerGen(); builder.Services.AddDbContext<ApplicationDbContext>(options => @@ -59,6 +60,7 @@ builder.Services.AddHttpClient<IFlightServiceClient, FlightServiceClient>(client builder.Services.AddScoped<IBookingService, BookingService>(); builder.Services.AddScoped<IReservationComplianceService, ReservationComplianceService>(); +builder.Services.AddScoped<IStripeService, StripeService>(); var app = builder.Build(); diff --git a/BookingMicroservice/Services/BookingService.cs b/BookingMicroservice/Services/BookingService.cs index 4c7a4fd983614f290d28e1ad3ee52bfaaf63d842..f869115e8289c8a73580dc02bd6a4e04e0ab2b1c 100644 --- a/BookingMicroservice/Services/BookingService.cs +++ b/BookingMicroservice/Services/BookingService.cs @@ -30,7 +30,7 @@ namespace BookingMicroservice.Services return bookings; } - public Booking CreateBooking(int flightId, int userId, BookingClass bookingClass) + public Booking CreateBooking(int flightId, int userId, BookingClass bookingClass, string paymentIntentId) { Booking booking = new Booking(flightId, userId, bookingClass, null); diff --git a/BookingMicroservice/Services/IBookingService.cs b/BookingMicroservice/Services/IBookingService.cs index b5bd32727c612296a115e6323e204eac9741dd4c..ddb2e279eb31a9e44e8c2d378c4c4f7f4f1a4aae 100644 --- a/BookingMicroservice/Services/IBookingService.cs +++ b/BookingMicroservice/Services/IBookingService.cs @@ -4,7 +4,7 @@ namespace BookingMicroservice.Services { public interface IBookingService { - Booking CreateBooking(int flightId, int userId, BookingClass bookingClass); + Booking CreateBooking(int flightId, int userId, BookingClass bookingClass, string paymentIntentId); List<Booking> GetBookings(int? flightId = null, int? userId = null, BookingClass? bookingClass = null); Booking? GetBooking(int bookingId); void DeleteBooking(int bookingId); diff --git a/BookingMicroservice/Services/IReservationComplianceService.cs b/BookingMicroservice/Services/IReservationComplianceService.cs index 7f82720510a1f07e8016add0940502dd22bf822c..92641968a283e4f10841072e03cf0a4b06519222 100644 --- a/BookingMicroservice/Services/IReservationComplianceService.cs +++ b/BookingMicroservice/Services/IReservationComplianceService.cs @@ -4,7 +4,7 @@ namespace BookingMicroservice.Services { public interface IReservationComplianceService { - Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId); + Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId, string paymentIntentId); Task TryBookSeatAsync(int bookingId, int seatId); } diff --git a/BookingMicroservice/Services/IStripeService.cs b/BookingMicroservice/Services/IStripeService.cs new file mode 100644 index 0000000000000000000000000000000000000000..0c3a0975033b5d9ec786fc54caa8c051cc1a44ba --- /dev/null +++ b/BookingMicroservice/Services/IStripeService.cs @@ -0,0 +1,10 @@ +using BookingMicroservice.Models; +using Stripe; + +namespace BookingMicroservice.Services +{ + public interface IStripeService + { + Task<bool> VerifyPaymentIntent(string paymentIntentId); + } +} \ No newline at end of file diff --git a/BookingMicroservice/Services/ReservationComplianceService.cs b/BookingMicroservice/Services/ReservationComplianceService.cs index df3f6a6effa87f3aa15568b52b339ec3456a81fb..8558ef4d0709c269201b3f853b15f39b3909d2c8 100644 --- a/BookingMicroservice/Services/ReservationComplianceService.cs +++ b/BookingMicroservice/Services/ReservationComplianceService.cs @@ -18,7 +18,7 @@ namespace BookingMicroservice.Services this.flightServiceClient = flightServiceClient; } - public async Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId) + public async Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId, string paymentIntentId) { HttpResponseMessage capacityResponse = await flightServiceClient.GetFlightCapacityAsync(flightId, (int)bookingClass); if (!capacityResponse.IsSuccessStatusCode) @@ -34,7 +34,7 @@ namespace BookingMicroservice.Services if (currentBookings >= capacity) throw new BookingException(string.Format(NO_AVAILABLE_SEAT_MSG, bookingClass.ToString().ToLower())); - Booking booking = bookingService.CreateBooking(flightId, userId, bookingClass); + Booking booking = bookingService.CreateBooking(flightId, userId, bookingClass, paymentIntentId); if(seatId.HasValue && booking?.Id != null) { try diff --git a/BookingMicroservice/Services/StripeService.cs b/BookingMicroservice/Services/StripeService.cs new file mode 100644 index 0000000000000000000000000000000000000000..68963ddf55794bf57b3de7cb95532fdabc7f7def --- /dev/null +++ b/BookingMicroservice/Services/StripeService.cs @@ -0,0 +1,36 @@ +using BookingMicroservice.Models; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; +using Stripe; +using System; +using System.Threading.Tasks; + +namespace BookingMicroservice.Services +{ + public class StripeService : IStripeService + { + private readonly ILogger<StripeService> _logger; + + public StripeService(ILogger<StripeService> logger, IConfiguration configuration) + { + _logger = logger; + StripeConfiguration.ApiKey = configuration["Stripe:SecretKey"]; + } + + public async Task<bool> VerifyPaymentIntent(string paymentIntentId) + { + var service = new PaymentIntentService(); + try + { + var paymentIntent = await service.GetAsync(paymentIntentId); + _logger.LogInformation($"Payment Intent Status: {paymentIntent.Status}"); + return paymentIntent.Status == "succeeded"; + } + catch (StripeException ex) + { + _logger.LogError($"Error verifying payment intent: {ex.Message}"); + throw new Exception("Failed to verify payment intent: " + ex.Message); + } + } + } +} diff --git a/BookingMicroservice/appsettings.json b/BookingMicroservice/appsettings.json index 7ce4758e8bacea93b6bfa282c518089174e34fb3..a9321d0a03d6d8ed9b2835edff262cbcb0cdc8f9 100644 --- a/BookingMicroservice/appsettings.json +++ b/BookingMicroservice/appsettings.json @@ -16,5 +16,8 @@ }, "FlightMicroservice": { "BaseUrl": "http://localhost:5175" + }, + "Stripe": { + "SecretKey": "sk_test_51P5UhOExQclpActcAn0yMrhaHESmCjtM69JOhjmo4B5AK67WwZn317QZmbunbuanwytn3xxhgVh6wfxEONorblgl00rQbt1YZk" } } diff --git a/GatewayAPI/Models/BookingCreation.cs b/GatewayAPI/Models/BookingCreation.cs index c3134926859c658ace68b0dc5806c7c398270dc8..d0460cd3c54288628ef1837b7cec5362fcd39f3f 100644 --- a/GatewayAPI/Models/BookingCreation.cs +++ b/GatewayAPI/Models/BookingCreation.cs @@ -5,6 +5,6 @@ public required int FlightId { get; set; } public required int BookingClass { get; set; } public int? SeatId { get; set; } - + public required string PaymentIntentId { get; set; } } }