Beli Online Ambil di Toko: Bonjour Meal - Bagian 3 - Integrasi dengan Pemroses Pembayaran

1. Pengantar

53003251caaf2be5.png 8826bd8cb0c0f1c7.png

Terakhir Diperbarui: 13-09-2021

Mengumpulkan pembayaran!

Mengumpulkan pembayaran di Business Messages dapat membuka peluang bisnis baru dalam platform percakapan. Bayangkan calon pelanggan mengirimkan pertanyaan tentang produk yang ingin mereka pelajari lebih lanjut. Setelah pertanyaan mereka dijawab, Anda dapat menyelesaikan transaksi dengan mereka dengan menyediakan gateway pembayaran langsung dalam percakapan.

fe0c6754fb69d708.png

Apa yang membuat pengalaman pembayaran baik?

Pengalaman pembayaran yang baik adalah pengalaman yang memungkinkan pengguna membayar seperti biasanya.

Pengguna memiliki preferensi terkait metode pembayaran dan metode pembayaran yang berbeda-beda lebih umum dibandingkan metode pembayaran lain di berbagai belahan dunia. Dengan Business Messages, Anda dapat berintegrasi dengan lebih dari satu pemroses pembayaran untuk memberikan kemudahan tertinggi bagi pengguna.

Setelah pengguna menyelesaikan alur pembayaran, Anda ingin memberi tahu bahwa Anda telah berhasil menerima pembayaran. Sebagian besar pemroses pembayaran menyertakan callback keberhasilan atau kegagalan yang mengirimkan permintaan HTTP ke URL pilihan Anda setelah alur pembayaran selesai.

Yang akan Anda build

Di bagian sebelumnya pada seri codelab, Anda memperluas agen Bonjour Meal untuk menampilkan katalog item, membuat keranjang belanja yang memungkinkan pengguna menambahkan dan menghapus item, serta menghitung harga total keranjang belanja. Di bagian ini, Anda akan memperpanjang agen agar dapat memproses pembayaran berdasarkan konten keranjang belanja.

Dalam codelab ini, aplikasi Anda akan

  • Mengintegrasikan dengan gateway pembayaran Stripe
  • Izinkan pengguna menyelesaikan alur pembayaran berdasarkan harga keranjang
  • Mengirimkan notifikasi kembali ke platform percakapan untuk memberi tahu pengguna status pembayaran

ba08a4d2f8c09c0e.png

Yang akan Anda lakukan

  • Melakukan integrasi dengan pemroses pembayaran Stripe.
  • Kirim permintaan ke Stripe untuk memulai sesi pembayaran.
  • Tangani keberhasilan atau kegagalan pembayaran dari Stripe.

Yang Anda butuhkan

  • Project GCP yang terdaftar dan disetujui untuk digunakan dengan Business Messages
  • Lihat situs developer kami untuk mendapatkan petunjuk terkait cara
  • Perangkat Android dengan versi 5 atau yang lebih baru ATAU perangkat iOS dengan aplikasi Google Maps
  • Pengalaman dengan pemrograman aplikasi web
  • Koneksi internet.

2. Menambahkan dependensi

Memperbarui persyaratan.txt

Karena akan berintegrasi dengan pemroses pembayaran Stripe, kita dapat menggunakan library klien Stripe Python. Tambahkan stripe ke persyaratan.txt tanpa versi untuk mendapatkan versi terbaru dependensi.

Hal ini diperlukan agar runtime Google Cloud App Engine Python dapat menyertakan modul Python stripe.

requirements.txt

...
stripe
...

Menyiapkan bopis/views.py

Di bagian atas bopis/views.py, impor render dari django.shortcuts dan JsonResponse dari django.http. Selain itu, kita perlu mengimpor stripe untuk mendukung panggilan ke library klien Stripe Python.

...
from django.shortcuts import render
from django.http import JsonResponse
import stripe
...

3. Bekerja dengan Stripe

Buat akun di Stripe.com

