ซื้อของออนไลน์แบบรับสินค้าที่ร้าน: อาหารบงชูร์ - ตอนที่ 2 - การสร้างรถเข็นช็อปปิ้ง

1. บทนำ

53003251caaf2be5.png 8826bd8cb0c0f1c7.png

อัปเดตล่าสุด: 30-10-2020

การสร้างรถเข็นช็อปปิ้งใน Business Messages

นี่เป็นโค้ดแล็บที่ 2 ในชุดที่มุ่งสร้างเส้นทางของผู้ใช้สำหรับ "ซื้อออนไลน์และรับสินค้าที่ร้าน" ในเส้นทางอีคอมเมิร์ซหลายเส้นทาง รถเข็นช็อปปิ้งเป็นกุญแจสําคัญในการเปลี่ยนผู้ใช้ให้กลายเป็นลูกค้าที่ชําระเงิน นอกจากนี้ รถเข็นช็อปปิ้งยังเป็นวิธีทำความเข้าใจลูกค้าได้ดียิ่งขึ้นและวิธีเสนอคำแนะนำเกี่ยวกับสินค้าอื่นๆ ที่ลูกค้าอาจสนใจ ในโค้ดแล็บนี้ เราจะมุ่งเน้นที่การสร้างประสบการณ์การใช้รถเข็นช็อปปิ้งและทำให้แอปพลิเคชันใช้งานได้ใน Google App Engine

รถเข็นช็อปปิ้งที่ดีควรเป็นอย่างไร

รถเข็นช็อปปิ้งเป็นกุญแจสำคัญสู่ประสบการณ์การช็อปปิ้งออนไลน์ที่ประสบความสำเร็จ ผลลัพธ์ที่ได้คือ Business Messages ไม่เพียงช่วยอำนวยความสะดวกในการถามและตอบเกี่ยวกับผลิตภัณฑ์กับลูกค้าเป้าหมายเท่านั้น แต่ยังช่วยอำนวยความสะดวกในการช็อปปิ้งทั้งกระบวนการจนเสร็จสมบูรณ์ภายในการสนทนา

9d17537b980d0e62.png

นอกจากรถเข็นช็อปปิ้งที่ดีแล้ว ประสบการณ์การช็อปปิ้งที่ดียังช่วยให้ผู้ใช้เลือกดูสินค้าตามหมวดหมู่และช่วยให้ธุรกิจแนะนำผลิตภัณฑ์อื่นๆ ที่ผู้ซื้ออาจสนใจได้ หลังจากเพิ่มสินค้าอื่นๆ ลงในรถเข็นช็อปปิ้งแล้ว ผู้ใช้จะตรวจสอบรถเข็นทั้งหมด รวมถึงนำสินค้าออกหรือเพิ่มสินค้าอื่นๆ ก่อนชำระเงินได้

สิ่งที่คุณจะสร้าง

ในส่วนนี้ของชุดโค้ดแล็บ คุณจะต้องขยายความสามารถของตัวแทนดิจิทัลที่คุณสร้างในส่วนที่ 1 สำหรับบริษัทสมมติชื่อ Bonjour Meal เพื่อให้ผู้ใช้เรียกดูแคตตาล็อกสินค้าและเพิ่มสินค้าลงในรถเข็นช็อปปิ้งได้

ใน Codelab นี้ แอปของคุณจะทำสิ่งต่อไปนี้

  • แสดงแคตตาล็อกคําถามภายใน Business Messages
  • แนะนำไอเทมที่ผู้ใช้อาจสนใจ
  • ตรวจสอบเนื้อหาในรถเข็นช็อปปิ้งและสร้างสรุปราคารวม

ab2fb6a4ed33a129.png

สิ่งที่คุณจะได้เรียนรู้

  • วิธีทำให้เว็บแอปพลิเคชันใช้งานได้บน App Engine ใน Google Cloud Platform
  • วิธีใช้กลไกพื้นที่เก็บข้อมูลถาวรเพื่อบันทึกสถานะของรถเข็นช็อปปิ้ง

Codelab นี้มุ่งเน้นที่การขยายตัวแทนดิจิทัลจากส่วนที่ 1 ของชุด Codelab นี้

สิ่งที่ต้องมี

2. การเริ่มตั้งค่า

Codelab นี้จะถือว่าคุณได้สร้างตัวแทนคนแรกและทําส่วนที่ 1 ของ Codelab เสร็จแล้ว ดังนั้น เราจะไม่อธิบายข้อมูลเบื้องต้นเกี่ยวกับการเปิดใช้ Business Messages และ Business Communications API, การสร้างคีย์บัญชีบริการ, การติดตั้งใช้งานแอปพลิเคชัน หรือการตั้งค่า Webhook ใน Business Communications Console อย่างไรก็ตาม เราจะโคลนแอปพลิเคชันตัวอย่างเพื่อให้แน่ใจว่าแอปพลิเคชันของคุณสอดคล้องกับสิ่งที่เรากำลังสร้าง และเราจะเปิดใช้ API สำหรับ Datastore ใน Google Cloud Platform เพื่อให้เก็บข้อมูลที่เกี่ยวข้องกับรถเข็นช็อปปิ้งได้

การโคลนแอปพลิเคชันจาก GitHub

ในเทอร์มินัล ให้โคลน Django Echo Bot Sample ไปยังไดเรกทอรีที่ทำงานของโปรเจ็กต์ด้วยคำสั่งต่อไปนี้

$ git clone https://github.com/google-business-communications/bm-bonjour-meal-django-starter-code

คัดลอกไฟล์ข้อมูลเข้าสู่ระบบ JSON ที่สร้างขึ้นสําหรับบัญชีบริการไปยังโฟลเดอร์ทรัพยากรของตัวอย่าง แล้วเปลี่ยนชื่อข้อมูลเข้าสู่ระบบเป็น "bm-agent-service-account-credentials.json"

