स्टोर से ऑनलाइन पिक अप करना: Bonjour Meal - भाग 3 - पेमेंट्स प्रोसेसर के साथ इंटिग्रेशन

1. सुविधा के बारे में जानकारी

53003251caaf2be5.png 8826bd8cb0c0f1c7.png

13-09-2021 को अपडेट किया गया

पेमेंट इकट्ठा किया जा रहा है!

Business Messages का इस्तेमाल करके पेमेंट करने पर, बातचीत के लिए इस्तेमाल होने वाले प्लैटफ़ॉर्म पर, कारोबार के अवसर दिखने लगते हैं. मान लें कि एक संभावित ग्राहक आपको ऐसे प्रॉडक्ट के बारे में पूछताछ करता है, जिसके बारे में वह और जानना चाहता है. जब उनके सवालों के जवाब मिल जाएं, तब आप बातचीत के अंदर ही पेमेंट गेटवे की मदद से, डील खत्म कर सकते हैं.

fe0c6754fb69d708.png

पेमेंट का अच्छा अनुभव क्या है?

बेहतर पेमेंट अनुभव वह होता है जहां उपयोगकर्ता पहले की तरह पेमेंट कर सकें.

पैसे चुकाने के तरीकों के मामले में उपयोगकर्ताओं की अलग-अलग प्राथमिकताएं होती हैं. साथ ही, पैसे चुकाने के अलग-अलग तरीके, दुनिया के अलग-अलग हिस्सों में मौजूद हैं. Business Messages सुविधा का इस्तेमाल करके, उपयोगकर्ताओं को बेहतरीन सुविधा देने के लिए, एक से ज़्यादा पेमेंट प्रोसेसर के साथ इंटिग्रेट किया जा सकता है.

जब कोई उपयोगकर्ता पेमेंट फ़्लो पूरा कर लेता है, तब आप उसे यह बताना चाहते हैं कि आपको पेमेंट मिल गया है. ज़्यादातर पेमेंट प्रोसेस करने वाली कंपनियों में, सफलता या असफल कॉलबैक शामिल होता है. यह कॉलबैक आपको पेमेंट फ़्लो पूरा होने पर, आपकी पसंद के यूआरएल पर एक एचटीटीपी अनुरोध भेजता है.

आप क्या बनाएं

कोडलैब (कोड बनाना सीखना) सीरीज़ के पिछले सेक्शन में, आपने आइटम बुक करने के लिए Bonjor Meal एजेंट को बढ़ाया था, एक शॉपिंग कार्ट बनाया था, जिससे उपयोगकर्ता आइटम जोड़ और हटा सकते हैं और शॉपिंग कार्ट की कुल कीमत का हिसाब लगा सकते हैं. इस सेक्शन में, आप एजेंट को और आगे ले जाएंगे, ताकि वह शॉपिंग कार्ट के कॉन्टेंट के आधार पर पेमेंट प्रोसेस कर सके.

इस कोडलैब में आपका ऐप्लिकेशन

  • स्ट्रिप पेमेंट गेटवे के साथ इंटिग्रेट करना
  • कार्ट की कीमत के हिसाब से, उपयोगकर्ता को पेमेंट फ़्लो पूरा करने की अनुमति दें
  • पेमेंट की स्थिति के बारे में उपयोगकर्ता को जानकारी देने के लिए, बातचीत की प्लैटफ़ॉर्म पर वापस जाने का विकल्प भेजें

ba08a4d2f8c09c0e.png

आप क्या करेंगे

  • Stripe पेमेंट प्रोसेस करने वाली कंपनी के साथ इंटिग्रेट करें.
  • पेमेंट सेशन शुरू करने के लिए, Stripe से अनुरोध भेजें.
  • Stripe से पेमेंट फ़ेल हो गया या काम नहीं कर पाया.

आपको इन चीज़ों की ज़रूरत होगी

  • Business Messages के साथ रजिस्टर किया गया और स्वीकार किया गया GCP प्रोजेक्ट
  • इस बारे में निर्देश पाने के लिए हमारी डेवलपर साइट देखें
  • Android 5 या उसके बाद के वर्शन वाला Android डिवाइस या Google Maps ऐप्लिकेशन वाला iOS डिवाइस
  • वेब ऐप्लिकेशन प्रोग्रामिंग का अनुभव
  • इंटरनेट कनेक्शन!

2. डिपेंडेंसी जोड़ना