Dalam codelab ini, kami kebetulan menggunakan Stripe, tetapi Anda dapat berintegrasi dengan prosesor apa pun yang mendukung integrasi web. Buat akun di stripe.com. Kami akan menggunakan profil ini untuk tujuan pengujian dan edukasi guna mempelajari cara mengintegrasikan langsung dengan pemroses pembayaran pihak ketiga mana pun.

6731d123c56feb67.png

Setelah membuat akun dan login, Anda akan melihat dasbor yang terlihat seperti ini.

6d9d165d2d1fbb8c.png

Pastikan Anda beroperasi dalam "Mode pengujian", lalu klik tombol Developer seperti yang diuraikan dalam screenshot di atas untuk mencari kunci API Anda. Anda akan melihat dua kumpulan kunci API: Kunci yang dapat dipublikasikan dan Kunci rahasia. Anda memerlukan kedua kunci ini untuk memfasilitasi transaksi pembayaran dengan Stripe.

Memperbarui bopis/views.py

Aplikasi Anda memerlukan kedua set kunci, jadi perbarui di views.py.

Anda dapat menetapkan kunci rahasia secara langsung di properti stripe.api_key dan memberinya nilai Kunci Rahasia yang ditemukan di dasbor developer Stripe. Lalu buat variabel global yang disebut STRIPE_PUBLIC_KEY dan tetapkan ke kunci yang dapat dipublikasikan.

Selain itu, Stripe perlu dialihkan kembali ke halaman web yang Anda kelola, jadi mari buat variabel global tambahan untuk menyertakan domain aplikasi Anda yang dapat dijangkau secara publik.

Di akhir perubahan ini, Anda akan mendapatkan tampilan seperti ini:

stripe.api_key = 'sk_test_abcde-12345'
STRIPE_PUBLIC_KEY = 'pk_test_edcba-54321'
YOUR_DOMAIN = 'https://<GCP_PROJECT_ID>.appspot.com'

Hanya itu yang perlu Anda lakukan untuk penyiapan Stripe.

4. Fungsi checkout

Memperbarui fungsi harga total keranjang belanja

Saat ini, fungsi send_shopping_cart_total_price hanya mengirimkan pesan yang menentukan harga keranjang belanja. Mari tambahkan tindakan yang disarankan untuk membuka URL ke halaman checkout.

def send_shopping_cart_total_price(conversation_id):
  """Sends shopping cart price to the user through Business Messages.

  Args:
    conversation_id (str): The unique id for this user and agent.
  """
  cart_price = get_cart_price(conversation_id)

  message_obj = BusinessMessagesMessage(
      messageId=str(uuid.uuid4().int),
      representative=BOT_REPRESENTATIVE,
      text=f'Your cart\'s total price is ${cart_price}.',
      suggestions=[
          BusinessMessagesSuggestion(
              action=BusinessMessagesSuggestedAction(
                  text='Checkout',
                  postbackData='checkout',
                  openUrlAction=BusinessMessagesOpenUrlAction(
                      url=f'{YOUR_DOMAIN}/checkout/{conversation_id}'))),
      ]
    )

  send_message(message_obj, conversation_id)

Saat mengetuk TapAction yang disarankan ini, pengguna akan diarahkan ke halaman web yang menampilkan harga total dan tombol untuk memulai pembayaran dengan Stripe.

Mari membuat halaman web sederhana yang akan mendukung alur ini.

Dalam kode sumber project, temukan direktori bernama bopis. Buat direktori baru dalam bopis yang bernama templates, dan di dalam template, buat direktori lain bernama bopis. Ini adalah pola desain Django untuk menentukan nama aplikasi dalam direktori template. Hal ini membantu mengurangi kebingungan template di antara aplikasi Django.

Anda kini akan memiliki direktori dengan jalur di bopis/templates/bopis/. Anda dapat membuat file HTML di direktori ini untuk menayangkan halaman web. Django menyebutnya sebagai template yang dirender ke browser. Mari mulai dengan checkout.html.

Dalam direktori ini, buat checkout.html. Cuplikan kode berikut menampilkan tombol checkout dan harga keranjang. Ini juga mencakup JavaScript untuk memulai checkout Stripe.