bm-bonjour-meal-django-starter-code/bonjourmeal-codelab/step-2/resources/bm-agent-service-account-credentials.json

เปิดใช้ Google Datastore API

ในส่วนที่ 1 ของโค้ดแล็บนี้ คุณได้เปิดใช้ Business Messages API, Business Communications API และ Cloud Build API

สําหรับโค้ดแล็บนี้ เนื่องจากเราจะทํางานกับ Google Datastore เราจึงต้องเปิดใช้ API นี้ด้วย

  1. เปิด Google Datastore API ใน Google Cloud Console
  2. ตรวจสอบว่าคุณกำลังใช้โปรเจ็กต์ GCP ที่ถูกต้อง
  3. คลิกเปิดใช้

ทำให้แอปพลิเคชันตัวอย่างใช้งานได้

ในเทอร์มินัล ให้ไปที่ไดเรกทอรี step-2 ของตัวอย่าง

เรียกใช้คําสั่งต่อไปนี้ในเทอร์มินัลเพื่อทําให้การนําตัวอย่างไปใช้งาน

$ gcloud config set project PROJECT_ID*
$ gcloud app deploy
  • PROJECT_ID คือรหัสโปรเจ็กต์ของโปรเจ็กต์ที่คุณใช้ลงทะเบียนกับ API

จด URL ของแอปพลิเคชันที่ติดตั้งใช้งานไว้ในเอาต์พุตของคําสั่งสุดท้าย

