Mağazadan Online Teslim Alma: Bonjour Yemeği - 3. Bölüm - Ödeme İşleyen ile Entegrasyon

1. Giriş

53003251caaf2be5.png 8826bd8cb0c0f1c7.png

Son Güncelleme: 13.09.2021

Ödeme alma!

Business Messages'ta ödeme toplamak, görüşme platformundaki yepyeni iş fırsatları dünyasına adım atmanızı sağlar. Potansiyel bir müşterinin size daha fazla bilgi edinmek istediği bir ürünle ilgili soru gönderdiğini düşünün. Soruları yanıtlandıktan sonra doğrudan iletişim içinde bir ödeme ağ geçidi sağlayarak onlarla anlaşmayı kapatabilirsiniz.

fe0c6754fb69d708.png

İyi bir ödeme deneyimi nasıl olur?

İyi bir ödeme deneyimi, kullanıcıların alıştıkları şekilde ödeme yapabileceği bir deneyimdir.

Kullanıcıların nasıl ödeme yapacakları konusunda tercihleri vardır. Dünyanın farklı yerlerinde diğer ödeme yöntemlerinden daha yaygındırlar. Business Messages ile, kullanıcılara en yüksek düzeyde kolaylık sunmak için birden fazla ödeme işleyiciyi entegre edebilirsiniz.

Kullanıcılar ödeme akışını tamamladıktan sonra ödemelerini başarıyla aldığınızı kullanıcılara bildirebilirsiniz. Ödeme işleyicilerin çoğu, ödeme akışının tamamlanmasından sonra istediğiniz bir URL'ye HTTP isteği gönderen bir başarılı veya başarısız geri çağırma içerir.

Geliştireceğiniz

Codelab serisinin önceki bölümünde Bonjour Yemek Aracı'nı kullanarak öğe kataloğu sundunuz, kullanıcıların öğe ekleyip kaldırmasına olanak tanıyan bir alışveriş sepeti oluşturdunuz ve alışveriş sepetinin toplam fiyatını hesapladınız. Bu bölümde, temsilciyi ödemeleri alışveriş sepetinin içeriğine göre işleyebilmesi için daha fazla genişletirsiniz.

Bu codelab'de uygulamanız

  • Stripe ödeme ağ geçidi ile entegrasyon
  • Alışveriş sepetinin fiyatına göre kullanıcının ödeme akışını tamamlamasına izin verme
  • Kullanıcıları ödeme durumuyla ilgili bilgilendirmek için görüşme yüzeyine bildirim gönderin

ba08a4d2f8c09c0e.png

Yapacağınız işlemler

  • Stripe ödeme işleyiciyle entegrasyon yapın.
  • Stripe'a ödeme oturumu başlatmak için istek gönderin.
  • Stripe'tan gelen ödeme ve başarısızlık yanıtlarını yönet.

Gerekenler

  • Business Messages ile kullanılmak üzere kaydedilmiş ve onaylanmış bir GCP projesi
  • Talimatlar için geliştirici sitemize göz atın.
  • Android 5 veya sonraki bir sürüme sahip Android cihaz VEYA Google Haritalar uygulamasına sahip bir iOS cihaz
  • Web uygulaması programlama deneyimi
  • İnternet bağlantısı!

2. Bağımlılık ekleme

requirements.txt dosyasını güncelleme

Stripe ödeme işleyiciyle entegrasyon gerçekleştireceğimiz için Stripe Python istemci kitaplığı'nı kullanabiliriz. Bağımlılığın en son sürümünü almak için requirements.txt dosyasına sürüm olmadan stripe ekleyin.

Bu, Google Cloud App Engine Python çalışma zamanının çizgili Python modülünü içermesi için gereklidir.

requirements.txt

...
stripe
...

Bopis/views.py hazırlanıyor

Bopis/views.py ifadesinin üst kısmında, render (django.shortcuts) ile JsonResponse arası django.http içe aktarın. Ayrıca, Stripe Python istemci kitaplığına yapılan çağrıları desteklemek için stripe dosyasını içe aktarmamız gerekecek.

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

3. Strip ile çalışma

Stripe.com'da hesap oluşturma

Bu codelab'de Stripe'ı kullanıyorduk ancak web entegrasyonunu destekleyen tüm işlemcilerle entegrasyon yapabilirsiniz. stripe.com adresinde bir hesap oluşturun. Bu profili, herhangi bir üçüncü taraf ödeme işleyicisiyle doğrudan nasıl entegre olabileceğinizi öğrenmek için test ve eğitim amacıyla kullanırız.