{% load static %}

<!DOCTYPE html>
<html>
  <head>
    <title>Purchase from Bonjour Meal</title>

    <script src="https://js.stripe.com/v3/"></script>
    <style>
      .description{
        font-size: 4em;
      }
      button {
        color: red;
        padding: 40px;
        font-size: 4em;
      }
    </style>
  </head>
  <body>
    <section>
      <img
        src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"
        alt="Bonjour Meal Restaurant"
      />
      <div class="product">
        <div class="description">
          <h3>Your Bonjour Meal Total</h3>
          <h5>${{cart_price}}</h5>
        </div>
      </div>
      <button type="button" id="checkout-button">Checkout</button>
    </section>
  </body>
  <script type="text/javascript">
    // Create an instance of the Stripe object with your publishable API key
    var stripe = Stripe("{{stripe_public_key}}");
    var checkoutButton = document.getElementById("checkout-button");

    checkoutButton.addEventListener("click", function () {
      fetch("/create-checkout-session/{{conversation_id}}", {
        method: "POST",
      })
        .then(function (response) {
          return response.json();
        })
        .then(function (session) {
          return stripe.redirectToCheckout({ sessionId: session.id });
        })
        .then(function (result) {
          // If redirectToCheckout fails due to a browser or network
          // error, you should display the localized error message to your
          // customer using error.message.
          if (result.error) {
            alert(result.error.message);
          }
        })
        .catch(function (error) {
          console.error("Error:", error);
        });
    });
  </script>
</html>

Kami memerlukan rute ke halaman web ini saat URL diminta. Checkout ActionAction memiliki nilai openUrlAction yang ditetapkan ke {YOUR_DOMAIN}/checkout/{conversation_id}. Ini diterjemahkan menjadi sesuatu seperti https://<GCP-Project-ID>.appspot.com/checkout/abc123-cba321-abc123-cba321. Sebelum rute ini dibuat, mari kita tinjau JavaScript yang ditemukan dalam Template HTML.

...
  <script type="text/javascript">
    // Create an instance of the Stripe object with your publishable API key
    var stripe = Stripe("{{stripe_public_key}}");
    var checkoutButton = document.getElementById("checkout-button");

    checkoutButton.addEventListener("click", function () {
      fetch("/create-checkout-session/{{conversation_id}}", {
        method: "POST",
      })
        .then(function (response) {
          return response.json();
        })
        .then(function (session) {
          return stripe.redirectToCheckout({ sessionId: session.id });
        })
        .then(function (result) {
          // If redirectToCheckout fails due to a browser or network
          // error, you should display the localized error message to your
          // customer using error.message.
          if (result.error) {
            alert(result.error.message);
          }
        })
        .catch(function (error) {
          console.error("Error:", error);
        });
    });
  </script>
...

Mari kita lihat cuplikan kode di atas bersama-sama.

  1. Pertama, entity Stripe dibuat dengan kunci publik yang diteruskan melalui konteks dari fungsi tampilan, paradigma Django lainnya.
  2. Selanjutnya, cuplikan akan mencari elemen di halaman dengan ID checkout-button.
  3. Pemroses peristiwa ditambahkan ke elemen tersebut.

Pemroses peristiwa ini akan dipicu saat pengguna mengklik atau mengetuk tombol ini yang memulai permintaan POST ke server web yang Anda tentukan melalui URL: {YOUR_DOMAIN}/create-checkout-session/{conversation_id}.

Anda dapat melihat logika server web dalam cuplikan di bawah. Saat pengguna mengetuk tombol dengan id "checkout-button" kita dapat mengharapkannya menampilkan ID Sesi Stripe yang dibuat menggunakan Stripe API yang menentukan harga keranjang.

Jika server Anda dapat menghasilkan ID Sesi yang valid, logika aplikasi akan mengalihkan pengguna ke halaman Checkout Stripe. Jika tidak, pengguna akan diberi tahu dengan pesan JavaScript standar bahwa ada sesuatu yang tidak beres.

