Mua qua mạng

1. Giới thiệu

53003251caaf2be5.png. 8826bd8cb0c0f1c7.png.

Ngày cập nhật gần đây nhất: Ngày 13/09/2021

Bạn đang thu thập khoản thanh toán!

Việc thu thập tiền thanh toán trên Business Messages mang đến cho bạn một thế giới hoàn toàn mới về những cơ hội kinh doanh trong nền tảng trò chuyện. Hãy tưởng tượng một khách hàng tiềm năng gửi cho bạn câu hỏi về một sản phẩm mà họ muốn tìm hiểu thêm. Sau khi đã trả lời câu hỏi thì bạn có thể đóng giao dịch với họ bằng cách cung cấp cổng thanh toán ngay trong cuộc trò chuyện.

fe0c6754fb69d708.png.

Điều gì tạo ra trải nghiệm thanh toán tốt?

Trải nghiệm thanh toán tốt là nơi người dùng có thể thanh toán theo cách họ đã quen.

Người dùng có các tùy chọn về phương thức thanh toán của họ và các phương thức thanh toán khác nhau phổ biến hơn các phương thức thanh toán khác ở những nơi khác trên thế giới. Thông qua Business Messages, bạn có thể tích hợp với nhiều trình xử lý thanh toán để có được mức độ thuận tiện cao nhất cho người dùng.

Sau khi người dùng hoàn tất quy trình thanh toán, bạn phải cho họ biết rằng bạn đã nhận được khoản thanh toán của họ. Hầu hết các công ty xử lý thanh toán bao gồm lệnh gọi lại thành công hoặc không thành công, trong đó gửi yêu cầu HTTP đến một URL mà bạn chọn sau khi hoàn thành quy trình thanh toán.

Sản phẩm bạn sẽ tạo ra

Trong phần trước của chuỗi lớp học lập trình, bạn đã mở rộng tác nhân Bonjour Thức ăn để hiển thị một danh mục các mặt hàng, tạo một giỏ hàng cho phép người dùng thêm và xóa các mặt hàng, rồi tính tổng giá của giỏ hàng. Trong phần này, bạn sẽ mở rộng thêm nhân viên hỗ trợ để có thể xử lý thanh toán dựa trên nội dung của giỏ hàng.

Trong lớp học lập trình này, ứng dụng của bạn sẽ

  • Tích hợp với cổng thanh toán Stripe
  • Cho phép người dùng hoàn tất quy trình thanh toán dựa trên giá của giỏ hàng
  • Gửi thông báo trở lại nền tảng trò chuyện để thông báo cho người dùng về trạng thái thanh toán

ba08a4d2f8c09c0e.png.

Bạn sẽ thực hiện

  • Tích hợp với công ty xử lý thanh toán Stripe.
  • Gửi yêu cầu tới Stripe để bắt đầu phiên thanh toán.
  • Xử lý thành công khoản thanh toán hoặc lỗi phản hồi từ Stripe.

Bạn cần có

  • Một dự án GCP đã đăng ký và phê duyệt để sử dụng cho Business Messages
  • Hãy xem trang web dành cho nhà phát triển của chúng tôi để biết hướng dẫn về cách thực hiện
  • Thiết bị Android chạy phiên bản 5 trở lên HOẶC thiết bị iOS có ứng dụng Google Maps
  • Có kinh nghiệm lập trình ứng dụng web
  • Kết nối Internet!

2. Thêm phần phụ thuộc

Đang cập nhật request.txt

Khi tích hợp với bộ xử lý thanh toán Stripe, chúng ta có thể dùng thư viện ứng dụng máy khách Stripe Python. Thêm stripe vào request.txt mà không cần phiên bản để có được phiên bản mới nhất của phần phụ thuộc.

Điều này là cần thiết để thời gian chạy Google Cloud App Engine Python bao gồm mô-đun Python dạng sọc.

yêu cầu.txt

...
stripe
...

Chuẩn bị cho bopis/views.py

Ở đầu trang bopis/views.py, hãy nhập render từ django.shortcutsJsonResponse từ django.http. Ngoài ra, chúng ta sẽ cần nhập stripe để hỗ trợ các lệnh gọi đến thư viện ứng dụng Stripe Python.

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

3. Làm việc với Stripe

Tạo tài khoản tại Stripe.com