Deployed service [default] to [https://PROJECT_ID.appspot.com]

โค้ดที่คุณเพิ่งทำให้ใช้งานได้มีเว็บแอปพลิเคชันที่มีเว็บฮุคเพื่อรับข้อความจาก Business Messages ไฟล์นี้มีทุกอย่างที่เราทําจากส่วนที่ 1 ของโค้ดแล็บ โปรดกําหนดค่า Webhook หากยังไม่ได้ทํา

แอปพลิเคชันจะตอบคำถามง่ายๆ เช่น ผู้ใช้ถามเกี่ยวกับเวลาทําการของ Bonjour Meal คุณควรทดสอบในอุปกรณ์เคลื่อนที่ผ่าน URL ทดสอบที่ดึงมาจากข้อมูลตัวแทนภายในคอนโซลการสื่อสารทางธุรกิจ URL ทดสอบจะเปิดประสบการณ์การใช้งาน Business Messages บนอุปกรณ์เคลื่อนที่ และคุณสามารถเริ่มโต้ตอบกับตัวแทนได้

3. แคตตาล็อกผลิตภัณฑ์

ระบบสินค้าคงคลัง

ในกรณีส่วนใหญ่ คุณสามารถผสานรวมกับพื้นที่โฆษณาของแบรนด์ได้โดยตรงผ่าน API ภายใน ในกรณีอื่นๆ คุณอาจทำการสกัดข้อมูลหน้าเว็บหรือสร้างระบบติดตามพื้นที่โฆษณาของคุณเอง เราไม่ได้มุ่งเน้นที่การสร้างระบบสินค้าคงคลัง แต่จะใช้ไฟล์คงที่แบบง่ายที่มีรูปภาพและข้อมูลผลิตภัณฑ์สำหรับตัวแทนของเรา ในส่วนนี้ เราจะดึงข้อมูลจากไฟล์แบบคงที่นี้ แสดงข้อมูลนั้นในการสนทนา และอนุญาตให้ผู้ใช้เรียกดูรายการที่พร้อมเพิ่มลงในรถเข็นช็อปปิ้ง

ไฟล์สินค้าคงคลังแบบคงที่มีลักษณะดังนี้

bonjourmeal-codelab/step-2/resources/inventory.json

{

    "food": [
        {
            "id":0,
            "name": "Ham and cheese sandwich",
            "price": "6.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/ham-and-cheese.png",
            "remaining": 8
        },
        {
            "id":1,
            "name": "Chicken veggie wrap",
            "price": "9.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/chicken-veggie-wrap.png",
            "remaining": 2
        },
        {
            "id":2,
            "name": "Assorted cheese plate",
            "price": "7.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/assorted-cheese-plate.png",
            "remaining": 6
        },
        {
            "id":3,
            "name": "Apple walnut salad",
            "price": "12.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/apple-walnut-salad.png",
            "remaining": 1
        }
    ]
}

มาเริ่มใช้แอปพลิเคชัน Python เพื่ออ่านไฟล์นี้กัน

การอ่านจากพื้นที่โฆษณาของเรา

พื้นที่โฆษณาคือไฟล์แบบคงที่ชื่อ "inventory.json" ซึ่งอยู่ในไดเรกทอรี ./resources เราต้องเพิ่มตรรกะ Python บางอย่างลงใน views.py เพื่ออ่านเนื้อหาของไฟล์ JSON แล้วแสดงในการสนทนา มาสร้างฟังก์ชันที่อ่านข้อมูลจากไฟล์ JSON และแสดงรายการผลิตภัณฑ์ที่พร้อมจำหน่ายกัน

คุณสามารถวางคําจํากัดความฟังก์ชันนี้ไว้ที่ใดก็ได้ใน views.py

bonjourmeal-codelab/step-2/bopis/views.py

...
def get_inventory_data():
        f = open(INVENTORY_FILE)
        inventory = json.load(f)
        return inventory
...

ซึ่งน่าจะให้ข้อมูลที่เราจําเป็นต่อการอ่านข้อมูลจากคลังสินค้า ตอนนี้เราต้องการวิธีแสดงข้อมูลผลิตภัณฑ์นี้ในการสนทนา

แสดงแคตตาล็อกผลิตภัณฑ์

เพื่อความสะดวกในโค้ดแล็บนี้ เรามีแคตตาล็อกผลิตภัณฑ์ทั่วไปเพื่อแสดงสินค้าคงคลังทั้งหมดในการสนทนาผ่าน Business Messages ผ่านภาพสไลด์ของการ์ดริชมีเดียใบเดียว

หากต้องการดูแคตตาล็อกผลิตภัณฑ์ เราจะสร้างการตอบกลับที่แนะนำซึ่งมีข้อความ "แสดงเมนู" และ postbackData "show-product-catalog" เมื่อผู้ใช้แตะการตอบกลับที่แนะนำและเว็บแอปพลิเคชันของคุณได้รับข้อมูลการรายงานผล Conversion เราจะส่งภาพสไลด์ของการ์ดริชมีเดีย มาเพิ่มค่าคงที่ใหม่สําหรับคําตอบที่แนะนํานี้ที่ด้านบนของ views.py

bonjourmeal-codelab/step-2/bopis/views.py

...
CMD_SHOW_PRODUCT_CATALOG = 'show-product-catalog'
...

จากตรงนี้ เราจะแยกวิเคราะห์ข้อความและส่งไปยังฟังก์ชันใหม่ที่ส่งภาพสไลด์ของการ์ดริชมีเดียที่มีแคตตาล็อกผลิตภัณฑ์ ก่อนอื่นให้ขยายฟังก์ชัน route_message เพื่อเรียกใช้ฟังก์ชัน "send_product_catalog" เมื่อมีการแตะการตอบที่แนะนำ จากนั้นเราจะกำหนดฟังก์ชัน

ในข้อมูลโค้ดต่อไปนี้ ให้เพิ่มเงื่อนไขเพิ่มเติมลงในคำสั่ง if ในฟังก์ชัน route_message เพื่อตรวจสอบว่า normalized_message เท่ากับค่าคงที่ CMD_SHOW_PRODUCT_CATALOG ที่เรากำหนดไว้ก่อนหน้านี้หรือไม่

bonjourmeal-codelab/step-2/bopis/views.py

...
def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATALOG:
        send_product_catalog(conversation_id)
    else:
        echo_message(message, conversation_id)
...

และมาตรวจสอบว่าทำตามขั้นตอนให้เสร็จสมบูรณ์และกำหนด send_product_catalog send_product_catalog เรียก get_menu_carousel, ซึ่งสร้างภาพสไลด์ของการ์ดริชมีเดียจากไฟล์พื้นที่โฆษณาที่เราอ่านก่อนหน้านี้

คุณสามารถวางคําจํากัดความของฟังก์ชันไว้ที่ใดก็ได้ใน views.py โปรดทราบว่าข้อมูลโค้ดต่อไปนี้ใช้ค่าคงที่ใหม่ 2 รายการที่ควรเพิ่มไว้ที่ด้านบนของไฟล์

bonjourmeal-codelab/step-2/bopis/views.py

...

CMD_ADD_ITEM = 'add-item'
CMD_SHOW_CART = 'show-cart'

...

def get_menu_carousel():
    """Creates a sample carousel rich card.

    Returns:
       A :obj: A BusinessMessagesCarouselCard object with three cards.
    """

    inventory = get_inventory_data()

    card_content = []

    for item in inventory['food']:
        card_content.append(BusinessMessagesCardContent(
            title=item['name'],
            description=item['price'],
            suggestions=[
                BusinessMessagesSuggestion(
                    reply=BusinessMessagesSuggestedReply(
                        text='Add item',
                        postbackData='{'+f'"action":"{CMD_ADD_ITEM}","item_name":"{item["id"]}"'+'}'))

                ],
            media=BusinessMessagesMedia(
                height=BusinessMessagesMedia.HeightValueValuesEnum.MEDIUM,
                contentInfo=BusinessMessagesContentInfo(
                    fileUrl=item['image_url'],
                    forceRefresh=False))))

    return BusinessMessagesCarouselCard(
        cardContents=card_content,
        cardWidth=BusinessMessagesCarouselCard.CardWidthValueValuesEnum.MEDIUM)

def send_product_catalog(conversation_id):
    """Sends the product catalog to the conversation_id.

    Args:
        conversation_id (str): The unique id for this user and agent.
    """
    rich_card = BusinessMessagesRichCard(carouselCard=get_menu_carousel())

    fallback_text = ''

    # Construct a fallback text for devices that do not support carousels
    for card_content in rich_card.carouselCard.cardContents:
        fallback_text += (card_content.title + '\n\n' + card_content.description
                          + '\n\n' + card_content.media.contentInfo.fileUrl
                          + '\n---------------------------------------------\n\n')

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        richCard=rich_card,
        fallback=fallback_text,
        suggestions=[
        BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='See my cart',
                postbackData=CMD_SHOW_CART)
            ),
        BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='See the menu',
                postbackData=CMD_SHOW_PRODUCT_CATALOG)
            ),
        ]
        )

    send_message(message_obj, conversation_id)
...

หากคุณตรวจสอบการสร้างรายการภาพสไลด์ เราจะสร้างอินสแตนซ์ของคลาส BusinessMessagesSuggestion ด้วย คำแนะนำแต่ละรายการแสดงถึงการเลือกผลิตภัณฑ์ของผู้ใช้ในภาพสไลด์ เมื่อผู้ใช้แตะการตอบกลับที่แนะนำ Business Messages จะส่ง postbackData ที่มี JSON ที่อธิบายสินค้าและการดําเนินการที่ผู้ใช้ต้องการทํา (เพิ่มหรือนําออกจากรถเข็น) ไปยัง Webhook ในส่วนถัดไป เราจะแยกวิเคราะห์ข้อความที่มีลักษณะเช่นนี้เพื่อให้เพิ่มสินค้าลงในรถเข็นได้

เมื่อทําการเปลี่ยนแปลงเหล่านี้แล้ว เรามาติดตั้งใช้งานเว็บแอปพลิเคชันใน Google App Engine และลองใช้ประสบการณ์การใช้งานกัน

$ gcloud app deploy

