using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using gehGassi.Core.Interfaces; using gehGassi.Domain.Common; using Microsoft.Extensions.Options; using PayPalCheckoutSdk.Core; using PayPalCheckoutSdk.Orders; using PayPalHttp; namespace gehGassi.External.Services { /// /// Service der alle PayPal-Funktionen zur Verfügung stellt /// public class PayPalService : IPayPalService { private HttpClient _httpClient; private readonly IOptions _shopOptions; private readonly IOrderService _orderService; private readonly ICustomerService _customerService; /// /// Erstellt eine Instanz /// /// Instanz von PaymentOptions /// Instanz eines IOrderService /// Instanz eines ICustomerService public PayPalService(IOptions shopOptions, IOrderService orderService, ICustomerService customerService) { _shopOptions = shopOptions; _orderService = orderService; _customerService = customerService; } /// /// Gibt einen HTTP-Client für die Kommunikation mit PayPal zurück /// /// PayPalEnvironment /// HttpClient internal HttpClient GetHttpClient(PayPalEnvironment environment) { return _httpClient ??= new PayPalHttpClient(environment); } /// /// Gibt das PayPal Environment basierend auf den Einstellungen zurück /// /// PayPal ClientId /// PayPal Secret /// PayPal Environment internal PayPalEnvironment GetEnvironment(string clientId, string secret) { PayPalEnvironment environment; if (_shopOptions.Value.PayPalUseSandbox) environment = new SandboxEnvironment(clientId, secret); else environment = new LiveEnvironment(clientId, secret); return environment; } /// /// Prüft ob die PayPal Credentials korrekt sind und eine Verbindung zur Api aufgenommen werden kann /// /// PayPal ClientId /// PayPal Secret /// true wenn erfolgreich, false sonst public async Task TestCredentialsAsync(string clientId, string secret) { var environment = GetEnvironment(clientId, secret); var client = GetHttpClient(environment); var request = new AccessTokenRequest(GetEnvironment(clientId, secret)); try { var result = await client.Execute(request); return result.StatusCode == HttpStatusCode.OK; } catch (Exception ex) { return false; } } /// /// Erstellen einer PayPal-Order /// /// Id der Bestellung /// PayPal ClientId /// PayPal Secret /// Redirect-Url für ERFOLG /// Redirect-URL für Fehler oder Abbrechen /// REdirect-Url zu PayPal oder leer wenn Fehler public async Task CreateOrderAsync(long orderId, string clientId, string secret, string successUrl, string cancelUrl) { var environment = GetEnvironment(clientId, secret); var client = GetHttpClient(environment); var order = await _orderService.GetAsync(orderId); if (order == null) return string.Empty; var orderItems = await _orderService.GetItemsAsync(orderId); if (!orderItems.Any()) return string.Empty; var customer = await _customerService.GetAsync(order.CustomerId.Value); if (customer == null) return string.Empty; var payPalOrder = new OrderRequest { CheckoutPaymentIntent = "CAPTURE", ApplicationContext = new ApplicationContext() { BrandName = $"gehGassi GmbH", LandingPage = "NO_PREFERENCE", UserAction = "CONTINUE", ShippingPreference = "SET_PROVIDED_ADDRESS", ReturnUrl = successUrl, CancelUrl = cancelUrl }, PurchaseUnits = new List() { new PurchaseUnitRequest() { CustomId = order.UniqueId.ToString(), InvoiceId = order.Number, SoftDescriptor = $"gehGassi GmbH", AmountWithBreakdown = new AmountWithBreakdown() { AmountBreakdown = new AmountBreakdown() { ItemTotal = new Money(){CurrencyCode = "EUR", Value = order.Subtotal.ToString(CultureInfo.InvariantCulture)}, Shipping = new Money(){CurrencyCode = "EUR", Value = order.Shipment.ToString(CultureInfo.InvariantCulture)}, TaxTotal = new Money(){CurrencyCode = "EUR", Value = (order.TotalGross - order.Total).ToString(CultureInfo.InvariantCulture)}, }, CurrencyCode = "EUR", Value = order.TotalGross.ToString(CultureInfo.InvariantCulture) }, ShippingDetail = new ShippingDetail() { Name = new Name() { FullName = $"{order.DeliveryAddress.GetNameForPayPal()}" }, AddressPortable = new AddressPortable() { AddressLine1 = order.DeliveryAddress.AddressLine1, AddressLine2 = order.DeliveryAddress.AddressLine2, AdminArea2 = order.DeliveryAddress.City, AdminArea1 = order.DeliveryAddress.State, PostalCode = order.DeliveryAddress.Zip, CountryCode = order.DeliveryAddress.CountryCode } } } } }; var items = new List(); foreach (var orderItem in orderItems) { var price = orderItem.Price + orderItem.Price2; price = decimal.Round(price, 2, MidpointRounding.AwayFromZero); var item = new Item() { Name = orderItem.Name, Quantity = orderItem.Quantity.ToString(CultureInfo.InvariantCulture), UnitAmount = new Money() { CurrencyCode = "EUR", Value = price.ToString(CultureInfo.InvariantCulture) }, //Tax = new Money() { CurrencyCode = "EUR", Value = (orderItem.PriceGross - orderItem.Price).ToString(CultureInfo.InvariantCulture) }, //Category = "PHYSICAL_GOODS" }; switch (orderItem.ProductType) { case ProductType.Physical: item.Category = "PHYSICAL_GOODS"; break; case ProductType.Download: item.Category = "DIGITAL_GOODS"; break; case ProductType.Listing: item.Category = "DIGITAL_GOODS"; break; case ProductType.Advertisement: item.Category = "DIGITAL_GOODS"; break; case ProductType.Pin: item.Category = "DIGITAL_GOODS"; break; case ProductType.Banner: item.Category = "DIGITAL_GOODS"; break; default: item.Category = "PHYSICAL_GOODS"; break; } items.Add(item); } payPalOrder.PurchaseUnits.First().Items = items; try { var payPalOrderCreateRequest = new OrdersCreateRequest(); payPalOrderCreateRequest.Prefer("return=representation"); payPalOrderCreateRequest.RequestBody(payPalOrder); var orderResponse = await _httpClient.Execute(payPalOrderCreateRequest); var statusCode = orderResponse.StatusCode; if (statusCode == HttpStatusCode.Created) { var result = orderResponse.Result(); var approveLink = string.Empty; if (result.Links.Any()) { var link = result.Links.FirstOrDefault(c => c.Rel == "approve"); if (link != null) approveLink = link.Href; } order.PayPalOrderId = result.Id; order.PaymentStatus = PaymentStatus.Pending; order.PaymentInfo = $"{DateTime.UtcNow}: PayPal order created. OrderId: {result.Id}" + System.Environment.NewLine + order.PaymentInfo; await _orderService.CommitAsync("paypal"); return approveLink; } } catch (Exception ex) { var msg = ex.Message; } return string.Empty; } /// /// Authorisieren der PayPal Order - Bezahlung durchführen /// /// PayPal-Order-Id /// PayPal ClientId /// PayPal Secret /// true wenn erfolgreich, false sonst public async Task AuthorizeOrderAsync(string payPalOrder, string clientId, string secret) { var environment = GetEnvironment(clientId, secret); var client = GetHttpClient(environment); var request = new OrdersCaptureRequest(payPalOrder); request.Prefer("return=representation"); request.RequestBody(new OrderActionRequest()); var response = await client.Execute(request); var result = response.Result(); return result.Status.ToUpper() == "COMPLETED"; } } }