Trong lớp học lập trình này, chúng tôi vừa mới sử dụng Stripe, nhưng bạn có thể tích hợp với bất kỳ bộ xử lý nào hỗ trợ việc tích hợp web. Tạo một tài khoản trên stripe.com. Chúng tôi sẽ sử dụng hồ sơ này cho mục đích thử nghiệm và giáo dục. Bạn có thể tìm hiểu cách tích hợp trực tiếp với bất kỳ công ty xử lý thanh toán bên thứ ba nào.

6731d123c56feb67.png.

Sau khi tạo một tài khoản và đăng nhập, bạn sẽ thấy một trang tổng quan có dạng như sau.

6d9d165d2d1fbb8c.png.

Đảm bảo bạn đang hoạt động ở "Chế độ thử nghiệm" và nhấp vào nút Nhà phát triển như được nêu trong ảnh chụp màn hình ở trên để tìm khoá API của bạn. Bạn sẽ thấy hai bộ khóa API: Khóa có thể xuất bảnKhóa bí mật. Bạn sẽ cần cả hai khoá này để hỗ trợ các giao dịch thanh toán với Stripe.

Cập nhật bopis/views.py

Ứng dụng của bạn cần cả hai bộ khoá, vì vậy, hãy cập nhật chúng trong view.py.

Bạn có thể trực tiếp đặt khóa bí mật trên thuộc tính Stripe.api_key và chỉ định khóa đó cho giá trị của Khóa bí mật tìm thấy trong trang tổng quan Stripe dành cho nhà phát triển. Sau đó, hãy tạo một biến toàn cục có tên là STRIPE_PUBLIC_KEY và đặt biến đó thành khoá có thể xuất bản.

Ngoài ra, Stripe cần chuyển hướng trở lại trang web mà bạn quản lý. Vì vậy, hãy tạo thêm một biến toàn cục để bao gồm miền có thể truy cập công khai của ứng dụng.

Sau khi sửa đổi, bạn sẽ có dạng như sau:

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

Và đó là tất cả những gì bạn cần làm để thiết lập Stripe.

4. Chức năng thanh toán

Cập nhật hàm tổng giá trong giỏ hàng

Hiện tại, hàm send_shopping_cart_total_price chỉ gửi thông báo chỉ định giá của giỏ hàng. Hãy thêm hành động được đề xuất để mở URL vào trang thanh toán.

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)

Khi người dùng nhấn vào Đề xuất hành động này, họ sẽ được chuyển đến một trang web hiển thị tổng giá và nút để bắt đầu thanh toán với Stripe.

Hãy tạo một trang web đơn giản sẽ hỗ trợ quy trình này.

Trong mã nguồn dự án, hãy tìm thư mục có tên bopis. Tạo một thư mục mới trong bopis, có tên là templates và trong các mẫu, hãy tạo một thư mục khác có tên bopis. Đây là mẫu thiết kế Django để chỉ định tên ứng dụng trong thư mục mẫu. Giúp giảm sự nhầm lẫn về các mẫu giữa các ứng dụng Django.

Bây giờ, bạn sẽ có một thư mục có đường dẫn tại bopis/templates/bopis/. Bạn có thể tạo tệp HTML trong thư mục này để phân phát các trang web. Django gọi các mẫu này là mẫu được kết xuất tới trình duyệt. Hãy bắt đầu với checkout.html.

Trong thư mục này, hãy tạo checkout.html. Đoạn mã sau đây cho thấy nút thanh toán và giá của giỏ hàng. Lựa chọn này cũng bao gồm JavaScript để bắt đầu quy trình thanh toán trên 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>

Chúng tôi cần một đường dẫn đến trang web này khi URL được yêu cầu. Quy trình thanh toán được đề xuất có giá trị openUrlAction được đặt thành {YOUR_DOMAIN}/checkout/{conversation_id}. Sau đó, hàm này sẽ chuyển thành https://<GCP-Project-ID>.appspot.com/checkout/abc123-cba321-abc123-cba321. Trước khi chúng ta tạo tuyến đường này, hãy xem xét JavaScript được tìm thấy trong Mẫu 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>
...

Hãy cùng xem qua đoạn mã trên.

  1. Trước tiên, phương thức này tạo một thực thể Stripe có khoá công khai được truyền qua ngữ cảnh từ hàm view, một mô hình Django khác.
  2. Sau đó, đoạn mã sẽ tìm một phần tử trên trang có mã checkout-button.
  3. Trình nghe sự kiện được thêm vào phần tử đó.

Trình nghe sự kiện này sẽ được kích hoạt khi người dùng nhấp hoặc nhấn vào nút này để bắt đầu yêu cầu POST tới máy chủ web mà bạn chỉ định thông qua URL: {YOUR_DOMAIN}/create-checkout-session/{conversation_id}.

