apeescape2.com
  • メイン
  • デザイナーライフ
  • リモートの台頭
  • ライフスタイル
  • Kpiと分析
Webフロントエンド

Ruby onRailsでのStripeとPayPalの支払い方法の統合

AliExpress、Ebay、Amazonなどの巨大なeコマース企業にとって重要な機能は、支払いを安全に処理する方法であり、これは彼らのビジネスに不可欠です。この機能が失敗した場合、その結果は壊滅的なものになります。これは業界のリーダーに適用され、 Ruby onRails開発者 eコマースアプリに取り組んでいます。

サイバーセキュリティは攻撃を防ぐために不可欠であり、トランザクションプロセスをより安全にする方法は、サードパーティのサービスにそれを処理するように依頼することです。アプリケーションに支払いゲートウェイを含めることは、ユーザー承認、データ暗号化、およびダッシュボードを提供するため、この目標を達成する方法であり、トランザクションのステータスをその場で追跡できます。

ウェブ上にはさまざまなペイメントゲートウェイサービスがありますが、この記事では統合に焦点を当てます 縞 そして PayPal Railsアプリケーションに。他のいくつかに言及すると:Amazon Payments、Square、SecurePay、WorldPay、Authorize.Net、2Checkout.com、Braintree、Amazon、またはBlueSnap。



ペイメントゲートウェイ統合の仕組み

支払いゲートウェイを含むトランザクションの一般的な表現
支払いゲートウェイを含むトランザクションの一般的な表現

一般に、ユーザーがログイン/クレジットカードデータを挿入できるフォーム/ボタンがアプリケーションにあります。 PayPalとStripeは、iframeを使用することで、この最初のステップをより安全にしています。フォームまたはpopupsこれにより、アプリケーションはこのトランザクションを表すトークンを返すため、機密性の高いユーザーのクレジットカード情報を保存できなくなります。一部のユーザーは、サードパーティのサービスがトランザクションプロセスを処理していることを知っていることで、支払いを処理することにすでに自信を持っているかもしれません。そのため、これもアプリケーションの魅力になります。

ユーザー情報を認証した後、支払いゲートウェイは、支払いを決済するために銀行と通信する支払い処理業者に連絡することによって支払いを確認します。これにより、トランザクションが適切に借方/貸方に記入されます。

Stripeは、クレジットカード番号、cvv、および有効期限を尋ねるクレジットカードフォームを使用します。したがって、ユーザーはセキュリティで保護されたStripe入力にクレジットカード情報を入力する必要があります。この情報を提供した後、アプリケーションのバックエンドはトークンを介してこの支払いを処理します。

Stripeとは異なり、PayPalはユーザーをPayPalログインページにリダイレクトします。ユーザーはPayPalを介して支払い方法を承認および選択します。この場合も、バックエンドはユーザーの機密データの代わりにトークンを処理します。

これらの2つの支払いゲートウェイの場合、バックエンドは、OK / NOK応答を返すStripeまたはPayPalAPIを介してトランザクションの実行を続行するように要求する必要があるため、アプリケーションはそれに応じてユーザーを成功ページまたはエラーページにリダイレクトする必要があることに注意してください。

この記事の目的は、これら2つの支払いゲートウェイを単一のアプリケーションに統合するためのクイックガイドを提供することです。すべてのテストで、支払いをシミュレートするために、StripeとPayPalが提供するサンドボックスとテストアカウントを使用します。

セットアップ

支払いゲートウェイを統合する前に、gem、データベーステーブル、およびインデックスページを追加してアプリケーションを初期化するためのセットアップを行います。このプロジェクトは、Railsバージョン5.2.3とRuby2.6.3を使用して作成されました。

注意: あなたは新しいをチェックアウトすることができます 最近の記事のRails6の機能 。

ステップ1: Railsアプリケーションを初期化します。

railsを使用してプロジェクトの初期化を実行し、プロジェクトを初期化します。アプリ名を使用したコマンド:

rails new YOUR_APP_NAME

そしてcdアプリケーションフォルダにあります。

ステップ2: gemをインストールします。

StripeとPayPalの宝石に加えて、他のいくつかの宝石が追加されました。

  • devise:ユーザーの認証と承認に使用されます
  • haml:ユーザーページをレンダリングするためのテンプレートツール
  • jquery-rails:jqueryの場合フロントエンドスクリプトで
  • money-rails:フォーマットされた金額の値を表示するため

Gemfileに追加:

gem 'devise', '>= 4.7.1' gem 'haml' gem 'jquery-rails' gem 'money-rails'

追加した後、CLIで実行します。

bundle install

ステップ3: 宝石を初期化します。

これらのgemのいくつかは、bundleを介してインストールする以外に、初期化が必要になります。

デバイスのインストール:

rails g devise:install

初期化money-rails:

rails g money_rails:initializer

初期化jquery-rails app/assets/javascripts/application.jsの下部に追加する以下:

//= require jquery //= require jquery_ujs

ステップ4: テーブルと移行

このプロジェクトでは3つのテーブルが使用されます ユーザー 、 製品 、および 注文 。

  • Users:デバイスによって生成されます
  • Products列:
    • name
    • price_cents
    • Stripe_plan_name:Stripeで作成されたサブスクリプションプランを表すID。ユーザーはそれをサブスクライブできます。このフィールドは、Stripeプランに関連付けられている製品にのみ必要です。
    • paypal_plan_name:stripe_plan_nameと同じしかしPayPalの場合
  • Orders列:
    • product_id
    • user_id
    • status:注文が保留中、失敗、または支払い済みの場合に通知されます。
    • token:これは、トランザクションを初期化するためにAPI(StripeまたはPayPal)から生成されたトークンです。
    • price_cents:製品と同様ですが、この値を注文レコードで永続化するために使用されます
    • payment_gateway:PayPalまたはStripeの注文に使用されている支払いゲートウェイを保存します
    • customer_id:これは、サブスクリプション用にStripeの顧客を保存するためにStripeに使用されます。これについては、後のセクションで詳しく説明します。

これらのテーブルを生成するには、いくつかの移行を生成する必要があります。

を作成するため ユーザーテーブル 。実行:

rails g devise User

を作成するため 製品表 。以下を実行して移行を生成します。

rails generate migration CreateProducts name:string stripe_plan_name:string paypal_plan_name:string

作成した移行ファイルを開きます。このファイルはdb/migrate/にあり、移行が次のようになるように変更を加えます。

class CreateProducts