เมื่อโหลดแพลตฟอร์มการสนทนาในอุปกรณ์เคลื่อนที่แล้ว ให้ส่งข้อความ "show-product-catalog" แล้วคุณจะเห็นภาพสไลด์ของผลิตภัณฑ์ที่มีลักษณะเช่นนี้

4639da46bcc5230c.png

หากแตะเพิ่มรายการ ไม่มีอะไรจะเกิดขึ้นจริง ยกเว้นตัวแทนจะส่งต่อข้อมูลการรายงานผล Conversion จากการตอบกลับที่แนะนำ ในส่วนถัดไป เราจะใช้ประโยชน์จากแคตตาล็อกผลิตภัณฑ์และนำไปสร้างรถเข็นช็อปปิ้งที่จะเพิ่มสินค้า

แคตตาล็อกผลิตภัณฑ์ที่คุณเพิ่งสร้างสามารถขยายได้หลายวิธี คุณอาจมีตัวเลือกเมนูเครื่องดื่มหรือตัวเลือกอาหารมังสวิรัติที่แตกต่างออกไป การใช้ภาพสไลด์หรือชิปคำแนะนำเป็นวิธีที่ยอดเยี่ยมในการช่วยให้ผู้ใช้เจาะลึกตัวเลือกเมนูเพื่อไปยังชุดผลิตภัณฑ์ที่กําลังมองหา เพื่อเป็นการขยายการทำงานจากโค้ดแล็บนี้ ให้ลองขยายระบบแคตตาล็อกผลิตภัณฑ์เพื่อให้ผู้ใช้ดูเครื่องดื่มแยกจากอาหารในเมนู หรือแม้แต่ระบุตัวเลือกอาหารมังสวิรัติได้

4. รถเข็นช็อปปิ้ง

ในส่วนนี้ของโค้ดแล็บ เราจะสร้างฟังก์ชันการทำงานของรถเข็นช็อปปิ้งต่อจากส่วนก่อนหน้า ซึ่งจะช่วยให้เราเรียกดูผลิตภัณฑ์ที่มีได้

ประสบการณ์การใช้งานรถเข็นช็อปปิ้งที่สำคัญอย่างหนึ่งคือช่วยให้ผู้ใช้เพิ่มสินค้าลงในรถเข็น นำสินค้าออกจากรถเข็น ติดตามจำนวนสินค้าแต่ละรายการในรถเข็น และตรวจสอบสินค้าในรถเข็นได้

การติดตามสถานะรถเข็นช็อปปิ้งหมายความว่าเราต้องเก็บข้อมูลไว้ในเว็บแอปพลิเคชัน เราจะใช้ Google Datastore ใน Google Cloud Platform เพื่อเก็บข้อมูลไว้อย่างถาวรเพื่อให้การทดสอบและการติดตั้งใช้งานง่ายขึ้น รหัสการสนทนาระหว่างผู้ใช้กับธุรกิจจะยังคงเดิม เราจึงใช้รหัสนี้เพื่อเชื่อมโยงผู้ใช้กับรายการในรถเข็นช็อปปิ้งได้

มาเริ่มกันด้วยการเชื่อมต่อกับ Google Datastore และเก็บรหัสการสนทนาไว้เมื่อเห็น

การเชื่อมต่อกับ Datastore

เราจะเชื่อมต่อกับ Google Datastore ทุกครั้งที่มีการโต้ตอบกับรถเข็นช็อปปิ้ง เช่น เมื่อผู้ใช้เพิ่มหรือลบสินค้า ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ไลบรารีไคลเอ็นต์นี้เพื่อโต้ตอบกับ Google Datastore ได้ที่เอกสารประกอบอย่างเป็นทางการ

ข้อมูลโค้ดต่อไปนี้จะกําหนดฟังก์ชันเพื่ออัปเดตรถเข็นช็อปปิ้ง ฟังก์ชันนี้ใช้อินพุต conversation_id และ message message มี JSON ที่อธิบายการดำเนินการที่ผู้ใช้ต้องการ ซึ่งสร้างไว้ในภาพสไลด์ที่แสดงแคตตาล็อกผลิตภัณฑ์อยู่แล้ว ฟังก์ชันนี้จะสร้างไคลเอ็นต์ Google Datastore และดึงข้อมูลเอนทิตี ShoppingCart ทันที โดยที่รหัสคือรหัสการสนทนา

คัดลอกฟังก์ชันต่อไปนี้ลงในไฟล์ views.py เราจะขยายความในส่วนถัดไป

bonjourmeal-codelab/step-2/bopis/views.py

from google.oauth2 import service_account
from google.cloud import datastore

def update_shopping_cart(conversation_id, message):
        credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_LOCATION)

        client = datastore.Client(credentials=credentials)
        key = client.key('ShoppingCart', conversation_id)
        entity = datastore.Entity(key=key)
        result = client.get(key)
        
        # TODO: Add logic to add and remove items from cart
        
        entity.update(result)
        client.put(entity)

มาขยายฟังก์ชันนี้เพื่อเพิ่มสินค้าลงในรถเข็นกัน

การเพิ่มสินค้าลงในรถเข็น

เมื่อผู้ใช้แตะการดําเนินการที่แนะนําเพิ่มสินค้าจากภาพสไลด์ผลิตภัณฑ์ ระบบจะใส่ JSON ที่อธิบายการดําเนินการที่ผู้ใช้ต้องการดำเนินการไว้ใน postbackData พจนานุกรม JSON มี 2 คีย์ ได้แก่ "action" และ "item_name" และระบบจะส่งพจนานุกรม JSON นี้ไปยัง Webhook ช่อง "item_name" คือตัวระบุที่ไม่ซ้ำกันซึ่งเชื่อมโยงกับสินค้าใน inventory.json