Bạn có thể xem logic của máy chủ web trong các đoạn mã dưới đây. Khi người dùng nhấn vào nút có id "checkout-button" chúng ta có thể mong đợi nó sẽ trả về mã phiên Stripe được tạo bằng API Stripe để chỉ định giá của giỏ hàng.

Nếu máy chủ của bạn có thể tạo ra Mã phiên hợp lệ thì logic ứng dụng sẽ chuyển hướng người dùng đến trang Thanh toán sọc, nếu không, máy chủ sẽ thông báo cho người dùng bằng thông báo JavaScript tiêu chuẩn rằng đã xảy ra sự cố.

Hãy bắt đầu bằng cách thêm các đường dẫn mới vào mảng urlpatterns để hỗ trợ trang thanh toán và tạo Mã phiên. Thêm nội dung sau vào mảng urlpatterns trong url.py.

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

Sau đó, hãy tạo các hàm xem trong view.py để trả về mẫu Checkout.html và tạo phiên thanh toán 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)

...

Cả hai hàm này đều sử dụng chat_id để liên kết giỏ hàng với người dùng và sau đó để xác định giá Stripe sẽ tính cho người dùng.

Hai phương thức này tạo thành nửa đầu tiên của quy trình thanh toán. Nếu triển khai việc này và thử nghiệm trải nghiệm, bạn sẽ thấy biểu mẫu thanh toán trên Stripe nơi bạn có thể hoàn thành giao dịch thanh toán bằng thẻ tín dụng thử nghiệm theo hướng dẫn trong tài liệu dành cho nhà phát triển Stripe để kiểm tra thẻ Visa.

Nửa thứ hai của quy trình là cách chúng tôi đưa người dùng quay lại cuộc trò chuyện sau khi nhận được phản hồi của Stripe về khoản thanh toán của người dùng.

5. Phản hồi sọc

Khi một người dùng tham gia vào quy trình thanh toán của bạn, họ đã thành công hoặc không hoàn tất việc thanh toán. Trong hàm create_checkout_session, chúng ta xác định success_urlcancel_url. Sọc sẽ chuyển hướng đến một trong hai URL này tùy thuộc vào trạng thái thanh toán. Hãy xác định hai tuyến này trong Url.py rồi thêm hai hàm xem vào bopis/views.py để hỗ trợ hai luồng này.

Thêm các dòng này vào tệp url.py.

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

Và các chế độ xem tương ứng sẽ có dạng như sau:

... 

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

...

Sọc chuyển hướng trở lại miền như bạn đã chỉ định trong hằng số DOMAIN, tức là bạn cần hiển thị phản hồi HTML thông qua một mẫu, nếu không trang web sẽ trông rất mờ. Hãy tạo hai tệp HTML đơn giản trong thư mục bopis/samples/bopis/ cùng Checkout.html.

bm-django-echo-bot/bopis/ mẫu/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/ samples/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>

Khi sử dụng 2 mẫu này, người dùng hoàn tất quy trình thanh toán sẽ tích hợp với Stripe của bạn và sẽ được chuyển hướng đến các URL phù hợp cũng như được cung cấp các mẫu tương ứng. Họ cũng sẽ nhận được một tin nhắn thông qua Business Messages, cho phép họ quay lại cuộc trò chuyện.

6. Nhận tiền thanh toán!

Xin chúc mừng! Bạn đã tích hợp thành công công ty xử lý thanh toán vào nhân viên hỗ trợ của ứng dụng Business Messages!

Trong chuỗi nội dung này, bạn đã triển khai một ứng dụng web cho Google Cloud App Engine, thiết lập webhook trên Business Console Developer Console, mở rộng ứng dụng này để hỗ trợ tính năng tra cứu kho hàng thông qua một cơ sở dữ liệu tĩnh và tạo giỏ hàng bằng Google Datastore. Trong phần cuối của chuỗi chủ đề, bạn đã tích hợp với Stripe, một công ty xử lý thanh toán hỗ trợ tích hợp web và có trải nghiệm này. Giờ đây, bạn có thể tích hợp với các công ty xử lý thanh toán khác và hơn thế nữa!

d6d80cf9c9fc621.pngS 44db8d6441dce4c5.pngS

Tiếp theo là gì?

Khi bạn đã sẵn sàng, hãy kiểm tra một số chủ đề sau để tìm hiểu về những hoạt động tương tác phức tạp hơn mà bạn có thể đạt được trong Business Messages:

Tài liệu tham khảo