Mari kita mulai dengan menambahkan jalur baru ke array urlpatterns untuk mendukung halaman checkout dan untuk membuat ID Sesi. Tambahkan kode berikut ke array urlpatterns di urls.py.

... 
path('checkout/<str:conversation_id>', bopis_views.payment_checkout),
path('create-checkout-session/<str:conversation_id>', bopis_views.create_checkout_session),
...

Kemudian, mari kita buat fungsi tampilan di views.py untuk menampilkan template checkout.html dan untuk membuat sesi checkout Stripe.

... 

def payment_checkout(request, conversation_id):
  """Sends the user to a payment confirmation page before the payment portal.

  Args:
    request (HttpRequest): Incoming Django request object
    conversation_id (str): The unique id for this user and agent.

  Returns:
    Obj (HttpResponse): Returns an HTTPResponse to the browser
  """

  cart_price = get_cart_price(conversation_id)
  context = {'conversation_id': conversation_id,
             'stripe_public_key': STRIPE_PUBLIC_KEY,
             'cart_price': cart_price
            }
  return render(request, 'bopis/checkout.html', context)


@csrf_exempt
def create_checkout_session(request, conversation_id):
  """Creates a Stripe session to start a payment from the conversation.

  Args:
    request (HttpRequest): Incoming Django request object
    conversation_id (str): The unique id for this user and agent.

  Returns:
    Obj (HttpResponse): Returns an HTTPResponse to the browser
  """
  cart_price = get_cart_price(conversation_id)
  try:
    checkout_session = stripe.checkout.Session.create(
        payment_method_types=['card'],
        line_items=[
            {
                'price_data': {
                    'currency': 'usd',
                    'unit_amount': int(cart_price*100),
                    'product_data': {
                        'name': 'Bonjour Meal Checkout',
                        'images': ['https://storage.googleapis.com/bonjour-rail.appspot.com/apple-walnut-salad.png'],
                    },
                },
                'quantity': 1,
            },
        ],
        mode='payment',
        success_url=YOUR_DOMAIN + '/success/' + conversation_id,
        cancel_url=YOUR_DOMAIN + '/cancel/' + conversation_id,
    )

    return JsonResponse({
        'id': checkout_session.id
    })

  except Exception as e:
    # Handle exceptions according to your payment processor's documentation
    # https://stripe.com/docs/api/errors/handling?lang=python
    return HttpResponse(e)

...

Kedua fungsi ini menggunakan percakapan_id untuk mengaitkan keranjang belanja dengan pengguna, lalu menentukan harga yang harus dibebankan Stripe kepada pengguna.

Kedua metode ini membentuk paruh pertama alur pembayaran. Jika men-deploy ini dan menguji pengalamannya, Anda akan melihat formulir checkout Stripe tempat Anda dapat menyelesaikan pembayaran dengan kartu kredit percobaan seperti yang disarankan dalam dokumentasi developer Stripe untuk menguji checkout Visa.

Paruh kedua alur adalah cara kita membawa pengguna kembali ke percakapan setelah kita menerima respons dari Stripe mengenai pembayaran pengguna.

5. Respons Stripe

Saat pengguna terlibat dalam alur pembayaran, mereka mungkin akan berhasil atau gagal menyelesaikan pembayaran. Dalam fungsi create_checkout_session, kita menentukan success_url dan cancel_url. Stripe akan mengalihkan ke salah satu dari dua URL ini tergantung status pembayaran. Mari tentukan kedua rute ini di urls.py, lalu tambahkan dua fungsi tampilan ke bopis/views.py untuk mendukung kedua kemungkinan alur ini.

Tambahkan baris ini ke file urls.py.

... 
    path('success/<str:conversation_id>', bopis_views.payment_success),
    path('cancel/<str:conversation_id>', bopis_views.payment_cancel),
...

Dan tampilan yang sesuai akan terlihat seperti ini:

... 