เมื่อเรามีคำสั่งรถเข็นและรายการรถเข็นที่แยกวิเคราะห์จากข้อความแล้ว เราจะเขียนคำสั่งเงื่อนไขเพื่อเพิ่มรายการได้ กรณีขอบเขตที่ควรพิจารณา ได้แก่ ในกรณีที่ Datastore ไม่เคยเห็นรหัสการสนทนา หรือรถเข็นช็อปปิ้งได้รับรายการนี้เป็นครั้งแรก ต่อไปนี้เป็นฟังก์ชันการทำงานเพิ่มเติมของ update_shopping_cart ที่ระบุไว้ข้างต้น การเปลี่ยนแปลงนี้จะเพิ่มสินค้าลงในรถเข็นช็อปปิ้งซึ่ง Google Datastore เก็บไว้

ข้อมูลโค้ดต่อไปนี้เป็นส่วนขยายของฟังก์ชันก่อนหน้าที่เพิ่มลงใน views.py คุณเพิ่มความแตกต่างหรือคัดลอกข้อมูลโค้ดมาแทนที่ฟังก์ชัน update_shopping_cart เวอร์ชันที่มีอยู่ก็ได้

bonjourmeal-codelab/step-2bopis/views.py

def update_shopping_cart(conversation_id, message):
    credentials = service_account.Credentials.from_service_account_file(
      SERVICE_ACCOUNT_LOCATION)
    inventory = get_inventory_data()

    cart_request = json.loads(message)
    cart_cmd = cart_request["action"]
    cart_item = cart_request["item_name"]

    item_name = inventory['food'][int(cart_item)]['name']

    client = datastore.Client(credentials=credentials)
    key = client.key('ShoppingCart', conversation_id)
    entity = datastore.Entity(key=key)
    result = client.get(key)

    if result is None:
        if cart_cmd == CMD_ADD_ITEM:
            entity.update({
                item_name: 1
            })

    else:
        if cart_cmd == CMD_ADD_ITEM:
            if result.get(item_name) is None:
                result[item_name] = 1
            else:
                result[item_name] = result[item_name] + 1

        entity.update(result)
    client.put(entity)

เราจะขยายฟังก์ชันนี้ในภายหลังเพื่อรองรับกรณีที่ cart_cmd มีสตริง "del-item" ที่กําหนดไว้ใน CMD_DEL_ITEM

การเชื่อมโยงข้อมูลเข้าด้วยกัน

ตรวจสอบว่าคุณได้เพิ่มการต่อท่อในฟังก์ชัน route_message เพื่อให้ระบบเรียกใช้ฟังก์ชัน update_shopping_cart เมื่อคุณได้รับข้อความให้เพิ่มสินค้าลงในรถเข็น นอกจากนี้ คุณยังต้องกำหนดค่าคงที่สำหรับการเพิ่มรายการโดยใช้รูปแบบที่เราใช้ในโค้ดแล็บ

bonjourmeal-codelab/step-2bopis/views.py

...

CMD_DEL_ITEM = 'del-item'

...

def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATEGORY:
        send_product_catalog(conversation_id)
    elif CMD_ADD_ITEM in normalized_message or CMD_DEL_ITEM in normalized_message:
       update_shopping_cart(conversation_id, message)
    else:
        echo_message(message, conversation_id)

...

ขณะนี้เราเพิ่มสินค้าลงในรถเข็นช็อปปิ้งได้ หากทําให้การเปลี่ยนแปลงมีผลใน Google App Engine คุณควรจะเห็นการเปลี่ยนแปลงรถเข็นช็อปปิ้งแสดงในหน้าแดชบอร์ด Google Datastore ในคอนโซล GCP ดูภาพหน้าจอด้านล่างของคอนโซล Google Datastore จะมีเอนทิตีเดียวที่ตั้งชื่อตามรหัสการสนทนา ตามด้วยความสัมพันธ์บางอย่างกับสินค้าคงคลังและจำนวนสินค้าเหล่านั้นที่อยู่ในรถเข็นช็อปปิ้ง

619dc18a8136ea69.png

ในส่วนถัดไป เราจะสร้างวิธีแสดงรายการในรถเข็นช็อปปิ้ง กลไกการตรวจสอบรถเข็นช็อปปิ้งควรแสดงรายการทั้งหมดในรถเข็น จำนวนของรายการเหล่านั้น และตัวเลือกในการนำสินค้าออกจากรถเข็น

การตรวจสอบสินค้าในรถเข็น

การระบุรายการในรถเข็นช็อปปิ้งเป็นวิธีเดียวที่เราเข้าใจสถานะของรถเข็นช็อปปิ้งและรู้ว่าจะนำรายการใดออกได้

ก่อนอื่นให้ส่งข้อความที่เป็นมิตร เช่น "นี่คือรถเข็นช็อปปิ้งของคุณ" ตามด้วยข้อความอื่นที่มีภาพสไลด์ของ Rich Card พร้อมคำตอบแนะนำที่เกี่ยวข้องสำหรับ "นำออก 1 รายการ" หรือ "เพิ่ม 1 รายการ" ภาพสไลด์ของการ์ดริชมีเดียควรแสดงจำนวนสินค้าที่บันทึกไว้ในรถเข็นด้วย

สิ่งที่ควรทราบก่อนที่จะเขียนฟังก์ชันจริงคือ หากมีสินค้าเพียงประเภทเดียวในรถเข็นช็อปปิ้ง เราจะแสดงผลเป็นภาพสไลด์ไม่ได้ ภาพสไลด์ของการ์ดริชมีเดียต้องมีการ์ดอย่างน้อย 2 ใบ ในทางกลับกัน หากไม่มีสินค้าในรถเข็น เราต้องการแสดงข้อความง่ายๆ ที่ระบุว่ารถเข็นว่างเปล่า

