在本教學中,我將向您展示如何使用 PayPal REST API 和 C# 進行付款。他們針對 Ruby、Node.js、Python、PHP 等不同語言提供的所有函式庫都非常相似,因此這裡的所有概念都適用於所有函式庫。
首先,我在 Visual Studio 2015 中建立了一個 MVC 專案:檔案 > 新建 > 專案,然後選擇 ASP.NET 應用程式。
選擇 ASP.NET 5 Web 應用程式 模板,該模板使用新的 MVC 6。如果你熟悉的話,它與 MVC 5 類似。
正如您在下面的照片中看到的,我已向解決方案添加了一些文件和資料夾。主要需要注意的兩件事是:
使用 NuGet 安裝 PayPal SDK。 右鍵點擊解決方案名稱並選擇管理 NuGet 套件,然後搜尋「PayPal」並安裝它。
#要將我們的應用程式與 PayPal 集成,我們需要導航到 PayPal Developers,然後在 REST API 應用程式下,點擊建立應用程式。
為您的應用程式命名並選擇與該應用程式關聯的沙盒開發者帳戶。出於測試目的,我們可以導航到 http://sandbox.paypal.com 並使用沙箱登錄詳細資訊進行登錄,以查看測試 PayPal 帳戶和交易。
點擊建立應用程式後,我們會看到包含客戶端 ID 和秘密令牌的確認畫面.
將 clientId 和 clientSecret 令牌複製到 appsettings.json
,如螢幕截圖所示如下:
PayPal 提供了沙盒環境進行測試。您可以從那裡建立測試買家和賣家帳戶。註冊後,您將在沙盒中擁有一個與您的開發者帳戶綁定的企業帳戶。
要建立新的測試帳戶,請登入開發者網站,然後點擊控制面板標籤並導覽至沙盒 > 帳戶。 您可以在此處查看測試帳戶清單(如果有):
如果您尚未建立測試帳戶,請繼續並點擊建立帳戶在右上角,建立至少一個測試個人帳戶和一個測試企業帳戶。
建立測試帳戶後,您可以使用測試電子郵件地址和密碼透過 www.sandbox.paypal.com 登入您在上一個表格上指派給每個帳戶的資訊。這對於測試當您使用「個人測試帳戶」購買商品時資金是否會轉移到您的「測試企業帳戶」非常有用。現在您已準備好開始與 PayPal 整合並測試資金是否從一個帳戶轉移到另一個帳戶。
PayPal 提供不同的付款方式。您可以使用直接信用卡付款,這表示您的客戶無法看到 PayPal 登入頁面或摘要 - 這一切都發生在您的網站上。為此,您需要符合 PCI 標準,我建議使用 Stripe,因為您只需要使用其 JavaScript 程式庫的 SSL。另一方面,要透過 PayPal 付款,需要三個步驟:
在我的 MVC 專案的 Services 資料夾中,我建立了 PayPalPaymentService 類,並在其中新增了以下方法:
#public static Payment CreatePayment(string baseUrl, string intent) { // ### Api Context // Pass in a `APIContext` object to authenticate // the call and to send a unique request id // (that ensures idempotency). The SDK generates // a request id if you do not pass one explicitly. var apiContext = PayPalConfiguration.GetAPIContext(); // Payment Resource var payment = new Payment() { intent = intent, // `sale` or `authorize` payer = new Payer() { payment_method = "paypal" }, transactions = GetTransactionsList(), redirect_urls = GetReturnUrls(baseUrl, intent) }; // Create a payment using a valid APIContext var createdPayment = payment.Create(apiContext); return createdPayment; } private static List<Transaction> GetTransactionsList() { // A transaction defines the contract of a payment // what is the payment for and who is fulfilling it. var transactionList = new List<Transaction>(); // The Payment creation API requires a list of Transaction; // add the created Transaction to a List transactionList.Add(new Transaction() { description = "Transaction description.", invoice_number = GetRandomInvoiceNumber(), amount = new Amount() { currency = "USD", total = "100.00", // Total must be equal to sum of shipping, tax and subtotal. details = new Details() // Details: Let's you specify details of a payment amount. { tax = "15", shipping = "10", subtotal = "75" } }, item_list = new ItemList() { items = new List<Item>() { new Item() { name = "Item Name", currency = "USD", price = "15", quantity = "5", sku = "sku" } } } }); return transactionList; } private static RedirectUrls GetReturnUrls(string baseUrl, string intent) { var returnUrl = intent == "sale" ? "/Home/PaymentSuccessful" : "/Home/AuthorizeSuccessful"; // Redirect URLS // These URLs will determine how the user is redirected from PayPal // once they have either approved or canceled the payment. return new RedirectUrls() { cancel_url = baseUrl + "/Home/PaymentCancelled", return_url = baseUrl + returnUrl }; } public static Payment ExecutePayment(string paymentId, string payerId) { // ### Api Context // Pass in a `APIContext` object to authenticate // the call and to send a unique request id // (that ensures idempotency). The SDK generates // a request id if you do not pass one explicitly. var apiContext = PayPalConfiguration.GetAPIContext(); var paymentExecution = new PaymentExecution() { payer_id = payerId }; var payment = new Payment() { id = paymentId }; // Execute the payment. var executedPayment = payment.Execute(apiContext, paymentExecution); return executedPayment; }
此呼叫中傳遞了一些參數:
可以從控制器中使用先前的功能,如下所示:
public IActionResult CreatePayment() { var payment = PayPalPaymentService.CreatePayment(GetBaseUrl(), "sale"); return Redirect(payment.GetApprovalUrl()); } public IActionResult PaymentCancelled() { // TODO: Handle cancelled payment return RedirectToAction("Error"); } public IActionResult PaymentSuccessful(string paymentId, string token, string PayerID) { // Execute Payment var payment = PayPalPaymentService.ExecutePayment(paymentId, PayerID); return View(); }
如您所見,我創建了三個操作:
#此場景與前一個案例非常相似。如果您嘗試預訂尚未上市的產品,您可能需要使用此方法。獲得這筆款項的步驟是:
為了實現這種類型的付款,我只在 PayPalPaymentService 類別中新增了一個新方法來捕獲付款:
public static Capture CapturePayment(string paymentId) { var apiContext = PayPalConfiguration.GetAPIContext(); var payment = Payment.Get(apiContext, paymentId); var auth = payment.transactions[0].related_resources[0].authorization; // Specify an amount to capture. By setting 'is_final_capture' to true, all remaining funds held by the authorization will be released from the funding instrument. var capture = new Capture() { amount = new Amount() { currency = "USD", total = "4.54" }, is_final_capture = true }; // Capture an authorized payment by POSTing to // URI v1/payments/authorization/{authorization_id}/capture var responseCapture = auth.Capture(apiContext, capture); return responseCapture; }
然後,我在 HomeController 中新增了兩個新操作來顯示此類付款:
public IActionResult AuthorizePayment() { var payment = PayPalPaymentService.CreatePayment(GetBaseUrl(), "authorize"); return Redirect(payment.GetApprovalUrl()); } public IActionResult AuthorizeSuccessful(string paymentId, string token, string PayerID) { // Capture Payment var capture = PayPalPaymentService.CapturePayment(paymentId); return View(); }
在這些程式碼範例中,為了簡單起見,我對付款變數值進行了硬編碼。在您的實際應用程式中,您可能會將它們包裝在將所有這些值作為變數的方法中,以便您可以動態設定和重複使用所有內容。
這在 PayPal 中稱為「結算計劃」 - 您可以建立定期付款計劃,並透過建立結算協議為您的客戶訂閱結算計劃。使用 PayPal REST API,您可以建立、更新或刪除結算計畫;如果您想建立一個管理面板來管理您的企業的這些事情,您可能會使用這個東西。
向客戶創建經常性費用的步驟如下:
建立定義計費週期的計費計畫。這是我們在建立計劃時需要傳遞的參數的摘要。
这是一个代码片段,展示了如何创建计费计划:
// Define the plan and attach the payment definitions and merchant preferences. // More Information: https://developer.paypal.com/webapps/developer/docs/api/#create-a-plan var billingPlan = new Plan { name = "Tuts+ Plus", description = "Monthly plan for courses.", type = "fixed", // Define the merchant preferences. // More Information: https://developer.paypal.com/webapps/developer/docs/api/#merchantpreferences-object merchant_preferences = new MerchantPreferences() { setup_fee = GetCurrency("0"), // $0 return_url = "returnURL", // Retrieve from config cancel_url = "cancelURL", // Retrieve from config auto_bill_amount = "YES", initial_fail_amount_action = "CONTINUE", max_fail_attempts = "0" }, payment_definitions = new List<PaymentDefinition> { // Define a trial plan that will only charge $9.99 for the first // month. After that, the standard plan will take over for the // remaining 11 months of the year. new PaymentDefinition() { name = "Trial Plan", type = "TRIAL", frequency = "MONTH", frequency_interval = "1", amount = GetCurrency("0"), // Free for the 1st month cycles = "1", charge_models = new List<ChargeModel> { new ChargeModel() { type = "TAX", amount = GetCurrency("1.65") // If we need to charge Tax }, new ChargeModel() { type = "SHIPPING", amount = GetCurrency("9.99") // If we need to charge for Shipping } } }, // Define the standard payment plan. It will represent a monthly // plan for $19.99 USD that charges once month for 11 months. new PaymentDefinition { name = "Standard Plan", type = "REGULAR", frequency = "MONTH", frequency_interval = "1", amount = GetCurrency("15.00"), // > NOTE: For `IFNINITE` type plans, `cycles` should be 0 for a `REGULAR` `PaymentDefinition` object. cycles = "11", charge_models = new List<ChargeModel> { new ChargeModel { type = "TAX", amount = GetCurrency("2.47") }, new ChargeModel() { type = "SHIPPING", amount = GetCurrency("9.99") } } } } }; // Get PayPal Config var apiContext = PayPalConfiguration.GetAPIContext(); // Create Plan plan.Create(apiContext);
新创建的结算计划处于 CREATED 状态。将其激活为“活动”状态,以便您的客户可以订阅该计划。要激活该计划,我们需要发出 PATCH 请求:
// Activate the plan var patchRequest = new PatchRequest() { new Patch() { op = "replace", path = "/", value = new Plan() { state = "ACTIVE" } } }; plan.Update(apiContext, patchRequest);
如您所见,PayPal 库是其 REST API 的直接包装器,这很好,但与 Stripe 等其他 API 相比,该 API 也非常复杂。因此,将所有 PayPal 通信包装在对象中,为我们的应用程序提供更清晰、更简单的 API,这确实是一个不错的选择。在这里您可以看到封装在多个带有参数的函数中的代码的样子:
public static Plan CreatePlanObject(string planName, string planDescription, string returnUrl, string cancelUrl, string frequency, int frequencyInterval, decimal planPrice, decimal shippingAmount = 0, decimal taxPercentage = 0, bool trial = false, int trialLength = 0, decimal trialPrice = 0) { // Define the plan and attach the payment definitions and merchant preferences. // More Information: https://developer.paypal.com/docs/rest/api/payments.billing-plans/ return new Plan { name = planName, description = planDescription, type = PlanType.Fixed, // Define the merchant preferences. // More Information: https://developer.paypal.com/webapps/developer/docs/api/#merchantpreferences-object merchant_preferences = new MerchantPreferences() { setup_fee = GetCurrency("1"), return_url = returnUrl, cancel_url = cancelUrl, auto_bill_amount = "YES", initial_fail_amount_action = "CONTINUE", max_fail_attempts = "0" }, payment_definitions = GetPaymentDefinitions(trial, trialLength, trialPrice, frequency, frequencyInterval, planPrice, shippingAmount, taxPercentage) }; } private static List<PaymentDefinition> GetPaymentDefinitions(bool trial, int trialLength, decimal trialPrice, string frequency, int frequencyInterval, decimal planPrice, decimal shippingAmount, decimal taxPercentage) { var paymentDefinitions = new List<PaymentDefinition>(); if (trial) { // Define a trial plan that will charge 'trialPrice' for 'trialLength' // After that, the standard plan will take over. paymentDefinitions.Add( new PaymentDefinition() { name = "Trial", type = "TRIAL", frequency = frequency, frequency_interval = frequencyInterval.ToString(), amount = GetCurrency(trialPrice.ToString()), cycles = trialLength.ToString(), charge_models = GetChargeModels(trialPrice, shippingAmount, taxPercentage) }); } // Define the standard payment plan. It will represent a 'frequency' (monthly, etc) // plan for 'planPrice' that charges 'planPrice' (once a month) for #cycles. var regularPayment = new PaymentDefinition { name = "Standard Plan", type = "REGULAR", frequency = frequency, frequency_interval = frequencyInterval.ToString(), amount = GetCurrency(planPrice.ToString()), // > NOTE: For `IFNINITE` type plans, `cycles` should be 0 for a `REGULAR` `PaymentDefinition` object. cycles = "11", charge_models = GetChargeModels(trialPrice, shippingAmount, taxPercentage) }; paymentDefinitions.Add(regularPayment); return paymentDefinitions; } private static List<ChargeModel> GetChargeModels(decimal planPrice, decimal shippingAmount, decimal taxPercentage) { // Create the Billing Plan var chargeModels = new List<ChargeModel>(); if (shippingAmount > 0) { chargeModels.Add(new ChargeModel() { type = "SHIPPING", amount = GetCurrency(shippingAmount.ToString()) }); } if (taxPercentage > 0) { chargeModels.Add(new ChargeModel() { type = "TAX", amount = GetCurrency(String.Format("{0:f2}", planPrice * taxPercentage / 100)) }); } return chargeModels; }
您可以通过提出“PATCH”请求来更新现有结算方案的信息。这是一个包装该调用的函数:
public static void UpdateBillingPlan(string planId, string path, object value) { // PayPal Authentication tokens var apiContext = PayPalConfiguration.GetAPIContext(); // Retrieve Plan var plan = Plan.Get(apiContext, planId); // Activate the plan var patchRequest = new PatchRequest() { new Patch() { op = "replace", path = path, value = value } }; plan.Update(apiContext, patchRequest); }
要更新计费计划描述,我们可以调用此函数并传递正确的参数:
UpdateBillingPlan( planId: "P-5FY40070P6526045UHFWUVEI", path: "/", value: new Plan { description = "new description" });
理想情况下,当您不想接受新客户加入结算计划时,您需要将其更新为“非活动”状态。这不会影响该计划的现有计费协议。只需调用 UpdateBillingPlan 函数即可完成此操作:
UpdateBillingPlan( planId: "P-5FY40070P6526045UHFWUVEI", path: "/", value: new Plan { state = "INACTIVE" });
创建一个或多个结算计划后,您希望开始让客户注册您的订阅计划。为此,您需要收集客户详细信息并向 PayPal 提出请求。为了能够测试此功能,我向 HomeController 添加了几个操作:
public IActionResult Subscribe() { var plan = PayPalSubscriptionsService.CreateBillingPlan("Tuts+ Plan", "Test plan for this article", GetBaseUrl()); var subscription = PayPalSubscriptionsService.CreateBillingAgreement(plan.id, new PayPal.Api.ShippingAddress { city = "London", line1 = "line 1", postal_code = "SW1A 1AA", country_code = "GB" }, "Pedro Alonso", "Tuts+", DateTime.Now); return Redirect(subscription.GetApprovalUrl()); } public IActionResult SubscribeSuccess(string token) { // Execute approved agreement PayPalSubscriptionsService.ExecuteBillingAgreement(token); return View(); } public IActionResult SubscribeCancel(string token) { // TODO: Handle cancelled payment return RedirectToAction("Error"); }
正如您在前面的代码片段中看到的,我已将大部分功能包装在几个方法中。第一个是上一节中解释的“CreateBillingPlan”。第二个是“CreateBillingAgreement”,用于为用户订阅计划:
public static Agreement CreateBillingAgreement(string planId, ShippingAddress shippingAddress, string name, string description, DateTime startDate) { // PayPal Authentication tokens var apiContext = PayPalConfiguration.GetAPIContext(); var agreement = new Agreement() { name = name, description = description, start_date = startDate.ToString("yyyy-MM-ddTHH:mm:ss") + "Z", payer = new Payer() { payment_method = "paypal" }, plan = new Plan() { id = planId }, shipping_address = shippingAddress }; var createdAgreement = agreement.Create(apiContext); return createdAgreement; }
第三种方法是“ExecuteBillingAgreement”。成功订阅批准后,我们使用返回的令牌来激活订阅:
public static void ExecuteBillingAgreement(string token) { // PayPal Authentication tokens var apiContext = PayPalConfiguration.GetAPIContext(); var agreement = new Agreement() { token = token }; var executedAgreement = agreement.Execute(apiContext); }
使用此方法暂停协议:
public static void SuspendBillingAgreement(string agreementId) { var apiContext = PayPalConfiguration.GetAPIContext(); var agreement = new Agreement() { id = agreementId }; agreement.Suspend(apiContext, new AgreementStateDescriptor() { note = "Suspending the agreement" }); }
这个与上一个非常相似:
public static void ReactivateBillingAgreement(string agreementId) { var apiContext = PayPalConfiguration.GetAPIContext(); var agreement = new Agreement() { id = agreementId }; agreement.ReActivate(apiContext, new AgreementStateDescriptor() { note = "Reactivating the agreement" }); }
使用此功能取消计划:
public static void CancelBillingAgreement(string agreementId) { var apiContext = PayPalConfiguration.GetAPIContext(); var agreement = new Agreement() { id = agreementId }; agreement.Cancel(apiContext, new AgreementStateDescriptor() { note = "Cancelling the agreement" }); }
这个选项非常有限,我希望从这次通话中可以更改订阅计划,以升级或降级客户。与 Stripe 不同,单次调用不支持此功能。您需要通过取消当前协议并创建新的升级或降级协议来处理这种情况。这并不理想,但将来可能会改变。
这是人们用来与 PayPal 集成的最常用功能的概述。他们的 API 比本文中解释的集成方法要大得多 - 您还可以发放退款和部分退款,并且他们针对本文涵盖的示例中的边缘情况提供了许多不同的选项。如果您有兴趣获得有关任何特定集成的更多详细信息,请在评论中留下建议。
以上是深入解析:PayPal整合第二部分:PayPal REST API的詳細內容。更多資訊請關注PHP中文網其他相關文章!