ज़रूरी शर्तें.txt अपडेट करना

हम धारी वाले पेमेंट प्रोसेसर के साथ मिलकर काम करेंगे. इस काम के लिए, हम S Stripe Python क्लाइंट लाइब्रेरी का इस्तेमाल कर सकते हैं. डिपेंडेंसी का नया वर्शन पाने के लिए, किसी वर्शन के बिना stripe को ज़रूरतों के आधार पर जोड़ें.

धारी Python मॉड्यूल को शामिल करने के लिए Google Cloud App Engine Python रनटाइम के लिए यह ज़रूरी है.

ज़रूरी शर्तें.txt

...
stripe
...

bopis/view.py तैयार करना

बोपिस/व्यू.py के सबसे ऊपर, django.shortcuts से render और django.http से JsonResponse इंपोर्ट करें. इसके अलावा, Stripe Python क्लाइंट लाइब्रेरी का इस्तेमाल करने के लिए, हमें stripe को इंपोर्ट करना होगा.

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

3. धारी के साथ काम करना

Stripe.com पर खाता बनाएं

इस कोडलैब में हम अभी Stripe का इस्तेमाल कर रहे हैं, लेकिन आप वेब इंटिग्रेशन की सुविधा देने वाले किसी भी प्रोसेसर के साथ जुड़ सकते हैं. sTRIPe.com पर खाता बनाएं. हम इस प्रोफ़ाइल का इस्तेमाल यह जानने के लिए करेंगे कि तीसरे पक्ष की पेमेंट प्रोसेस करने वाली कंपनी के साथ सीधे तौर पर कैसे जुड़ा जा सकता है. साथ ही, हम इस प्रोफ़ाइल का इस्तेमाल, शिक्षा और शिक्षा से जुड़े कामों के लिए करेंगे.

6731d123c56feb67.png

जब आप खाता बना लेते हैं और लॉग इन करते हैं, तो आपको एक ऐसा डैशबोर्ड दिखाई देता है जो ऐसा दिखता है.

6d9d165d2d1fbb8c.png

पक्का करें कि आप ऑपरेट और &जांच मोड में काम कर रहे हैं. साथ ही, अपनी एपीआई कुंजियां देखने के लिए ऊपर दिए गए स्क्रीनशॉट में बताए गए डेवलपर बटन पर क्लिक करें. आपको एपीआई कुंजियों के दो सेट दिखेंगे: पब्लिश करने लायक कुंजी और सीक्रेट कुंजी. Stripe से पेमेंट का लेन-देन करने के लिए, आपको इन दोनों कुंजियों की ज़रूरत होगी.

bopis/view.py अपडेट करें

आपके ऐप्लिकेशन को दोनों कुंजियों की ज़रूरत है, इसलिए उन्हें view.py में अपडेट करें.

Stripe.api_key प्रॉपर्टी पर सीधे कुंजी को सेट किया जा सकता है. साथ ही, इस स्ट्रिंग को 'स्ट्राइप डेवलपर डैशबोर्ड' में जाकर, सीक्रेट कुंजी की वैल्यू असाइन की जा सकती है. इसके बाद, STRIPE_PUBLIC_KEY नाम का एक ग्लोबल वैरिएबल बनाएं और उसे पब्लिश करने लायक कुंजी पर सेट करें.

इसके अलावा, स्ट्रिप को उस वेब पेज पर वापस रीडायरेक्ट करना होता है जिसे आप मैनेज करते हैं, ताकि आपके ऐप्लिकेशन के सार्वजनिक रूप से ऐक्सेस किए जा सकने वाले डोमेन में शामिल करने के लिए हम एक और ग्लोबल वैरिएबल बना लें.

इन बदलावों के आखिर में, आपके पास कुछ ऐसा होगा:

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

और आपको स्ट्राइप सेट अप के लिए बस इतना ही करना है.

4. चेकआउट की सुविधा

शॉपिंग कार्ट की कुल कीमत का फ़ंक्शन अपडेट करना

फ़िलहाल, send_shopping_cart_total_price फ़ंक्शन सिर्फ़ शॉपिंग कार्ट की कीमत बताने वाला मैसेज भेजता है. चेकआउट पेज पर यूआरएल खोलने के लिए चलिए सुझाई गई कार्रवाई जोड़ें.

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)