ด้วยเหตุนี้ เรามากำหนดฟังก์ชันชื่อ send_shopping_cart กัน ฟังก์ชันนี้จะเชื่อมต่อกับ Google Datastore และขอเอนทิตี ShoppingCart ตามรหัสการสนทนา เมื่อได้ข้อมูลแล้ว เราจะเรียกใช้ฟังก์ชัน get_inventory_data และใช้ภาพสไลด์ของการ์ดริชมีเดียเพื่อรายงานสถานะของรถเข็นช็อปปิ้ง นอกจากนี้ เราจะต้องขอรหัสของผลิตภัณฑ์ตามชื่อ และสามารถประกาศฟังก์ชันเพื่อค้นหาใน Google Datastore เพื่อระบุค่าดังกล่าว ขณะสร้างภาพสไลด์ เราสามารถเชื่อมโยงการตอบกลับที่แนะนำเพื่อลบรายการหรือเพิ่มรายการตามรหัสผลิตภัณฑ์ ข้อมูลโค้ดด้านล่างจะดําเนินการทั้งหมดเหล่านี้ คัดลอกโค้ดไปวางที่ใดก็ได้ใน views.py

bonjourmeal-codelab/step-2/bopis/views.py

...
def get_id_by_product_name(product_name):
  inventory = get_inventory_data()
  for item in inventory['food']:
    if item['name'] == product_name:
      return int(item['id'])
  return False


def send_shopping_cart(conversation_id):
  credentials = service_account.Credentials.from_service_account_file(
      SERVICE_ACCOUNT_LOCATION)

  # Retrieve the inventory data
  inventory = get_inventory_data()

  # Pull the data from Google Datastore
  client = datastore.Client(credentials=credentials)
  key = client.key('ShoppingCart', conversation_id)
  result = client.get(key)

  shopping_cart_suggestions = [
      BusinessMessagesSuggestion(
          reply=BusinessMessagesSuggestedReply(
              text='See total price', postbackData='show-cart-price')),
      BusinessMessagesSuggestion(
          reply=BusinessMessagesSuggestedReply(
              text='Empty the cart', postbackData='empty-cart')),
      BusinessMessagesSuggestion(
          reply=BusinessMessagesSuggestedReply(
              text='See the menu', postbackData=CMD_SHOW_PRODUCT_CATALOG)),
  ]

  if result is None or len(result.items()) == 0:
    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        text='There are no items in your shopping cart.',
        suggestions=shopping_cart_suggestions)

    send_message(message_obj, conversation_id)
  elif len(result.items()) == 1:

    for product_name, quantity in result.items():
      product_id = get_id_by_product_name(product_name)

      fallback_text = ('You have one type of item in the shopping cart')

      rich_card = BusinessMessagesRichCard(
          standaloneCard=BusinessMessagesStandaloneCard(
              cardContent=BusinessMessagesCardContent(
                  title=product_name,
                  description=f'{quantity} in cart.',
                  suggestions=[
                      BusinessMessagesSuggestion(
                          reply=BusinessMessagesSuggestedReply(
                              text='Remove one',
                              postbackData='{'+f'"action":"{CMD_DEL_ITEM}","item_name":"{product_id}"'+'}'))
                  ],
                  media=BusinessMessagesMedia(
                      height=BusinessMessagesMedia.HeightValueValuesEnum.MEDIUM,
                      contentInfo=BusinessMessagesContentInfo(
                          fileUrl=inventory['food'][product_id]
                          ['image_url'],
                          forceRefresh=False)))))

      message_obj = BusinessMessagesMessage(
          messageId=str(uuid.uuid4().int),
          representative=BOT_REPRESENTATIVE,
          richCard=rich_card,
          suggestions=shopping_cart_suggestions,
          fallback=fallback_text)

      send_message(message_obj, conversation_id)
  else:
    cart_carousel_items = []

    # Iterate through the cart and generate a carousel of items
    for product_name, quantity in result.items():
      product_id = get_id_by_product_name(product_name)

      cart_carousel_items.append(
          BusinessMessagesCardContent(
              title=product_name,
              description=f'{quantity} in cart.',
              suggestions=[
                  BusinessMessagesSuggestion(
                      reply=BusinessMessagesSuggestedReply(
                          text='Remove one',
                          postbackData='{'+f'"action":"{CMD_DEL_ITEM}","item_name":"{product_id}"'+'}'))
              ],
              media=BusinessMessagesMedia(
                  height=BusinessMessagesMedia.HeightValueValuesEnum.MEDIUM,
                  contentInfo=BusinessMessagesContentInfo(
                      fileUrl=inventory['food'][product_id]
                      ['image_url'],
                      forceRefresh=False))))

    rich_card = BusinessMessagesRichCard(
        carouselCard=BusinessMessagesCarouselCard(
            cardContents=cart_carousel_items,
            cardWidth=BusinessMessagesCarouselCard.CardWidthValueValuesEnum
            .MEDIUM))

    fallback_text = ''

    # Construct a fallback text for devices that do not support carousels
    for card_content in rich_card.carouselCard.cardContents:
      fallback_text += (
          card_content.title + '\n\n' + card_content.description + '\n\n' +
          card_content.media.contentInfo.fileUrl +
          '\n---------------------------------------------\n\n')

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        richCard=rich_card,
        suggestions=shopping_cart_suggestions,
        fallback=fallback_text,
    )

    send_message(message_obj, conversation_id)

...

ตรวจสอบว่าคุณได้กําหนด CMD_SHOW_CART ที่ด้านบนของ views.py แล้ว และเรียกใช้ send_shopping_cart หากผู้ใช้ส่งข้อความที่มี "show-cart"

bonjourmeal-codelab/step-2/bopis/views.py

...
def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATEGORY:
        send_product_catalog(conversation_id)
    elif CMD_ADD_ITEM in normalized_message or CMD_DEL_ITEM in normalized_message:
        update_shopping_cart(conversation_id, message)
    elif normalized_message == CMD_SHOW_CART:
        send_shopping_cart(conversation_id)
    else:
        echo_message(message, conversation_id)
