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";
}
}
}