जब उपयोगकर्ता इस सुझाई गई कार्रवाई पर टैप करते हैं, तो उन्हें उस वेबपेज पर ले जाया जाता है जहां उनकी कुल कीमत दिखती है. साथ ही, वे स्ट्राइप से पेमेंट शुरू करने का बटन भी देखते हैं.

चलिए एक साधारण वेबपेज बनाते हैं जो इस फ़्लो का समर्थन करेगा.

प्रोजेक्ट सोर्स कोड में, bopis नाम वाली डायरेक्ट्री ढूंढें. बोप में templates नई डायरेक्ट्री बनाएं और टेंप्लेट में bopis नाम की दूसरी डायरेक्ट्री बनाएं. यह टेंप्लेट डायरेक्ट्री में ऐप्लिकेशन का नाम बताने के लिए, Django का डिज़ाइन पैटर्न है. इससे Django ऐप्लिकेशन के बीच टेंप्लेट को भ्रम की स्थिति से बचाने में मदद मिलती है.

अब आपके पास bopis/templates/bopis/ वाली पाथ वाली डायरेक्ट्री होनी चाहिए. वेब पेजों को दिखाने के लिए, इस डायरेक्ट्री में एचटीएमएल फ़ाइलें बनाई जा सकती हैं. Django इसका मतलब उन टेंप्लेट से है जो ब्राउज़र को रेंडर किए जाते हैं. चलिए, checkout.html से शुरू करते हैं.

इस निर्देशिका में, checkout.html बनाएं. यह कोड स्निपेट, चेकआउट बटन और कार्ट की कीमत दिखाता है. इसमें धारी वाले चेकआउट शुरू करने के लिए JavaScript भी शामिल है.

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

यूआरएल का अनुरोध करने पर, हमें इस वेबपेज का रूट चाहिए. सुझाई गई चेकआउट कार्रवाई में, OpenUrlAction की वैल्यू {YOUR_DOMAIN}/checkout/{conversation_id} पर सेट की गई है. इसका अनुवाद कुछ इस तरह होता है https://<GCP-Project-ID>.appspot.com/checkout/abc123-cba321-abc123-cba321. इससे पहले कि हम यह रास्ता बनाएं, हमें एचटीएमएल टेम्प्लेट में दिए गए JavaScript की समीक्षा करने दें.

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

आइए, ऊपर दिए गए कोड स्निपेट को एक साथ देखें.

  1. पहले, यह सार्वजनिक कुंजी वाली एक धारीदार इकाई बनाता है, जिसे व्यू फ़ंक्शन से संदर्भ के ज़रिए पास किया जाता है. यह Django का दूसरा उदाहरण है.
  2. इसके बाद, स्निपेट, checkout-button आईडी वाले पेज पर मौजूद एलिमेंट को खोजता है.
  3. उस एलिमेंट में इवेंट लिसनर जोड़ा जाता है.

यह इवेंट लिसनर तब ट्रिगर होगा, जब कोई उपयोगकर्ता इस बटन पर क्लिक या टैप करेगा. यह ऐसे यूआरएल के लिए, 'पोस्ट करें' अनुरोध शुरू करेगा जिसे आपने यूआरएल के ज़रिए तय किया है: {YOUR_DOMAIN}/create-checkout-session/{conversation_id}.

नीचे दिए गए स्निपेट में, वेब सर्वर के लॉजिक को देखा जा सकता है. जब उपयोगकर्ता आईडी और कोट के साथ बटन पर टैप करता है;checkout-button" हम उम्मीद कर सकते हैं कि यह धारी वाले सत्र आईडी पर वापस आएगा, जो कार्ट की कीमत बताने वाले धारी वाले API का इस्तेमाल करके बनाया गया होगा.

अगर आपके सर्वर से एक मान्य सेशन आईडी जनरेट हो जाता है, तो ऐप्लिकेशन लॉजिक, उपयोगकर्ता को धारी चेकआउट पेज पर रीडायरेक्ट करेगा. हालांकि, यह उपयोगकर्ता को स्टैंडर्ड JavaScript मैसेज के साथ सूचना देगा कि कोई गड़बड़ी हुई है.

चेकआउट पेज का समर्थन करने और सेशन आईडी जनरेट करने के लिए, यूआरएल पैटर्न में नए पाथ जोड़ना शुरू करें. यूआरएल के यूआरएल के पैटर्न में, ये चीज़ें जोड़ें.

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

फिर चेकआउट.html टेम्प्लेट पर वापस जाने और धारी वाले चेकआउट सत्र को जनरेट करने के लिए, व्यू की फ़ंक्शन बनाएं.