...

34801776a97056ac.png

จากตรรกะที่เราได้แนะนำไว้ในฟังก์ชัน send_shopping_cart เมื่อคุณพิมพ์ "show-cart" เราจะได้ข้อความระบุว่าไม่มีสินค้าในรถเข็น การ์ดริชมีเดียที่แสดงสินค้า 1 รายการในรถเข็น หรือภาพสไลด์ของการ์ดที่แสดงสินค้าหลายรายการ นอกจากนี้ เรายังมีคำตอบแนะนำ 3 รายการ ได้แก่ "ดูราคารวม" "ล้างรถเข็น" และ "ดูเมนู"

ลองใช้การเปลี่ยนแปลงโค้ดข้างต้นเพื่อทดสอบว่ารถเข็นช็อปปิ้งติดตามสินค้าที่เพิ่มและคุณสามารถตรวจสอบรถเข็นจากแพลตฟอร์มการสนทนาได้ตามที่แสดงในภาพหน้าจอด้านบน คุณสามารถทําให้การเปลี่ยนแปลงใช้งานได้ด้วยคําสั่งนี้ที่เรียกใช้จากไดเรกทอรี step-2 ที่คุณเพิ่มการเปลี่ยนแปลง

$ gcloud app deploy

เราจะสร้างฟีเจอร์ "ดูราคารวม" ในส่วนถัดไปหลังจากสร้างฟังก์ชันการทำงานเพื่อนำสินค้าออกจากรถเข็นแล้ว ฟังก์ชัน get_cart_price จะทํางานคล้ายกับฟีเจอร์ "ดูรถเข็นช็อปปิ้ง" ตรงที่จะตรวจสอบข้อมูลใน Datastore กับไฟล์ inventory.json เพื่อให้ได้ราคารวมของรถเข็นช็อปปิ้ง ซึ่งจะมีประโยชน์สำหรับส่วนถัดไปของโค้ดแล็บที่เราผสานรวมกับการชำระเงิน

การนำสินค้าออกจากรถเข็น

สุดท้าย เราจะทําให้ลักษณะการทํางานของรถเข็นช็อปปิ้งเสร็จสมบูรณ์ได้ด้วยการแสดงฟังก์ชันการนํารถเข็นออก แทนที่ฟังก์ชัน update_shopping_cart ที่มีอยู่ด้วยข้อมูลโค้ดต่อไปนี้

bonjourmeal-codelab/step-2/ bopis/views.py

def update_shopping_cart(conversation_id, message):
    credentials = service_account.Credentials.from_service_account_file(
      SERVICE_ACCOUNT_LOCATION)
    inventory = get_inventory_data()

    cart_request = json.loads(message)
    cart_cmd = cart_request["action"]
    cart_item = cart_request["item_name"]

    item_name = inventory['food'][int(cart_item)]['name']


    client = datastore.Client(credentials=credentials)
    key = client.key('ShoppingCart', conversation_id)
    entity = datastore.Entity(key=key)
    result = client.get(key)

    if result is None:
        if cart_cmd == CMD_ADD_ITEM:
            entity.update({
                item_name: 1
            })
        elif cart_cmd == CMD_DEL_ITEM:
            # The user is trying to delete an item from an empty cart. Pass and skip
            pass

    else:
        if cart_cmd == CMD_ADD_ITEM:
            if result.get(item_name) is None:
                result[item_name] = 1
            else:
                result[item_name] = result[item_name] + 1

        elif cart_cmd == CMD_DEL_ITEM:
            if result.get(item_name) is None:
                # The user is trying to remove an item that's no in the shopping cart. Pass and skip
                pass
            elif result[item_name] - 1 > 0:
                result[item_name] = result[item_name] - 1
            else:
                del result[item_name]

        entity.update(result)
    client.put(entity)

การส่งข้อความยืนยัน

เมื่อผู้ใช้เพิ่มสินค้าลงในรถเข็น คุณควรส่งข้อความยืนยันเพื่อรับทราบการดําเนินการของผู้ใช้และแจ้งว่าคุณได้ดําเนินการตามคําขอแล้ว วิธีนี้ไม่เพียงช่วยกำหนดความคาดหวัง แต่ยังช่วยให้การสนทนาดำเนินต่อไปด้วย

มาขยายฟังก์ชัน update_shopping_cart เพื่อส่งข้อความไปยังรหัสการสนทนาที่ระบุว่ามีการเพิ่มหรือนำสินค้าออกแล้ว และแสดงคำแนะนำให้ตรวจสอบรถเข็นช็อปปิ้งหรือดูเมนูอีกครั้ง

bonjourmeal-codelab/step-2/bopis/views.py

def update_shopping_cart(conversation_id, message):

     # No changes to the function, except appending the following logic
     ...
   
    if cart_cmd == CMD_ADD_ITEM:
        message = 'Great! You\'ve added an item to the cart.'
    else:
        message = 'You\'ve removed an item from the cart.'

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        text=message,
        suggestions=[
            BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='Review shopping cart',
                postbackData=CMD_SHOW_CART)
            ),
            BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='See menu again',
                postbackData=CMD_SHOW_PRODUCT_CATALOG)
            ),
            ])
    send_message(message_obj, conversation_id)

905a1f3d89893ba0.png

เท่านี้ก็เรียบร้อย ประสบการณ์การใช้งานรถเข็นช็อปปิ้งที่สมบูรณ์แบบซึ่งช่วยให้ผู้ใช้เพิ่มสินค้า นำสินค้าออก และตรวจสอบสินค้าในรถเข็นได้

เมื่อถึงขั้นตอนนี้ หากต้องการดูฟังก์ชันการทำงานของรถเข็นช็อปปิ้งในการสนทนาผ่าน Business Messages ให้ติดตั้งใช้งานแอปพลิเคชันเพื่อโต้ตอบกับตัวแทน ซึ่งทำได้โดยการเรียกใช้คำสั่งนี้ในไดเรกทอรี step-2