def payment_success(request, conversation_id):
  """Sends a notification to the user prompting them back into the conversation.

  Args:
    request (HttpRequest): Incoming Django request object
    conversation_id (str): The unique id for this user and agent.

  Returns:
    Obj (HttpResponse): Returns an HTTPResponse to the browser
  """
  message_obj = BusinessMessagesMessage(
      messageId=str(uuid.uuid4().int),
      representative=BOT_REPRESENTATIVE,
      suggestions=[
          BusinessMessagesSuggestion(
              reply=BusinessMessagesSuggestedReply(
                  text='Check on order', postbackData='check-order')),
      ],
      text='Awesome it looks like we\'ve received your payment.')

  send_message(message_obj, conversation_id)

  return render(request, 'bopis/success.html')


def payment_cancel(request, conversation_id):
  """Sends a notification to the user prompting them back into the conversation.

  Args:
    request (HttpRequest): Incoming Django request object
    conversation_id (str): The unique id for this user and agent.

  Returns:
    Obj (HttpResponse): Returns an HTTPResponse to the browser
  """
  message_obj = BusinessMessagesMessage(
      messageId=str(uuid.uuid4().int),
      representative=BOT_REPRESENTATIVE,
      suggestions=[
          BusinessMessagesSuggestion(
              action=BusinessMessagesSuggestedAction(
                  text='Checkout',
                  postbackData='checkout',
                  openUrlAction=BusinessMessagesOpenUrlAction(
                      url=f'{YOUR_DOMAIN}/checkout/{conversation_id}'))),
      ],
      text='It looks like there was a problem with checkout. Try again?')

  send_message(message_obj, conversation_id)

  return render(request, 'bopis/cancel.html')

...

Stripe mengalihkan kembali ke domain seperti yang Anda tetapkan dalam konstanta DOMAIN, yang berarti Anda harus merender respons HTML melalui sebuah template atau situs akan terlihat sangat sederhana. Mari kita buat dua file HTML sederhana dalam direktori bopis/templates/bopis/ beserta checkout.html.

bm-django-echo-bot/bopis/ template/bopis/success.html

{% load static %}

<html>
<head>
  <title>Business Messages Payment Integration Sample!</title>
  <style>
    p{
      font-size: 4em;
    }
  </style>
</head>
<body>
  <section>

    <p>
      Checkout succeeded - We appreciate your business!
      <br/><br/>
      For support related questions, please email
      <a href="mailto:bm-support@google.com">bm-support@google.com</a>.

    </p>
  </section>
</body>
</html>

bm-django-echo-bot/bopis/ template/bopis/cancel.html

{% load static %}

<html>
<head>
  <title>Checkout canceled</title>
  <style>
    p{
      font-size: 4em;
    }
    </style>
</head>
<body>
  <section>
    <p>Checkout canceled - Forgot to add something to your cart? Shop around then come back to pay!</p>
  </section>
</body>
</html>

Dengan kedua template ini, pengguna yang menyelesaikan alur pembayaran dengan integrasi Stripe, diarahkan ke URL yang sesuai dan diberi template masing-masing. Mereka juga akan menerima pesan melalui Business Messages yang memungkinkan mereka kembali ke percakapan.

6. Terima pembayaran!

Selamat, Anda telah berhasil mengintegrasikan pemroses pembayaran ke agen Business Messages Anda.

Dalam seri ini, Anda telah men-deploy aplikasi web ke Google Cloud App Engine, menyetel webhook Anda di Business Communications Developer Console, memperluas aplikasi untuk mendukung pencarian inventaris melalui database statis, dan membuat keranjang belanja menggunakan Google Datastore. Di bagian akhir seri ini, Anda berintegrasi dengan Stripe, pemroses pembayaran yang mendukung integrasi web dan dengan pengalaman ini. Sekarang Anda dapat melakukan integrasi dengan pemroses pembayaran lain dan banyak lagi.

d6d80cf9c9fc621.png 44db8d6441dce4c5.png

Apa selanjutnya?

Jika Anda sudah siap, lihat beberapa topik berikut untuk mempelajari interaksi lebih kompleks yang dapat Anda capai di Business Messages:

Dokumen referensi