mirror of
https://github.com/bitwarden/server
synced 2026-01-02 16:43:25 +00:00
[AC-1800] PayPal IPN Refactor (#3619)
* Add more logging to PayPal IPN webhook * Add PayPalIPNClient tests * Add PayPalControllerTests --------- Co-authored-by: aelinton <95626935+aelinton@users.noreply.github.com>
This commit is contained in:
110
src/Billing/Models/PayPalIPNTransactionModel.cs
Normal file
110
src/Billing/Models/PayPalIPNTransactionModel.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Web;
|
||||
|
||||
namespace Bit.Billing.Models;
|
||||
|
||||
public class PayPalIPNTransactionModel
|
||||
{
|
||||
public string TransactionId { get; }
|
||||
public string TransactionType { get; }
|
||||
public string ParentTransactionId { get; }
|
||||
public string PaymentStatus { get; }
|
||||
public string PaymentType { get; }
|
||||
public decimal MerchantGross { get; }
|
||||
public string MerchantCurrency { get; }
|
||||
public string ReceiverId { get; }
|
||||
public DateTime PaymentDate { get; }
|
||||
public Guid? UserId { get; }
|
||||
public Guid? OrganizationId { get; }
|
||||
public bool IsAccountCredit { get; }
|
||||
|
||||
public PayPalIPNTransactionModel(string formData)
|
||||
{
|
||||
var queryString = HttpUtility.ParseQueryString(formData);
|
||||
|
||||
var data = queryString
|
||||
.AllKeys
|
||||
.ToDictionary(key => key, key => queryString[key]);
|
||||
|
||||
TransactionId = Extract(data, "txn_id");
|
||||
TransactionType = Extract(data, "txn_type");
|
||||
ParentTransactionId = Extract(data, "parent_txn_id");
|
||||
PaymentStatus = Extract(data, "payment_status");
|
||||
PaymentType = Extract(data, "payment_type");
|
||||
|
||||
var merchantGross = Extract(data, "mc_gross");
|
||||
if (!string.IsNullOrEmpty(merchantGross))
|
||||
{
|
||||
MerchantGross = decimal.Parse(merchantGross);
|
||||
}
|
||||
|
||||
MerchantCurrency = Extract(data, "mc_currency");
|
||||
ReceiverId = Extract(data, "receiver_id");
|
||||
|
||||
var paymentDate = Extract(data, "payment_date");
|
||||
PaymentDate = ToUTCDateTime(paymentDate);
|
||||
|
||||
var custom = Extract(data, "custom");
|
||||
|
||||
if (string.IsNullOrEmpty(custom))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var metadata = custom.Split(',')
|
||||
.Where(field => !string.IsNullOrEmpty(field) && field.Contains(':'))
|
||||
.Select(field => field.Split(':'))
|
||||
.ToDictionary(parts => parts[0], parts => parts[1]);
|
||||
|
||||
if (metadata.TryGetValue("user_id", out var userIdStr) &&
|
||||
Guid.TryParse(userIdStr, out var userId))
|
||||
{
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
if (metadata.TryGetValue("organization_id", out var organizationIdStr) &&
|
||||
Guid.TryParse(organizationIdStr, out var organizationId))
|
||||
{
|
||||
OrganizationId = organizationId;
|
||||
}
|
||||
|
||||
IsAccountCredit = custom.Contains("account_credit:1");
|
||||
}
|
||||
|
||||
private static string Extract(IReadOnlyDictionary<string, string> data, string key)
|
||||
{
|
||||
var success = data.TryGetValue(key, out var value);
|
||||
return success ? value : null;
|
||||
}
|
||||
|
||||
private static DateTime ToUTCDateTime(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var success = DateTime.TryParseExact(input,
|
||||
new[]
|
||||
{
|
||||
"HH:mm:ss dd MMM yyyy PDT",
|
||||
"HH:mm:ss dd MMM yyyy PST",
|
||||
"HH:mm:ss dd MMM, yyyy PST",
|
||||
"HH:mm:ss dd MMM, yyyy PDT",
|
||||
"HH:mm:ss MMM dd, yyyy PST",
|
||||
"HH:mm:ss MMM dd, yyyy PDT"
|
||||
}, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTime);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var pacificTime = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time")
|
||||
: TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
|
||||
|
||||
return TimeZoneInfo.ConvertTimeToUtc(dateTime, pacificTime);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user