$ gcloud app deploy

5. การเตรียมพร้อมสําหรับการชําระเงิน

เราต้องการวิธีรับราคาของรถเข็นช็อปปิ้งเพื่อเตรียมพร้อมสำหรับการผสานรวมกับระบบประมวลผลการชำระเงินในภาคถัดไปของชุดบทแนะนำนี้ มาสร้างฟังก์ชันที่ดึงข้อมูลราคาให้เราโดยตรวจสอบข้อมูลรถเข็นช็อปปิ้งใน Google Datastore, ดึงข้อมูลราคาของแต่ละรายการจากสินค้าคงคลัง และคูณราคาด้วยจำนวนของแต่ละรายการในรถเข็น

bonjourmeal-codelab/step-2/bopis/views.py

...
def get_cart_price(conversation_id):
    # Pull the data from Google Datastore
    credentials = service_account.Credentials.from_service_account_file(
    SERVICE_ACCOUNT_LOCATION)
    client = datastore.Client(credentials=credentials)
    key = client.key('ShoppingCart', conversation_id)
    entity = datastore.Entity(key=key)
    result = client.get(key)

    # Retrieve the inventory data
    inventory = get_inventory_data()
   
    # Start off with a total of 0 before adding up the total
    total_price = 0

    if len(result.items()) != 0:
      for product_name, quantity in result.items():
        total_price = total_price + float(
            inventory['food'][get_id_by_product_name(product_name)]['price']) * int(quantity)

    return total_price

...

และสุดท้าย เราจะใช้ฟังก์ชันดังกล่าวและส่งข้อความถึงผู้ใช้ได้

bonjourmeal-codelab/step-2/bopis/views.py

...

def send_shopping_cart_total_price(conversation_id):
    cart_price = get_cart_price(conversation_id)

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        suggestions=[],
        text=f'Your cart\'s total price is ${cart_price}.')

    send_message(message_obj, conversation_id)
...

มาสรุปทั้งหมดกันด้วยการอัปเดตฟังก์ชัน route_message และค่าคงที่เพื่อเรียกใช้ตรรกะข้างต้น

bonjourmeal-codelab/step-2/bopis/views.py

...
CMD_GET_CART_PRICE = 'show-cart-price'
...
def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATEGORY:
        send_product_catalog(conversation_id)
    elif CMD_ADD_ITEM in normalized_message or CMD_DEL_ITEM in normalized_message:
        update_shopping_cart(conversation_id, message)
    elif normalized_message == CMD_SHOW_CART:
        send_shopping_cart(conversation_id)
    elif normalized_message == CMD_GET_CART_PRICE:
        send_shopping_cart_total_price(conversation_id)
    else:
        echo_message(message, conversation_id)
...

ภาพหน้าจอบางส่วนที่แสดงผลลัพธ์ของตรรกะข้างต้นมีดังนี้

8feacf94ed0ac6c4.png

เมื่อพร้อมที่จะผสานรวมกับผู้ประมวลผลการชำระเงินในส่วนถัดไปของโค้ดแล็บ เราจะเรียกใช้ฟังก์ชัน get_cart_price เพื่อส่งข้อมูลไปยังผู้ประมวลผลการชำระเงินและเริ่มขั้นตอนการชําระเงิน

อีกครั้ง คุณสามารถลองใช้ฟังก์ชันการทำงานของรถเข็นช็อปปิ้งนี้ในการสนทนาผ่าน Business Messages ได้โดยการติดตั้งใช้งานแอปพลิเคชันและโต้ตอบกับตัวแทน

$ gcloud app deploy

6. ขอแสดงความยินดี

ยินดีด้วย คุณสร้างประสบการณ์การใช้รถเข็นช็อปปิ้งภายใน Business Messages เรียบร้อยแล้ว

สิ่งที่เราไม่ได้พูดถึงในโค้ดแล็บนี้คือฟีเจอร์สำหรับล้างรถเข็นช็อปปิ้งทั้งหมด หากต้องการ ให้ลองขยายระยะเวลาของใบสมัครเพื่อใช้ฟีเจอร์ "ล้างรถเข็น" โซลูชันจะอยู่ในขั้นตอนที่ 3 ของซอร์สโค้ดที่คุณโคลน

เราจะผสานรวมกับผู้ให้บริการประมวลผลการชำระเงินภายนอกในอนาคตเพื่อให้ผู้ใช้ทำธุรกรรมการชำระเงินกับแบรนด์ของคุณได้

รถเข็นช็อปปิ้งที่ดีควรเป็นอย่างไร

ประสบการณ์การใช้รถเข็นช็อปปิ้งที่ดีในการสนทนานั้นไม่ต่างจากแอปบนอุปกรณ์เคลื่อนที่หรือในร้านค้าจริง ความสามารถในการเพิ่มสินค้า นำสินค้าออก และคำนวณราคาของรถเข็นเป็นเพียงฟีเจอร์บางส่วนที่เราได้สำรวจในโค้ดแล็บนี้ สิ่งที่แตกต่างจากรถเข็นช็อปปิ้งในชีวิตจริงคือความสามารถในการดูราคาของสินค้าทั้งหมดในรถเข็นได้ทุกเมื่อขณะที่คุณเพิ่มหรือนำสินค้าออก ฟีเจอร์ที่มีคุณค่าสูงประเภทนี้จะทำให้ประสบการณ์คอมเมิร์ซแบบการสนทนาของคุณโดดเด่น

ขั้นตอนถัดไป

เมื่อพร้อมแล้ว ให้ดูหัวข้อต่อไปนี้เพื่อดูข้อมูลเกี่ยวกับการโต้ตอบที่ซับซ้อนมากขึ้นที่คุณทำได้ใน Business Messages

เอกสารอ้างอิง