を作成するため 注文表 。以下を実行して移行を生成します。

rails generate migration CreateOrders product_id:integer user_id:integer status:integer token:string charge_id:string error_message:string customer_id:string payment_gateway:integer

ここでも、作成した移行ファイルを開きます。このファイルはdb/migrate/にあります。次のように見えるように、そのファイルに変更を加えます。

class CreateOrders

以下を実行して、データベースの移行を実行します。

rails db:migrate

ステップ5: モデルを作成します。

ユーザーモデルはデバイスのインストールからすでに作成されており、変更する必要はありません。その上、2つのモデルが作成されます 製品 そして 注文 。

製品。 新しいファイルapp/models/product.rbを次のように追加します。

class Product

注文。 新しいファイルapp/models/order.rbを次のように追加します。

class Order { where(created_at: 1.minutes.ago..DateTime.now) } def set_paid self.status = Order.statuses[:paid] end def set_failed self.status = Order.statuses[:failed] end def set_paypal_executed self.status = Order.statuses[:paypal_executed] end end

ステップ6: データベースにデータを入力します。

ユーザーと2つの製品がコンソールに作成されます。注文記録は、支払いテストに従って作成されます。

  • 実行rails s
  • ブラウザでhttp://localhost:3000にアクセスします
  • サインアップページにリダイレクトされます。
  • メールアドレスとパスワードを入力して、ユーザーを登録します。
  • ターミナルでは、データベースにユーザーが作成されたことを示す次のログが表示されます。
User Create (0.1ms) INSERT INTO 'users' ('email', 'encrypted_password', 'created_at', 'updated_at') VALUES (?, ?, ?, ?) …
  • rails cを実行して、サブスクリプションなしで2つの製品を作成しますと追加:
    • Product.create(name: 'Awesome T-Shirt', price_cents: 3000)
    • Product.create(name: 'Awesome Sneakers', price_cents: 5000)

ステップ7: インデックスページを作成する

プロジェクトのメインページには、購入またはサブスクリプションの製品選択が含まれています。さらに、支払い方法の選択(StripeまたはPayPal)のセクションもあります。送信ボタンは、支払いゲートウェイの種類ごとにも使用されます。PayPalの場合は、JavaScriptライブラリを介して独自のボタンデザインを追加します。

まず、indexのルートを作成しますおよびsubmit config/routes.rbで。

Rails.application.routes.draw do devise_for :users get '/', to: 'orders#index' post '/orders/submit', to: 'orders#submit' end

アクションの作成と追加indexおよびsubmit注文コントローラーでapp/controllers/orders_controller.rb。 orders#indexアクションは、フロントエンドで消費される2つの変数を格納します:@products_purchase計画のない製品のリストと@products_subscriptionがありますPayPalとStripeの両方のプランの製品があります。

class OrdersController

app/views/orders/index.html.hamlにファイルを作成します。このファイルには、送信方法を介してバックエンドに送信するすべての入力と、支払いゲートウェイと製品選択の相互作用が含まれています。入力名の属性は次のとおりです。

  • Orders[product_id]製品IDを格納します。
  • Orders[payment_gateway]ストライプまたはPayPalのいずれかの値を持つ支払いゲートウェイが含まれています。
%div %h1 List of products = form_tag({:controller => 'orders', :action => 'submit' }, {:id => 'order-details'}) do %input{id:'order-type', :type=>'hidden', :value=>'stripe', :name=>'orders[payment_gateway]'} .form_row %h4 Charges/Payments - @products_purchase.each do |product| %div{'data-charges-and-payments-section': true} = radio_button_tag 'orders[product_id]', product.id, @products_purchase.first == product %span{id: 'radioButtonName#{product.id}'} #{product.name} %span{id: 'radioButtonPrice#{product.id}', :'data-price' => '#{product.price_cents}'} #{humanized_money_with_symbol product.price} %br %h4 Subscriptions - @products_subscription.each do |product| %div = radio_button_tag 'orders[product_id]', product.id, false %span{id: 'radioButtonName#{product.id}'} #{product.name} %span{id: 'radioButtonPrice#{product.id}', :'data-price' => '#{product.price_cents}'} #{humanized_money_with_symbol product.price} %br %hr %h1 Payment Method .form_row %div = radio_button_tag 'payment-selection', 'stripe', true, onclick: 'changeTab();' %span Stripe %br %div = radio_button_tag 'payment-selection', 'paypal', false, onclick: 'changeTab();' %span Paypal %br %br %div{id:'tab-stripe', class:'paymentSelectionTab active'} %div{id:'card-element'} %div{id:'card-errors', role:'alert'} %br %br = submit_tag 'Buy it!', id: 'submit-stripe' %div{id:'tab-paypal', class:'paymentSelectionTab'} %div{id: 'submit-paypal'} %br %br %hr :javascript function changeTab() { var newActiveTabID = $('input[name='payment-selection']:checked').val(); $('.paymentSelectionTab').removeClass('active'); $('#tab-' + newActiveTabID).addClass('active'); } :css #card-element { width:500px; } .paymentSelectionTab { display: none; } .paymentSelectionTab.active { display: block !important; }

rails sを使用してアプリケーションを実行する場合http://localhost:3000のページにアクセスしてください。このページは次のように表示されます。

StripeとPayPalが統合されていない生のインデックスページ
StripeとPayPalが統合されていない生のインデックスページ

ペイメントゲートウェイ資格情報ストレージ

PayPalとStripeキーは、Gitによって追跡されないファイルに保存されます。このファイルには、ペイメントゲートウェイごとに2種類のキーが保存されています。ここでは、それらにダミー値を使用します。これらのキーを作成するための追加の指示は、以降のセクションに示されています。

ステップ1: これを.gitignoreに追加します。

/config/application.yml

ステップ2: config/application.ymlに資格情報を使用してファイルを作成します。これらのAPIにアクセスするためのすべてのPayPalおよびStripeサンドボックス/テストキーが含まれている必要があります。

test: &default PAYPAL_ENV: sandbox PAYPAL_CLIENT_ID: YOUR_CREDENTIAL_HERE PAYPAL_CLIENT_SECRET: YOUR_CREDENTIAL_HERE STRIPE_PUBLISHABLE_KEY: YOUR_CREDENTIAL_HERE STRIPE_SECRET_KEY: YOUR_CREDENTIAL_HERE development: <<: *default

ステップ3: ファイルから変数を保存するためにconfig/application.ymlアプリケーションの起動時に、これらの行をconfig/application.rbに追加しますApplicationの内部クラスなので、ENVで利用できます。

