264 lines
11 KiB
C#

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
{
/// <summary>
/// Service der alle PayPal-Funktionen zur Verfügung stellt
/// </summary>
public class PayPalService : IPayPalService
{
private HttpClient _httpClient;
private readonly IOptions<ShopOptions> _shopOptions;
private readonly IOrderService _orderService;
private readonly ICustomerService _customerService;
/// <summary>
/// Erstellt eine Instanz
/// </summary>
/// <param name="shopOptions">Instanz von PaymentOptions</param>
/// <param name="orderService">Instanz eines IOrderService</param>
/// <param name="customerService">Instanz eines ICustomerService</param>
public PayPalService(IOptions<ShopOptions> shopOptions, IOrderService orderService, ICustomerService customerService)
{
_shopOptions = shopOptions;
_orderService = orderService;
_customerService = customerService;
}
/// <summary>
/// Gibt einen HTTP-Client für die Kommunikation mit PayPal zurück
/// </summary>
/// <param name="environment">PayPalEnvironment</param>
/// <returns>HttpClient</returns>
internal HttpClient GetHttpClient(PayPalEnvironment environment)
{
return _httpClient ??= new PayPalHttpClient(environment);
}
/// <summary>
/// Gibt das PayPal Environment basierend auf den Einstellungen zurück
/// </summary>
/// <param name="clientId">PayPal ClientId</param>
/// <param name="secret">PayPal Secret</param>
/// <returns>PayPal Environment</returns>
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;
}
/// <summary>
/// Prüft ob die PayPal Credentials korrekt sind und eine Verbindung zur Api aufgenommen werden kann
/// </summary>
/// <param name="clientId">PayPal ClientId</param>
/// <param name="secret">PayPal Secret</param>
/// <returns>true wenn erfolgreich, false sonst</returns>
public async Task<bool> 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;
}
}
/// <summary>
/// Erstellen einer PayPal-Order
/// </summary>
/// <param name="orderId">Id der Bestellung</param>
/// <param name="clientId">PayPal ClientId</param>
/// <param name="secret">PayPal Secret</param>
/// <param name="successUrl">Redirect-Url für ERFOLG</param>
/// <param name="cancelUrl">Redirect-URL für Fehler oder Abbrechen</param>
/// <returns>REdirect-Url zu PayPal oder leer wenn Fehler</returns>
public async Task<string> 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<PurchaseUnitRequest>()
{
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<Item>();
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<Order>();
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;
}
/// <summary>
/// Authorisieren der PayPal Order - Bezahlung durchführen
/// </summary>
/// <param name="payPalOrder">PayPal-Order-Id</param>
/// <param name="clientId">PayPal ClientId</param>
/// <param name="secret">PayPal Secret</param>
/// <returns>true wenn erfolgreich, false sonst</returns>
public async Task<bool> 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<Order>();
return result.Status.ToUpper() == "COMPLETED";
}
}
}