6731d123c56feb67.png

Hesap oluşturup giriş yaptıktan sonra aşağıdaki gibi bir kontrol paneli görürsünüz.

6d9d165d2d1fbb8c.png

"Test modu"nda çalıştığınızdan emin olun ve API anahtarlarınızı aramak için yukarıdaki ekran görüntüsünde belirtildiği gibi Geliştiriciler düğmesini tıklayın. İki tür API anahtarı görürsünüz: Yayınlanabilir anahtar ve Gizli anahtar. Stripe ile ödeme işlemlerini kolaylaştırmak için bu anahtarlardan her ikisine de ihtiyacınız vardır.

Bopis/views.py dosyasını güncelleyin

Uygulamanız için her iki anahtar grubu da gereklidir. Bu nedenle, bunları views.py sayfasında güncelleyebilirsiniz.

Gizli anahtarı doğrudantripe.api_key mülkünde ayarlayabilir ve Stripe geliştirici kontrol panelinde bulunan Gizli Anahtarın değerini atayabilirsiniz. Ardından, STRIPE_PUBLIC_KEY adında genel bir değişken oluşturun ve bunu yayınlanabilir anahtar olarak ayarlayın.

Ayrıca, Stripe'ın yönettiğiniz bir web sayfasına yeniden yönlendirmesi gerekir. Bu yüzden, uygulamanızın herkese açık alanını eklemek için ek bir global değişken oluşturalım.

Bu değişikliklerin sonunda şunlara sahip olacaksınız:

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

Stripe kurulum için yapmanız gereken tek şey bu.

4. Ödeme işlevi

Alışveriş sepeti toplam fiyat işlevini güncelleme

Şu anda send_shopping_cart_total_price işlevi, yalnızca alışveriş sepetinin fiyatını belirten bir mesaj gönderir. Ödeme sayfasına giden URL'yi açmak için önerilen bir işlem ekleyelim.

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)

Bu önerilen işleme dokunan kullanıcılar, toplam fiyatlarını ve Stripe ile ödeme başlatma düğmesini gösteren bir web sayfasına yönlendirilir.

Bu akışı destekleyecek basit bir web sayfası oluşturalım.

Proje kaynak kodunda bopis adlı dizini bulun. Bopis'lerde templates adlı yeni bir dizin oluşturun ve şablonlar içinde bopis adında başka bir dizin oluşturun. Bu, şablonlar dizinindeki uygulama adını belirtmek için bir Django tasarım kalıbıdır. Django uygulamaları arasındaki şablonların karışıklığını azaltmaya yardımcı olur.

Artık bopis/templates/bopis/ konumunda yolu olan bir dizininiz olmalıdır. Bu dizinde web sayfaları sunmak için HTML dosyaları oluşturabilirsiniz. Django, bunlara tarayıcıda oluşturulan şablonlar anlamına gelir. checkout.html ile başlayalım.

Bu dizinde, checkout.html. Aşağıdaki kod snippet'inde bir ödeme düğmesi ve alışveriş sepetinin fiyatı görüntülenir. Ayrıca, Stripe ödemesini başlatmak için JavaScript de içerir.

{% 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>

URL istendiğinde bu web sayfasına yönlendirme yapmamız gerekiyor. Ödeme işlemi için önerilen Action, openUrlAction değeri {YOUR_DOMAIN}/checkout/{conversation_id} olarak ayarlandı. Bu, https://<GCP-Project-ID>.appspot.com/checkout/abc123-cba321-abc123-cba321 gibi bir anlama gelir. Bu rotayı oluşturmadan önce, HTML Şablonunda bulunan JavaScript'i inceleyelim.

...
  <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>
...

Yukarıdaki kod snippet'ini birlikte inceleyelim.

  1. Öncelikle, görünüm işlevinden bağlam aracılığıyla iletilen ortak anahtara sahip bir Stripe varlığı oluşturur. Başka bir Django paradigması.
  2. Ardından, snippet, sayfada checkout-button kimliğine sahip bir öğeyi arar.
  3. Bir öğeye bir etkinlik işleyici eklenir.

Bu etkinlik dinleyici, bir kullanıcı şu düğmeyi tıkladığında veya düğmeye dokunduğunda tetiklenir: URL'de belirttiğiniz web sunucusuna bir POST isteği başlatılır: {YOUR_DOMAIN}/create-checkout-session/{conversation_id}.

Web sunucusu mantığını aşağıdaki snippet'lerde görebilirsiniz. Kullanıcı, kimliği "checkout-button" olan düğmeye dokunduğunda, alışveriş sepetinin fiyatını belirten Stripe API'si kullanılarak oluşturulan Stripe Oturum Kimliği'nin döndürülmesini bekleyebiliriz.

Sunucunuz geçerli bir Oturum Kimliği oluşturabildiyse, uygulama mantığı kullanıcıyı Stripe Checkout sayfasına yönlendirir, aksi takdirde kullanıcıyı bir hata oluştuğuna dair standart bir JavaScript mesajı ile uyarır.

Ödeme sayfasını desteklemek ve Oturum Kimliği'ni oluşturmak için urlpatterns dizisine yeni yollar ekleyerek başlayalım. Aşağıdakileri urls.py adresindeki urlpatterns dizisine ekleyin.

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

Ardından, checkout.html şablonunu döndürmek ve Stripe ödeme oturumunu oluşturmak için view.py görünümünde görünüm işlevleri oluşturalım.

... 

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)