config_file = Rails.application.config_for(:application) config_file.each do |key,value| ENV[key] = value end unless config_file.nil?

ストライプ構成

Stripe APIを使用するためのgemを追加します:stripe-rails。料金とサブスクリプションを処理できるように、Stripeアカウントを作成することも必要です。必要に応じて、StripeAPIのAPIメソッドを参照できます。 公式ドキュメント 。

ステップ1: ストライプレールの宝石をプロジェクトに追加します。

ザ・ ストライプレールの宝石 このプロジェクトで使用されるすべてのAPIリクエストのインターフェースを提供します。

これをGemfileに追加します。

gem 'stripe-rails'

実行:

bundle install

ステップ2: APIキーを生成します。

Stripeと通信するためのAPIキーを取得するには、Stripeでアカウントを作成する必要があります。アプリケーションをテストするには、テストモードを使用できるため、Stripeアカウントの作成プロセスで実際のビジネス情報を入力する必要はありません。

  • アカウントをお持ちでない場合は、Stripeでアカウントを作成してください( https://dashboard.stripe.com/ )。
  • Stripeダッシュボードにいる間に、ログインした後、切り替えます テストデータの表示 オン。
  • で https://dashboard.stripe.com/test/apikeys 、YOUR_CREDENTIAL_HEREを置き換えます値STRIPE_PUBLISHABLE_KEYの場合およびSTRIPE_SECRET_KEY /config/application.ymlでPublishable Keyのコンテンツを使用およびSecret key。

ステップ3: Stripeモジュールを初期化します

キーを置き換えるだけでなく、Stripeモジュールを初期化して、ENVですでに設定されているキーを使用するようにする必要があります。

config/initializers/stripe.rbにファイルを作成しますと:

Rails.application.configure do config.stripe.secret_key = ENV['STRIPE_SECRET_KEY'] config.stripe.publishable_key = ENV['STRIPE_PUBLISHABLE_KEY'] end

ステップ4: フロントエンドにStripeを統合します。

Stripe JavaScriptライブラリと、ユーザーのクレジットカード情報を表すトークンを送信するためのロジックを追加し、バックエンドで処理します。

index.html.hamlでファイル、これをファイルの先頭に追加します。これにより、Stripeモジュール(gemが提供)を使用して、Stripejavascriptライブラリがユーザーのページに追加されます。

= stripe_javascript_tag

Stripeは、APIを介して作成された安全な入力フィールドを使用します。 iframeで作成されるためこのAPIを介して作成されているため、ユーザーのクレジットカード情報を処理する可能性のある脆弱性について心配する必要はありません。さらに、バックエンドはユーザーの機密データを処理/保存することができず、この情報を表すトークンのみを受け取ります。

これらの入力フィールドは、stripe.elements().create('card')を呼び出すことによって作成されます。その後、返されたオブジェクトをmount()で呼び出す必要があります。これらの入力をマウントする必要があるHTML要素ID /クラスを引数として渡すことによって。詳細については、次のURLをご覧ください。 縞 。

ユーザーがStripe支払い方法で送信ボタンを押すと、作成されたStripeカード要素に対してpromiseを返す別のAPI呼び出しが実行されます。

stripe.createToken(card).then(function(result)

resultこの関数の変数には、プロパティエラーが割り当てられていない場合、属性result.token.idにアクセスすることで取得できるトークンがあります。このトークンはバックエンドに送信されます。

これらの変更を行うには、コメント付きコードを置き換えます// YOUR STRIPE AND PAYPAL CODE WILL BE HERE index.html.hamlでと:

(function setupStripe() { //Initialize stripe with publishable key var stripe = Stripe('#{ENV['STRIPE_PUBLISHABLE_KEY']}'); //Create Stripe credit card elements. var elements = stripe.elements(); var card = elements.create('card'); //Add a listener in order to check if card.addEventListener('change', function(event) { //the div card-errors contains error details if any var displayError = document.getElementById('card-errors'); document.getElementById('submit-stripe').disabled = false; if (event.error) { // Display error displayError.textContent = event.error.message; } else { // Clear error displayError.textContent = ''; } }); // Mount Stripe card element in the #card-element div. card.mount('#card-element'); var form = document.getElementById('order-details'); // This will be called when the #submit-stripe button is clicked by the user. form.addEventListener('submit', function(event) { $('#submit-stripe').prop('disabled', true); event.preventDefault(); stripe.createToken(card).then(function(result) { if (result.error) { // Inform that there was an error. var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { // Now we submit the form. We also add a hidden input storing // the token. So our back-end can consume it. var $form = $('#order-details'); // Add a hidden input orders[token] $form.append($('').val(result.token.id)); // Set order type $('#order-type').val('stripe'); $form.submit(); } }); return false; }); }()); //YOUR PAYPAL CODE WILL BE HERE

ページにアクセスすると、新しいStripeセキュア入力フィールドで次のようになります。

Stripeセキュア入力フィールドと統合されたインデックスページ。
Stripeセキュア入力フィールドと統合されたインデックスページ。

ステップ5: アプリケーションをテストします。

クレジットカードフォームにテストカードを記入します( https://stripe.com/docs/testing )ページを送信します。 submitかどうかを確認しますアクションはすべてのパラメーターで呼び出されます( 製品番号 、 Payment_gateway 、および トークン )サーバー出力で。

ストライプチャージ

ストライプ料金は1回限りのトランザクションを表します。したがって、Stripeの請求トランザクションの後、クライアントから直接お金を受け取ります。これは、プランに関連付けられていない製品の販売に最適です。後のセクションで、PayPalで同じトランザクションタイプを実行する方法を示しますが、このタイプのトランザクションのPayPalの名前は 支払い 。

このセクションでは、注文を処理および送信するためのすべてのスケルトンも提供します。 submitで注文を作成しますStripeフォームが送信されたときのアクション。この注文には最初に 保留中 ステータスなので、この注文の処理中に問題が発生した場合でも、注文は 保留中 。

Stripe API呼び出しでエラーが発生した場合は、 失敗しました 状態であり、充電が正常に完了すると、 有料 状態。次のグラフに示すように、ユーザーはStripeAPI応答に従ってリダイレクトされます。

ストライプトランザクション。
ストライプトランザクション。

また、ストライプチャージを行うとIDが返されます。このIDは、後で必要に応じてStripeダッシュボードで検索できるように保存されます。このIDは、注文の払い戻しが必要な場合にも使用できます。この記事では、そのようなことについては説明しません。

ステップ1: Stripeサービスを作成します。

Stripe APIを使用してStripe操作を表すために、シングルトンクラスを使用します。料金を作成するには、メソッドStripe::Charge.createが呼び出され、返されたオブジェクトID属性が注文レコードcharge_idに保存されます。これcreate関数は、フロントエンドで発生したトークン、注文価格、および説明を渡すことによって呼び出されます。

したがって、新しいフォルダーapp/services/ordersを作成し、Stripeサービスを追加します:app/services/orders/stripe.rb Orders::Stripe を含むメソッドexecuteにエントリがあるシングルトンクラス。

class Orders::Stripe INVALID_STRIPE_OPERATION = 'Invalid Stripe Operation' def self.execute(order:, user:) product = order.product # Check if the order is a plan if product.stripe_plan_name.blank? charge = self.execute_charge(price_cents: product.price_cents, description: product.name, card_token: order.token) else #SUBSCRIPTIONS WILL BE HANDLED HERE end unless charge&.id.blank? # If there is a charge with id, set order paid. order.charge_id = charge.id order.set_paid end rescue Stripe::StripeError => e # If a Stripe error is raised from the API, # set status failed and an error message order.error_message = INVALID_STRIPE_OPERATION order.set_failed end private def self.execute_charge(price_cents:, description:, card_token:) Stripe::Charge.create({ amount: price_cents.to_s, currency: 'usd', description: description, source: card_token }) end end

ステップ2: 送信アクションを実装し、Stripeサービスを呼び出します。

orders_controller.rbで、submitに以下を追加しますアクション。基本的にサービスを呼び出しますOrders::Stripe.execute。 2つの新しいプライベート関数も追加されたことに注意してください:prepare_new_orderおよびorder_params。

def submit @order = nil #Check which type of order it is if order_params[:payment_gateway] == 'stripe' prepare_new_order Orders::Stripe.execute(order: @order, user: current_user) elsif order_params[:payment_gateway] == 'paypal' #PAYPAL WILL BE HANDLED HERE end ensure if @order&.save if @order.paid? # Success is rendered when order is paid and saved return render html: SUCCESS_MESSAGE elsif @order.failed? && [email protected] _message.blank? # Render error only if order failed and there is an error_message return render html: @order.error_message end end render html: FAILURE_MESSAGE end private # Initialize a new order and and set its user, product and price. def prepare_new_order @order = Order.new(order_params) @order.user_id = current_user.id @product = Product.find(@order.product_id) @order.price_cents = @product.price_cents end def order_params params.require(:orders).permit(:product_id, :token, :payment_gateway, :charge_id) end

ステップ3: アプリケーションをテストします。

有効なテストカードを使用して送信アクションが呼び出されたときに、成功したメッセージへのリダイレクトを実行するかどうかを確認します。さらに、 ストライプダッシュボード 注文も表示されている場合。

ストライプサブスクリプション

定期支払いのサブスクリプションまたはプランを作成できます。このタイプの製品では、ユーザーは、に応じて、毎日、毎週、毎月、または毎年自動的に課金されます。 計画構成 。このセクションでは、製品stripe_plan_nameのフィールドを使用します。プランIDを保存するために—実際にはIDを選択することが可能であり、それをpremium-planと呼びます—これは関係customer subscriptionを作成するために使用されます。

また、stripe_customer_idというユーザーテーブルの新しい列を作成します。 Stripeカスタマーオブジェクトのidプロパティで埋められます。関数Stripe::Customer.createの場合、Stripeカスタマーが作成されます。が呼び出され、アカウントに作成およびリンクされている顧客を( https://dashboard.stripe.com/test/customers )。顧客はsourceを渡すことによって作成されますこの場合、フォームが送信されたときに送信されるフロントエンドで生成されたトークンであるパラメーター。

最後に述べたStripeAPI呼び出しから取得した顧客オブジェクトは、customer.subscriptions.createを呼び出すことによって実行されるサブスクリプションの作成にも使用されます。プランIDをパラメータとして渡します。

さらに、stripe-rails gemは、Stripeから顧客を取得および更新するためのインターフェースを提供します。これは、Stripe::Customer.retrieveを呼び出すことによって実行されます。それぞれStripe::Customer.update。

したがって、ユーザーレコードにすでにstripe_customer_idがある場合、Stripe::Customer.createを使用して新しい顧客を作成する代わりに、Stripe::Customer.retrieveを呼び出します。 stripe_customer_idを渡すパラメータとして、その後にStripe::Customer.updateが続き、この場合、トークンにパラメータを渡します。

まず、Stripe APIを使用してプランを作成し、フィールドstripe_plan_nameを使用して新しいサブスクリプション製品を作成できるようにします。その後、orders_controllerで変更を行いますStripeサブスクリプションの作成と実行が処理されるようにするStripeサービス。

ステップ1: StripeAPIを使用してプランを作成します。

コマンドrails c を使用してコンソールを開きます。次のコマンドを使用して、Stripeアカウントのサブスクリプションを作成します。

Stripe::Plan.create({ amount: 10000, interval: 'month', product: { name: 'Premium plan', }, currency: 'usd', id: 'premium-plan', })

このステップで返された結果がtrueの場合、プランが正常に作成されたことを意味し、でアクセスできます。 ストライプダッシュボード 。

ステップ2: stripe_plan_nameを使用してデータベースに製品を作成しますフィールドセット。

次に、stripe_plan_nameを使用して製品を作成しますpremium-planとして設定データベース内:

Product.create(price_cents: 10000, name: 'Premium Plan', stripe_plan_name: 'premium-plan')

ステップ3: 列を追加するための移行を生成しますstripe_customer_id usersでテーブル。

ターミナルで以下を実行します。

rails generate migration AddStripeCustomerIdToUser stripe_customer_id:string rails db:migrate

ステップ4: Stripeサービスクラスにサブスクリプションロジックを実装します。

app/services/orders/stripe.rbのプライベートメソッドにさらに2つの関数を追加します:execute_subscription顧客のオブジェクトでサブスクリプションを作成する責任があります。関数find_or_create_customerすでに作成された顧客を返すか、新しく作成された顧客を返す責任があります。

def self.execute_subscription(plan:, token:, customer:) customer.subscriptions.create({ plan: plan }) end def self.find_or_create_customer(card_token:, customer_id:, email:) if customer_id stripe_customer = Stripe::Customer.retrieve({ id: customer_id }) if stripe_customer stripe_customer = Stripe::Customer.update(stripe_customer.id, { source: card_token}) end else stripe_customer = Stripe::Customer.create({ email: email, source: card_token }) end stripe_customer end

最後に、executeで同じファイル(app/services/orders/stripe.rb)内の関数の場合、最初にfind_or_create_customerを呼び出します。次に、execute_subscriptionを呼び出してサブスクリプションを実行します。以前に取得/作成した顧客を渡すことによって。したがって、コメントを置き換えます#SUBSCRIPTIONS WILL BE HANDLED HERE executeで次のコードのメソッド:

customer = self.find_or_create_customer(card_token: order.token, customer_id: user.stripe_customer_id, email: user.email) if customer user.update(stripe_customer_id: customer.id) order.customer_id = customer.id charge = self.execute_subscription(plan: product.stripe_plan_name, customer: customer)

ステップ5: アプリケーションをテストします。

Webサイトにアクセスし、サブスクリプション製品Premium Planを選択して、有効なテストカードに入力します。送信後、成功したページにリダイレクトされます。さらに、 ストライプダッシュボード サブスクリプションが正常に作成された場合。

PayPalの設定

Stripeで行ったように、PayPal APIを使用するためのgem:paypal-sdk-restも追加します。また、PayPalアカウントの作成も必要です。このgemを使用したPayPalの説明的なワークフローは、公式で参照できます。 PayPalAPIドキュメント 。

ステップ1: paypal-sdk-restを追加しますあなたのプロジェクトへの宝石。

これをGemfileに追加します。

gem 'paypal-sdk-rest'

実行:

bundle install

ステップ2: APIキーを生成します。

PayPalと通信するためのAPIキーを取得するには、PayPalアカウントを作成する必要があります。そう:

  • でアカウントを作成します(またはPayPalアカウントを使用します) https://developer.paypal.com/ 。
  • まだアカウントにログインしている場合は、次の場所で2つのサンドボックスアカウントを作成します。 https://developer.paypal.com/developer/accounts/ :
    • 個人(購入者アカウント)–これは支払いとサブスクリプションを行うためのテストで使用されます。
    • ビジネス(マーチャントアカウント)–これは、探しているAPIキーを持つアプリケーションにリンクされます。それ以外に、このアカウントではすべてのトランザクションを追跡できます。
  • でアプリを作成する https://developer.paypal.com/developer/applications 以前のビジネスサンドボックスアカウントを使用します。
  • このステップの後、PayPalの2つのキーを受け取ります:Client IDおよびSecret。
  • config/application.ymlで、YOUR_CREDENTIAL_HEREを置き換えますPAYPAL_CLIENT_IDからおよびPAYPAL_CLIENT_SECRET受け取ったばかりの鍵を使って。

ステップ3: PayPalモジュールを初期化します。

Stripeと同様に、application.ymlのキーを置き換える以外に、ENVですでに設定されているキーを使用できるようにPayPalモジュールを初期化する必要があります。変数。この目的のために、config/initializers/paypal.rbにファイルを作成しますと:

PayPal::SDK.configure( mode: ENV['PAYPAL_ENV'], client_id: ENV['PAYPAL_CLIENT_ID'], client_secret: ENV['PAYPAL_CLIENT_SECRET'], ) PayPal::SDK.logger.level = Logger::INFO

ステップ4: フロントエンドにPayPalを統合します。

index.html.hamlでこれをファイルの先頭に追加します。

%script(src='https://www.paypal.com/sdk/js?client-id=#{ENV['PAYPAL_CLIENT_ID']}')

Stripeとは異なり、PayPalはボタンのみを使用します。このボタンをクリックすると、ユーザーがログインして支払い/サブスクリプションに進むことができる安全なポップアップが開きます。このボタンは、メソッドpaypal.Button(PARAM1).render(PARAM2)を呼び出すことでレンダリングできます。

  • PARAM1は、環境構成と2つのコールバック関数をプロパティとして持つオブジェクトです:createOrderおよびonApprove。
  • PARAM2 PayPalボタンを付ける必要のあるHTML要素識別子を示します。

したがって、同じファイル内で、コメント付きのコードを置き換えますYOUR PAYPAL CODE WILL BE HEREと:

(function setupPaypal() { function isPayment() { return $('[data-charges-and-payments-section] input[name='orders[product_id]']:checked').length } function submitOrderPaypal(chargeID) { var $form = $('#order-details'); // Add a hidden input orders[charge_id] $form.append($('').val(chargeID)); // Set order type $('#order-type').val('paypal'); $form.submit(); } paypal.Buttons({ env: '#{ENV['PAYPAL_ENV']}', createOrder: function() { }, onApprove: function(data) { } }).render('#submit-paypal'); }());

ステップ5: アプリケーションをテストします。

ページにアクセスして、支払い方法としてPayPalを選択したときにPayPalボタンが表示されるかどうかを確認します。

PayPal取引

Stripeとは異なり、PayPalトランザクションのロジックは、フロントエンドからバックエンドに発信されるリクエストが増えるため、少し複雑になります。そのため、このセクションが存在します。 createOrderで説明されている関数がどのように(コードなしで)多かれ少なかれ説明します。およびonApproveメソッドが実装され、バックエンドプロセスでも期待されることです。

ステップ1: ユーザーがPayPal送信ボタンをクリックすると、ユーザーの資格情報を要求するPayPalポップアップが開きますが、読み込み状態です。関数コールバックcreateOrderと呼ばれます。

PayPalポップアップ、読み込み状態
PayPalポップアップ、読み込み状態

ステップ2: この関数では、支払い/サブスクリプションを作成するバックエンドへのリクエストを実行します。これはトランザクションの最初の段階であり、料金はまだ適用されないため、トランザクションは実際には 保留中 状態。バックエンドからトークンが返されます。トークンはPayPalモジュール(paypal-rest-sdk gemから提供)を使用して生成されます。

ステップ3: まだcreateOrderコールバックでは、バックエンドで生成されたこのトークンを返します。すべて問題がない場合、PayPalポップアップは次のように表示し、ユーザーの資格情報を要求します。

PayPalポップアップ、ユーザー資格情報
PayPalポップアップ、ユーザー資格情報

ステップ4: ユーザーがログインして支払い方法を選択すると、ポップアップの状態が次のように変わります。

PayPalポップアップ、承認されたトランザクション
PayPalポップアップ、承認されたトランザクション

ステップ5: onApprove関数コールバックが呼び出されるようになりました。これを次のように定義しました:onApprove: function(data)。 dataオブジェクトはそれを実行するために支払い情報を持っています。このコールバックでは、PayPal注文を実行するために、今回はデータオブジェクトを渡してバックエンド関数への別のリクエストが実行されます。

ステップ6: バックエンドはこのトランザクションを実行し、200を返します(成功した場合)。

ステップ7: バックエンドが戻ってきたら、フォームを送信します。これは、バックエンドに対して行う3番目の要求です。

Stripeとは異なり、このプロセスではバックエンドに対して3つのリクエストが行われることに注意してください。また、それに応じて注文レコードのステータスを同期させます。

  • createOrderコールバック:トランザクションが作成され、注文レコードも作成されます。したがって、それは 保留中 デフォルトとして状態。
  • onApproveコールバック:トランザクションが実行され、注文は次のように設定されます paypal_executed 。
  • 注文ページが送信されます:トランザクションはすでに実行されているため、何も変更されません。注文レコードはその状態を次のように変更します 有料 。

このプロセス全体を次のグラフで説明します。

PayPal取引
PayPal取引

PayPal支払い

PayPalの支払いは、Stripe Chargesと同じロジックに従うため、1回限りのトランザクションを表しますが、前のセクションで説明したように、フローロジックが異なります。 PayPal支払いを処理するために実行する必要がある変更は次のとおりです。

ステップ1: PayPalの新しいルートを作成し、支払いを実行します。

config/routes.rbに次のルートを追加します。

post 'orders/paypal/create_payment' => 'orders#paypal_create_payment', as: :paypal_create_payment post 'orders/paypal/execute_payment' => 'orders#paypal_execute_payment', as: :paypal_execute_payment

これにより、paypal_create_paymentで処理される支払いを作成および実行するための2つの新しいルートが作成されます。およびpaypal_execute_paymentコントローラメソッドを注文します。

ステップ2: PayPalサービスを作成します。

シングルトンクラスを追加するOrders::Paypalで:app/services/orders/paypal.rb。

このサービスには、最初に3つの責任があります。

  • create_paymentメソッドはPayPal::SDK::REST::Payment.newを呼び出すことによって支払いを作成します。 A トークン 生成され、フロントエンドに返されます。
  • execute_paymentメソッドは、最初にPayPal::SDK::REST::Payment.find(payment_id)を介して前に作成された支払いオブジェクトを見つけることによって支払いを実行します。を使用します Payment_id と同じ値を持つ引数として Charge_id 前のステップでorderオブジェクトに格納されます。その後、executeと呼びます。特定の支払人をパラメーターとして使用する支払オブジェクト内。この支払人は、ユーザーが資格情報を提供し、ポップアップで支払い方法を選択した後、フロントエンドによって提供されます。
  • finishメソッドは特定の順序で注文を検索します Charge_id で最近作成された注文のクエリ paypal_executed 状態。レコードが見つかった場合、それは支払い済みとしてマークされます。
class Orders::Paypal def self.finish(charge_id) order = Order.paypal_executed.recently_created.find_by(charge_id: charge_id) return nil if order.nil? order.set_paid order end def self.create_payment(order:, product:) payment_price = (product.price_cents/100.0).to_s currency = 'USD' payment = PayPal::SDK::REST::Payment.new({ intent: 'sale', payer: { payment_method: 'paypal' }, redirect_urls: { return_url: '/', cancel_url: '/' }, transactions: [{ item_list: { items: [{ name: product.name, sku: product.name, price: payment_price, currency: currency, quantity: 1 } ] }, amount: { total: payment_price, currency: currency }, description: 'Payment for: #{product.name}' }] }) if payment.create order.token = payment.token order.charge_id = payment.id return payment.token if order.save end end def self.execute_payment(payment_id:, payer_id:) order = Order.recently_created.find_by(charge_id: payment_id) return false unless order payment = PayPal::SDK::REST::Payment.find(payment_id) if payment.execute( payer_id: payer_id ) order.set_paypal_executed return order.save end end

ステップ3: 送信アクションでコントローラーのPayPalサービスを呼び出します。

prepare_new_orderのコールバックを追加しますアクションの前paypal_create_payment (次のステップで追加されます)は、ファイルapp/controllers/orders_controller.rbに以下を追加することによって要求されます。

class OrdersController

繰り返しますが、同じファイルで、コメントされたコードを置き換えることにより、送信アクションでPayPalサービスを呼び出します#PAYPAL WILL BE HANDLED HERE.次のように:

... elsif order_params[:payment_gateway] == 'paypal' @order = Orders::Paypal.finish(order_params[:token]) end ...

ステップ4: リクエストを処理するためのアクションを作成します。

それでも、app/controllers/orders_controller.rbではファイルに、paypal_create_paymentへのリクエストを処理するための2つの新しいアクション(パブリックにする必要があります)を作成しますおよびpaypal_execute_paymentルート:

  • paypal_create_paymentメソッド:サービスメソッドcreate_paymentを呼び出します。それが正常に戻ると、注文が返されます トークン Orders::Paypal.create_paymentによって作成されました。
  • paypal_execute_paymentメソッド:サービスメソッドを呼び出しますexecute_payment (これは私たちの支払いを実行します)。支払いが正常に実行されると、200が返されます。
... def paypal_create_payment result = Orders::Paypal.create_payment(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_payment if Orders::Paypal.execute_payment(payment_id: params[:paymentID], payer_id: params[:payerID]) render json: {}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...

ステップ5: createOrderのフロントエンドコールバック関数を実装しますおよびonApprove。

paypal.Button.renderを作成します呼び出しは次のようになります。

paypal.Buttons({ env: '#{ENV['PAYPAL_ENV']}', createOrder: function() { $('#order-type').val('paypal'); if (isPayment()) { return $.post('#{paypal_create_payment_url}', $('#order-details').serialize()).then(function(data) { return data.token; }); } else { } }, onApprove: function(data) { if (isPayment()) { return $.post('#{paypal_execute_payment_url}', { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { } } }).render('#submit-paypal');

前のセクションで述べたように、paypal_create_payment_urlと呼びます。 createOrderの場合コールバックとpaypal_execute_payment_url onApproveの場合折り返し電話。最後のリクエストが成功を返した場合、サーバーに対して行われた3番目のリクエストである注文を送信することに注意してください。

createOrderで関数ハンドラー、トークンを返します(バックエンドから取得)。 onApproveでコールバック、バックエンドに渡される2つのプロパティがありますpaymentIDおよびpayerID。これらは、支払いを実行するために使用されます。

最後に、2つの空のelseがあることに注意してください。 PayPalサブスクリプションを追加する次のセクションの余地を残しているため、条項。

フロントエンドのJavaScriptセクションを統合した後でページにアクセスし、支払い方法としてPayPalを選択すると、次のようになります。

PayPalと統合した後のインデックスページ
PayPalと統合した後のインデックスページ

ステップ6: アプリケーションをテストします。

  • インデックスページにアクセスしてください。
  • 支払い/課金製品と支払い方法としてPayPalを選択します。
  • [PayPalの送信]ボタンをクリックします。
  • PayPalポップアップの場合:
    • 作成したバイヤーアカウントの認証情報を使用します。
    • ログインして注文を確認します。
    • ポップアップが閉じます。
  • 成功ページにリダイレクトされているかどうかを確認します。
  • 最後に、でビジネスアカウントを使用してサインインし、PayPalアカウントで注文が実行されたかどうかを確認します。 https://www.sandbox.paypal.com/signin ダッシュボードをチェックします https://www.sandbox.paypal.com/listing/transactions 。

PayPalサブスクリプション

PayPalのプラン/契約/サブスクリプションは、Stripeサブスクリプションと同じロジックに従い、定期的な支払い用に作成されます。このタイプの製品では、ユーザーはその製品に応じて、毎日、毎週、毎月、または毎年自動的に課金されます 構成 。

PayPalから提供されたプランIDを保存するために、商品paypal_plan_nameのフィールドを使用します。この場合、Stripeとは異なり、IDは選択せず、PayPalはこの値を返します。この値は、データベースで作成された最後の製品を更新するために使用されます。

サブスクリプションを作成する場合、customerはありませんメソッドonApproveのように、どのステップでも情報が必要です。おそらく、その基礎となる実装でこのリンケージを処理します。したがって、テーブルは同じままです。

ステップ1: PayPalAPIを使用してプランを作成します。

コマンドrails c を使用してコンソールを開きます。次の方法でPayPalアカウントのサブスクリプションを作成します。

plan = PayPal::SDK::REST::Plan.new({ name: 'Premium Plan', description: 'Premium Plan', type: 'fixed', payment_definitions: [{ name: 'Premium Plan', type: 'REGULAR', frequency_interval: '1', frequency: 'MONTH', cycles: '12', amount: { currency: 'USD', value: '100.00' } }], merchant_preferences: { cancel_url: 'http://localhost:3000/', return_url: 'http://localhost:3000/', max_fail_attempts: '0', auto_bill_amount: 'YES', initial_fail_amount_action: 'CONTINUE' } }) plan.create plan_update = { op: 'replace', path: '/', value: { state: 'ACTIVE' } } plan.update(plan_update)

ステップ2: データベース内の最後の製品を更新しますpaypal_plan_name返されたplan.idで。

実行:

Product.last.update(paypal_plan_name: plan.id)

ステップ3: PayPalサブスクリプションのルートを追加します。

config/routes.rbに2つの新しいルートを追加します。

post 'orders/paypal/create_subscription' => 'orders#paypal_create_subscription', as: :paypal_create_subscription post 'orders/paypal/execute_subscription' => 'orders#paypal_execute_subscription', as: :paypal_execute_subscription

ステップ4: PayPalサービスでの作成と実行を処理します。

Orders::Paypalでサブスクリプションを作成および実行するための関数をさらに2つ追加します。のapp/services/orders/paypal.rb:

def self.create_subscription(order:, product:) agreement = PayPal::SDK::REST::Agreement.new({ name: product.name, description: 'Subscription for: #{product.name}', start_date: (Time.now.utc + 1.minute).iso8601, payer: { payment_method: 'paypal' }, plan: { id: product.paypal_plan_name } }) if agreement.create order.token = agreement.token return agreement.token if order.save end end def self.execute_subscription(token:) order = Order.recently_created.find_by(token: token) return false unless order agreement = PayPal::SDK::REST::Agreement.new agreement.token = token if agreement.execute order.charge_id = agreement.id order.set_paypal_executed return order.charge_id if order.save end end

create_subscriptionでは、メソッドPayPal::SDK::REST::Agreement.newを呼び出して契約を初期化します。そしてproduct.paypal_plan_nameを渡しますその属性の1つとして。その後、それを作成し、この最後のオブジェクトにトークンが設定されます。また、トークンをフロントエンドに返します。

execute_subscriptionには、orderがあります。前の呼び出しで作成されたレコード。その後、新しい契約を初期化し、この前のオブジェクトのトークンを設定して実行します。この最後のステップが正常に実行されると、注文ステータスは次のように設定されます。 paypal_executed 。そして今、フロントエンドに戻ります。これもorder.chager_idに保存されています。

ステップ5: orders_controllerでサブスクリプションを作成および実行するためのアクションを追加します。

app/controllers/orders_controller.rbを変更します。クラスの最上位で、最初に、次にコールバックを更新しますprepare_new_order paypal_create_subscriptionの前にも実行されますと呼ばれます:

class OrdersController

また、同じファイルに2つのパブリック関数を追加して、Orders::Paypalを呼び出すようにします。 PayPalの支払いですでに行っているのと同様のフローのサービス:

... def paypal_create_subscription result = Orders::Paypal.create_subscription(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_subscription result = Orders::Paypal.execute_subscription(token: params[:subscriptionToken]) if result render json: { id: result}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...

ステップ6: createOrderのサブスクリプションハンドラーの追加およびonApproveフロントエンドでのコールバック。

最後に、index.html.hamlで、paypal.Buttonsを置き換えます次の関数を使用すると、2つの空のelseが埋められます。以前に持っていた:

paypal.Buttons({ env: '#{ENV['PAYPAL_ENV']}', createOrder: function() { $('#order-type').val('paypal'); if (isPayment()) { return $.post('#{paypal_create_payment_url}', $('#order-details').serialize()).then(function(data) { return data.token; }); } else { return $.post('#{paypal_create_subscription_url}', $('#order-details').serialize()).then(function(data) { return data.token; }); } }, onApprove: function(data) { if (isPayment()) { return $.post('#{paypal_execute_payment_url}', { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { return $.post('#{paypal_execute_subscription_url}', { subscriptionToken: data.orderID }).then(function(executeData) { submitOrderPaypal(executeData.id) }); } } }).render('#submit-paypal');

サブスクリプションの作成と実行には、支払いに使用されるのと同様のロジックがあります。 1つの違いは、支払いを実行するとき、コールバック関数からのデータonApproveです。すでにpaymentIDがありますcharge_idを表すsubmitOrderPaypal(data.paymentID)からフォームを送信します。サブスクリプションの場合、charge_idを取得しますPOSTを要求して実行した後でのみpaypal_execute_subscription_urlで、submitOrderPaypal(executeData.id)を呼び出すことができます。

ステップ7: アプリケーションをテストします。

  • インデックスページにアクセスしてください。
  • サブスクリプション製品とPayPalを支払い方法として選択します。
  • [PayPalの送信]ボタンをクリックします。
  • PayPalポップアップの場合:
    • 作成したバイヤーアカウントの認証情報を使用します。
    • ログインして注文を確認します。
    • ポップアップが閉じます。
  • 成功ページにリダイレクトされているかどうかを確認します。
  • 最後に、でビジネスアカウントでサインインして、PayPalアカウントで注文が実行されたかどうかを確認します。 https://www.sandbox.paypal.com/signin ダッシュボードをチェックします https://www.sandbox.paypal.com/listing/transactions 。

結論

この記事を読むと、PayPalとStripeの支払い/請求とサブスクリプショントランザクションをRailsアプリケーションに統合できるようになります。簡潔にするためにこの記事では追加しなかった、改善できる点がたくさんあります。私は難易度の仮定に基づいてすべてを整理しました:

  • より簡単に:
    • リクエストがHTTPSを使用するように、トランスポート層セキュリティ(TLS)を使用します。
    • PayPalとStripeの両方の本番環境構成を実装します。
    • ユーザーが以前の注文の履歴にアクセスできるように、新しいページを追加します。
  • 中:
    • サブスクリプションの払い戻しまたはキャンセル。
    • 未登録のユーザー支払いのソリューションを提供します。
  • もっと強く:
    • アカウントを削除して保持する方法を提供する トークン そして 顧客ID ユーザーが戻ってきたい場合。ただし、一定の日数が経過したら、このデータを削除して、アプリケーションがPCIに準拠するようにします。
    • サーバー側でPayPalバージョン2APIに移行します( https://developer.paypal.com/docs/api/payments/v2/ )このチュートリアルで使用したgem paypal-sdk-rest 、バージョン2のベータ版しかないため、慎重に使用できます( https://github.com/paypal/PayPal-Ruby-SDK/tree/2.0-beta )。
    • べき等の要求を含めます。
      • 縞: https://stripe.com/docs/api/idempotent_requests
      • PayPal: https://developer.paypal.com/docs/api-basics/#api-idempotency

また、Stripeをフロントエンドに統合するもう1つの方法であるStripeCheckout要素について読むことをお勧めします。このチュートリアルで使用したStripeElementsとは異なり、Stripe Checkoutは、ユーザーがクレジットカード情報を入力するか、Google Pay / Apple Payで支払うことを選択するボタン(PayPalと同様)をクリックするとポップアップを開きます。 https://stripe.com/docs/web 。

2番目の推奨事項は、両方のペイメントゲートウェイのセキュリティページです。

  • ために 縞
  • ために PayPal

最後に、この記事を読んでくれてありがとう!私もチェックできます このプロジェクトサンプルに使用されたGitHubプロジェクト 。そこに、私は追加しました rspec 開発中にもテストします。

基本を理解する

Stripeとは何ですか?どのように機能しますか?

Stripeは、インターネットを介して安全な支払いを実行するための個人または企業向けのソフトウェアを開発する会社です。

初心者のためのCSSチートシート

PayPalとStripeの違いは何ですか?

彼らは支払いを含むさまざまなアプリケーションを提供し、彼らのサービスを使用するためのさまざまな料金を持っています。

お支払い方法トークンとは何ですか?

支払いのトークン化は、ユーザーからの機密データを処理してトークンに変換するプロセスであるため、機密データの漏洩はありません。

PayPalは支払いゲートウェイまたはプロセッサーですか?

PayPalはゲートウェイではありませんが、完全なマーチャントソリューションです。ただし、Payflowと呼ばれる支払いゲートウェイを使用します。

Stripeは支払いゲートウェイまたはプロセッサーですか?

Stripeは、顧客のカードを処理する支払いゲートウェイです。

コミュニケーションライン–書体の歴史(インフォグラフィック付き)

Uiデザイン

コミュニケーションライン–書体の歴史(インフォグラフィック付き)
効率的なエンジニアの時間管理の秘密

効率的なエンジニアの時間管理の秘密

ライフスタイル

人気の投稿
電子メール感情分析ボットを作成する方法:NLPチュートリアル。
電子メール感情分析ボットを作成する方法:NLPチュートリアル。
Redux、RxJS、およびReduxを使用したリアクティブアプリの構築-ReactNativeで観察可能
Redux、RxJS、およびReduxを使用したリアクティブアプリの構築-ReactNativeで観察可能
プレゼンテーションデザインとビジュアルストーリーテリングの芸術
プレゼンテーションデザインとビジュアルストーリーテリングの芸術
ヘルムには誰がいますか? –デザインリーダーシップの質の分析
ヘルムには誰がいますか? –デザインリーダーシップの質の分析
遺伝的アルゴリズム:自然淘汰による検索と最適化
遺伝的アルゴリズム:自然淘汰による検索と最適化
 
リモート再発明:フリーランスの仕事を見つける方法
リモート再発明:フリーランスの仕事を見つける方法
バーチャルリアリティ:仕事の未来を触媒する
バーチャルリアリティ:仕事の未来を触媒する
予測ソーシャルネットワーク分析のためのデータマイニング
予測ソーシャルネットワーク分析のためのデータマイニング
Ruby onRailsでのStripeとPayPalの支払い方法の統合
Ruby onRailsでのStripeとPayPalの支払い方法の統合
製品管理会議の包括的なリスト
製品管理会議の包括的なリスト
人気の投稿
  • C ++にヘッダーファイルをインクルードする方法
  • フォントはいくつありますか
  • キャッシュフロー計算書の作成
  • C ++をどうするか
  • Web開発技術仕様書サンプル
  • ギリシャの債務危機の原因
カテゴリー
ライフスタイル 計画と予測 トレンド ヒントとツール ツールとチュートリアル 仕事の未来 リモートの台頭 エンジニアリング管理 プロジェクト管理 プロセスとツール

© 2021 | 全著作権所有

apeescape2.com