... 

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)

...

ये दोनों फ़ंक्शन, Shopping कार्ट को उपयोगकर्ता से जोड़ने के लिए बातचीत के आईडी का इस्तेमाल करते हैं. इसके बाद, यह तय करने के लिए कि Stripe से उपयोगकर्ता से शुल्क लिया जाए.

इन दो तरीकों से पेमेंट फ़्लो के पहले आधे हिस्से को बनाया जाता है. अगर आप इस सुविधा का इस्तेमाल करते हैं और इस अनुभव की जांच करते हैं, तो आपको धारी वाला चेकआउट फ़ॉर्म दिखेगा. इस फ़ॉर्म के ज़रिए आप Visa चेकआउट की जांच करने के लिए Stripe डेवलपर दस्तावेज़ में टेस्ट क्रेडिट कार्ड से पैसे चुका सकते हैं.

दूसरे चरण में हम ट्रिपल से उपयोगकर्ता के जवाब को लेकर, उपयोगकर्ता का फिर से बातचीत करते हैं.

5. धारी वाले जवाब

जब कोई उपयोगकर्ता आपके पेमेंट फ़्लो में दिलचस्पी दिखाता है, तो वह या तो पेमेंट कर देता है या पेमेंट नहीं कर पाता. create_checkout_session फ़ंक्शन में, हमने success_url और cancel_url को तय किया है. धारी, भुगतान की स्थिति के आधार पर इनमें से किसी एक URL पर रीडायरेक्ट हो जाएगी. यूआरएल के लिए दो पाथ तय करने के लिए, यूआरएल को &&39

यूआरएल में इन लाइनों को जोड़ें.

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

और संबंधित व्यू कुछ इस तरह दिखेंगे:

... 

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

...

स्ट्राइप, DOMAIN कॉन्सटेंट के मुताबिक आपके डोमेन पर वापस रीडायरेक्ट करता है. इसका मतलब है कि आपको टेंप्लेट के ज़रिए एचटीएमएल रिस्पॉन्स रेंडर करना होगा या फिर वेबसाइट काफ़ी दिखेगी. Let's, bopis/templates/bopis/ डायरेक्ट्री में दो आसान एचटीएमएल फ़ाइलें बनाता है. साथ ही, chat.html का इस्तेमाल करता है.

bm-django-echo-bot/bopis/ टेंप्लेट/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/ टेंप्लेट/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>

इन दो टेंप्लेट की मदद से, आपके स्ट्रिप इंटिग्रेशन के साथ पेमेंट फ़्लो पूरा करने वाला उपयोगकर्ता, सही यूआरएल पर रीडायरेक्ट हो जाता है. साथ ही, उसे उससे जुड़े टेंप्लेट प्रज़ेंट कर दिए जाते हैं. उन्हें Business Messages से भी एक मैसेज मिलेगा, जिसमें उन्हें बातचीत पर वापस जाने की अनुमति दी जाएगी.

6. पैसे पाएं!

बधाई हो, आपके Business Messages एजेंट में, पेमेंट प्रोसेस करने वाली कंपनी शामिल हो गई है!

इस सीरीज़ में, आपने Google Cloud App Engine पर एक वेब ऐप्लिकेशन लागू किया. साथ ही, अपने वेबहुक को बिज़नेस कम्यूनिकेशन डेवलपर कंसोल पर सेट किया. साथ ही, स्टैटिक डेटाबेस के ज़रिए इन्वेंट्री को खोजने के लिए ऐप्लिकेशन को बढ़ाया और Google Datastore का इस्तेमाल करके एक शॉपिंग कार्ट बनाया. सीरीज़ के आखिरी हिस्से में, आपने Stripe के साथ इंटिग्रेट किया था. यह पैसे चुकाने की प्रोसेस करने वाली एक कंपनी है, जो वेब इंटिग्रेशन के साथ-साथ इस सुविधा के साथ काम करती है. अब आप अन्य पेमेंट प्रोसेस करने वाली कंपनी वगैरह की मदद से इंटिग्रेशन में शामिल हो सकते हैं!

d6d80cf9c9fc621.png 44db8d6441dce4c5.png

आगे क्या होगा?

Business Profile में और ज़्यादा मुश्किल इंटरैक्शन के बारे में जानने के लिए, नीचे दिए गए विषयों के बारे में जानें.

रेफ़रंस दस्तावेज़