...

Bu işlevlerin her ikisi de alışveriş sepetini kullanıcıyla ilişkilendirmek ve ardından Stripe'ın kullanıcıdan ödeme alması gereken fiyatı belirlemek için chat_id değerini kullanır.

Bu iki yöntem ödeme akışının ilk yarısını oluşturur. Bunu dağıtır ve deneyimi test ederseniz, Stripe geliştirici belgelerinde belirtildiği şekilde, Visa ödemesinin test edilmesi için bir test kredi kartıyla ödeme yapabileceğiniz bir Stripe ödeme formu görürsünüz.

Stripe'tan kullanıcının ödemesiyle ilgili yanıt aldığımızda, akışın ikinci yarısında, kullanıcıları tekrar görüşmeye alırız.

5. Çizgili yanıtlar

Bir kullanıcı ödeme akışınızla etkileşimde bulunduğunda ya başarılı olmuştur ya da ödemeyi tamamlayamamıştır. create_checkout_session işlevinde success_url ve cancel_url tanımladık. Stripe, ödemenin durumuna bağlı olarak bu iki URL'den birine yönlendirme yapar. Şimdi, bu iki rotayı urls.py içinde tanımlayalım ve ardından bu iki olası akışı desteklemek için bopis/views.py adresine iki görünüm işlevi ekleyelim.

Bu satırları urls.py dosyasına ekleyin.

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

İlgili görünümler ise şu şekilde görünür:

... 

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')

...

Strip, alana DOMAIN sabitinde belirttiğiniz şekilde yeniden yönlendirme yapar. Bu durumda, bir şablon aracılığıyla HTML yanıtı oluşturmanız gerekir, aksi halde web sitesi çok sade görünür. bopis/templates/bopis/ dizininde checkout.html ile birlikte iki basit HTML dosyası oluşturalım.

bm-django-echo-bot/bopis/ şablonlar/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/ templates/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>

Bu iki şablonla, Stripe entegrasyonunuzla ödeme akışını tamamlayan bir kullanıcı, uygun URL'lere yönlendirilir ve ilgili şablonlar sunulur. Ayrıca, Business Messages üzerinden de görüşmeye geri dönmelerini sağlayan bir mesaj alırlar.

6. Ödeme alma!

Tebrikler, Business Messages temsilcinize bir ödeme işleyiciyi başarıyla entegre ettiniz.

Bu seride Google Cloud App Engine'e bir web uygulaması dağıttınız, Business Communications Developer Console'da webhook'unuzu ayarladınız, uygulamayı statik veritabanı aracılığıyla envanter aramasını destekleyecek şekilde genişlettiniz ve Google Datastore'u kullanarak bir alışveriş sepeti oluşturdunuz. Dizinin son bölümünde, web entegrasyonlarını ve bu deneyimi destekleyen bir ödeme işleyicisi olan Stripe ile entegrasyon yaptınız. Artık diğer ödeme işleyicilerle entegrasyonlar ve daha fazlası gerçekleştirebilirsiniz.

d6d80cf9c9fc621.png 44db8d6441dce4c5.png

Sırada ne var?

Hazır olduğunuzda, Business Messages'ta ulaşabileceğiniz daha karmaşık etkileşimler hakkında bilgi edinmek için aşağıdaki konulardan bazılarına göz atın:

Referans dokümanlar