2023년 6월 13일에 대화형 작업이 종료되기 전에 2023년 5월 3일에 Transactions API가 지원 중단됩니다. 자세한 내용은 대화 작업 지원 중단을 참고하세요.

판매자가 관리하는 결제로 물리적 거래 구축

이 가이드에서는 사이트에서 관리하는 결제 수단을 사용하여 실제 상품의 거래를 통합하는 작업 프로젝트를 개발하는 과정을 안내합니다.

트랜잭션 흐름

작업 프로젝트에서 판매자 관리 결제를 사용하여 실제 트랜잭션을 처리하는 경우 다음 흐름을 사용합니다.

  1. 사용자 계정 연결 - 사용자가 서비스에 저장한 결제 수단을 사용할 수 있도록 하려면 계정 연결을 사용하여 Google 계정을 서비스에 있는 계정과 연결합니다.
  2. 정보 수집 (선택사항) - 트랜잭션의 특성에 따라 대화 초기에 사용자로부터 다음 정보를 수집하는 것이 좋습니다.
    1. 트랜잭션 요구사항 확인 - 대화의 트랜잭션 섹션 시작 시 사용자가 장바구니를 만들기 전에 결제 정보를 올바르게 구성하고 사용할 수 있게 하는 등 거래를 위한 요구사항을 충족하는지 확인합니다.
    2. 배송지 주소 요청 - 거래에 배송지 주소가 필요한 경우 사용자로부터 주소를 수집합니다.
  3. 주문 빌드 - 사용자가 구매할 상품을 선택하는 '장바구니 조립' 과정을 안내합니다.
  4. 주문 제안 - 장바구니가 완료되면 사용자에게 주문이 제대로 되었는지 확인할 수 있도록 주문을 제안합니다. 주문이 확인되면 주문 세부정보와 결제 토큰이 포함된 응답이 전송됩니다.
  5. 주문 완료 및 영수증 전송 - 주문이 확인되면 인벤토리 추적 또는 기타 처리 서비스를 업데이트한 다음 사용자에게 영수증을 전송합니다.
  6. 주문 업데이트 보내기 - 주문 처리의 수명이 지속되는 동안 Orders API에 PATCH 요청을 전송하여 사용자에게 주문 업데이트를 제공합니다.

제한사항 및 검토 가이드라인

거래가 있는 작업에는 추가 정책이 적용됩니다. 트랜잭션이 포함된 작업을 검토하는 데 최대 6주가 걸릴 수 있으므로 출시 일정을 계획할 때 이 시간을 고려하세요. 검토 프로세스를 쉽게 하려면 검토를 위해 작업을 제출하기 전에 트랜잭션 정책 및 가이드라인을 준수하는지 확인하세요.

다음 국가에서는 실제 상품을 판매하는 작업만 배포할 수 있습니다.

오스트레일리아
브라질
캐나다
인도네시아
일본
멕시코
카타르
러시아
싱가포르
스위스
태국
터키
영국
미국

프로젝트 빌드

트랜잭션 대화의 예는 Node.js 트랜잭션 샘플을 참조하세요.

프로젝트 설정

작업을 만들 때 Actions 콘솔에서 트랜잭션을 수행하도록 지정해야 합니다.

프로젝트 및 처리를 설정하려면 다음 단계를 따르세요.

  1. 새 프로젝트를 만들거나 기존 프로젝트를 가져옵니다.
  2. 배포 > 디렉터리 정보로 이동합니다.
  3. 추가 정보 > 거래로 이동하여 '작업에서 Transactions API를 사용하여 실제 상품의 거래를 수행하나요?'라는 내용의 체크박스를 선택합니다.

자체 결제 수단을 사용하여 사용자에게 청구하는 경우 사용자의 Google 계정을 자체 서비스가 포함된 계정에 연결하여 저장된 결제 수단을 검색, 표시, 청구하는 것이 좋습니다.

인증 흐름을 위한 음성 사용자 인터페이스 디자인

사용자가 확인되었는지 확인하고 계정 연결 흐름을 시작합니다.

  1. Actions 콘솔에서 Actions Builder 프로젝트를 엽니다.
  2. 작업에서 계정을 연결하기 위한 새로운 장면을 만듭니다.
    1. 장면을 클릭합니다.
    2. add (+) 아이콘을 클릭하여 새 장면을 추가합니다.
  3. 새로 만든 장면에서 조건의 추가 아이콘을 클릭합니다.
  4. 대화와 연결된 사용자가 확인된 사용자인지 확인하는 조건을 추가합니다. 검사에 실패하면 작업에서 대화 중에 계정 연결을 실행할 수 없으므로 계정 연결이 필요하지 않은 기능에 대한 액세스 권한을 대신 제공해야 합니다.
    1. 조건Enter new expression 필드에 다음 로직을 입력합니다. user.verificationStatus != "VERIFIED"
    2. 전환에서 계정 연결이 필요하지 않은 장면이나 게스트 전용 기능의 진입점인 장면을 선택합니다.

  1. 조건에 추가 아이콘을 클릭합니다.
  2. 사용자에게 연결된 ID가 없는 경우 계정 연결 흐름을 트리거하는 조건을 추가합니다.
    1. 조건Enter new expression 필드에 다음 로직을 입력합니다. user.verificationStatus == "VERIFIED"
    2. 전환에서 계정 연결 시스템 장면을 선택합니다.
    3. 저장을 클릭합니다.

저장 후 <SceneName>_AccountLinking라는 새 계정 연결 시스템 장면이 프로젝트에 추가됩니다.

계정 연결 장면 맞춤설정

  1. Scenes에서 계정 연결 시스템 장면을 선택합니다.
  2. 메시지 보내기를 클릭하고 작업이 ID에 액세스해야 하는 이유를 사용자에게 설명하는 짧은 문장을 추가합니다 (예: '환경설정 저장').
  3. 저장을 클릭합니다.

  1. 조건에서 사용자가 계정 연결을 완료한 경우를 클릭합니다.
  2. 사용자가 계정을 연결하는 데 동의하면 흐름이 진행되는 방식을 구성합니다. 예를 들어 웹훅을 호출하여 필요한 커스텀 비즈니스 로직을 처리하고 원래 장면으로 다시 전환할 수 있습니다.
  3. 저장을 클릭합니다.

  1. 조건에서 사용자가 계정 연결을 취소하거나 닫은 경우를 클릭합니다.
  2. 사용자가 계정 연결에 동의하지 않는 경우 흐름이 진행되는 방식을 구성합니다. 예를 들어 확인 메시지를 보내고 계정 연결이 필요하지 않은 기능을 제공하는 장면으로 리디렉션합니다.
  3. 저장을 클릭합니다.

  1. 조건에서 시스템 또는 네트워크 오류가 발생하는 경우를 클릭합니다.
  2. 시스템 또는 네트워크 오류로 인해 계정 연결 흐름을 완료할 수 없는 경우 흐름이 진행되는 방식을 구성합니다. 예를 들어 확인 메시지를 보내고 계정 연결이 필요하지 않은 기능을 제공하는 장면으로 리디렉션합니다.
  3. 저장을 클릭합니다.

정보 수집(선택사항)

거래 요구사항 확인(선택사항)

사용자가 구매 의사를 밝히는 즉시 트랜잭션을 진행할 수 있는지 확인해야 합니다. 예를 들어 작업이 호출될 때 "신발을 주문하시겠어요, 아니면 계정 잔액을 확인하시겠어요?"라고 질문할 수 있습니다. 사용자가 '신발 주문해'라고 말하면 계속 진행할 수 있는지 확인하고 사용자가 거래를 계속할 수 없도록 하는 모든 설정을 수정할 기회를 제공해야 합니다. 이렇게 하려면 트랜잭션 요구사항 확인을 실행하는 장면으로 전환해야 합니다.

거래 요구사항 확인 장면 만들기
  1. 장면 탭에서 이름이 TransactionRequirementsCheck인 새 장면을 추가합니다.
  2. 슬롯 채우기에서 +를 클릭하여 새 슬롯을 추가합니다.
  3. 유형 선택에서 슬롯 유형으로 actions.type.TransactionRequirementsCheckResult를 선택합니다.
  4. 슬롯 이름 필드에 슬롯 이름을 TransactionRequirementsCheck로 지정합니다.
  5. 슬롯 값 재작성 맞춤설정 체크박스 (기본적으로 사용 설정됨)를 사용 설정합니다.
  6. 저장을 클릭합니다.

거래 요구사항 확인 시 다음 중 한 가지 결과가 발생합니다.

  • 요구사항이 충족되면 세션 매개변수가 성공 조건으로 설정되며 사용자의 주문 빌드를 진행할 수 있습니다.
  • 하나 이상의 요구사항을 충족할 수 없는 경우 세션 매개변수가 실패 조건으로 설정됩니다. 이 경우 대화를 트랜잭션 환경에서 벗어나거나 대화를 종료해야 합니다.
    • 사용자가 실패 상태를 해결할 수 있는 오류가 있으면 기기에서 이러한 문제를 해결하라는 메시지가 표시됩니다. 음성 전용 표시 경로에서 대화가 진행되면 사용자의 휴대전화로 핸드오프가 시작됩니다.

거래 요구사항 확인 결과 처리

  1. Scenes 탭에서 새로 만든 TransactionRequirementsCheck 장면을 선택합니다.
  2. 조건에서 +를 클릭하여 새 조건을 추가합니다.
  3. 텍스트 필드에 다음 조건 구문을 입력하여 성공 조건을 확인합니다.

    scene.slots.status == "FINAL" && session.params.TransactionRequirementsCheck.resultType == "CAN_TRANSACT"
    
  4. 방금 추가한 조건 위로 커서를 가져간 후 위쪽 화살표를 클릭하여 if scene.slots.status == "FINAL" 앞에 배치합니다.

  5. 메시지 보내기를 사용 설정하고 사용자에게 거래를 할 준비가 되었음을 알리는 단순한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: >-
                You are ready to purchase physical goods.
    
  6. 전환에서 다른 장면을 선택하여 사용자가 대화를 계속 진행하고 거래를 진행할 수 있도록 합니다.

  7. 조건 else if scene.slots.status == "FINAL"을 선택합니다.

  8. 메시지 보내기를 사용 설정하고 사용자에게 거래를 할 수 없음을 알리는 간단한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: Transaction requirements check failed.
    
  9. 사용자가 거래를 할 수 없는 경우 Transition에서 EndConversation을 선택하여 대화를 종료합니다.

배송지 주소 요청(선택사항)

거래에 사용자의 배송 주소가 필요한 경우 사용자에게 요청해야 합니다. 총 가격, 배송/수령 위치를 확인하거나 사용자가 서비스 지역 내에 있는지 확인하는 데 유용할 수 있습니다. 이렇게 하려면 사용자에게 배송지 주소를 묻는 장면으로 전환해야 합니다.

배송지 주소 장면 만들기

  1. Scenes 탭에서 이름이 DeliveryAddress인 새 장면을 추가합니다.
  2. 슬롯 채우기에서 +를 클릭하여 새 슬롯을 추가합니다.
  3. 유형 선택에서 슬롯 유형으로 actions.type.DeliveryAddressValue를 선택합니다.
  4. 슬롯 이름 필드에 슬롯 이름을 TransactionDeliveryAddress로 지정합니다.
  5. 슬롯 값 재작성 맞춤설정 체크박스 (기본적으로 사용 설정됨)를 사용 설정합니다.
  6. 저장을 클릭합니다.

시간대를 구성할 때 문자열이 있는 주소를 가져오기 위한 어시스턴트 요청을 시작할 수 있는 reason를 제공할 수 있습니다.기본 이유 문자열은 '주문을 보낼 위치를 아는 것'입니다. 따라서 어시스턴트는 사용자에게 다음과 같이 요청할 수 있습니다. "주문 상품을 어디로 보낼지 알아보려면 배송지 주소를 확인해야 합니다."

  • 화면이 있는 표면에서 사용자는 거래에 사용할 주소를 선택합니다. 이전에 주소를 제공하지 않은 경우 새 주소를 입력할 수 있습니다.
  • 음성 전용 표시 경로에서 어시스턴트는 사용자에게 트랜잭션의 기본 주소를 공유할 수 있는 권한을 요청합니다. 이전에 주소를 제공하지 않은 경우 대화는 전화로 전달되어 입장합니다.

배송 주소 결과를 처리하려면 다음 단계를 따르세요.

  1. Scenes 탭에서 새로 만든 DeliveryAddress 장면을 선택합니다.
  2. 조건에서 +를 클릭하여 새 조건을 추가합니다.
  3. 텍스트 필드에 다음 조건 구문을 입력하여 성공 조건을 확인합니다.

    scene.slots.status == "FINAL" && session.params.TransactionDeliveryAddress.userDecision == "ACCEPTED"
    
  4. 방금 추가한 조건 위로 커서를 가져간 후 위쪽 화살표를 클릭하여 if scene.slots.status == "FINAL" 앞에 배치합니다.

  5. 메시지 보내기를 사용 설정하고 사용자에게 주소를 받았음을 알리는 간단한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Great! Your order will be delivered to
                $session.params.TransactionDeliveryAddress.location.postalAddress.locality
                $session.params.TransactionDeliveryAddress.location.postalAddress.administrativeArea
                $session.params.TransactionDeliveryAddress.location.postalAddress.regionCode
                $session.params.TransactionDeliveryAddress.location.postalAddress.postalCode
    
  6. Transition에서 사용자가 대화를 계속 진행할 수 있도록 다른 장면을 선택합니다.

  7. else if scene.slots.status == "FINAL" 조건을 선택합니다.

  8. 메시지 보내기를 사용 설정하고 사용자에게 거래를 할 수 없음을 알리는 간단한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: I failed to get your delivery address.
    
  9. 사용자가 거래를 할 수 없는 경우 Transition에서 EndConversation을 선택하여 대화를 종료합니다.

주문 빌드

필요한 사용자 정보가 확보되면 사용자에게 주문 빌드를 안내하는 '장바구니 조립' 환경을 빌드하게 됩니다. 각 작업의 제품 또는 서비스에 따라 장바구니 조립 흐름이 약간 달라집니다.

가장 기본적인 장바구니 어셈블리 환경에는 사용자가 목록에서 항목을 선택하여 주문에 추가할 수 있지만, 사용자 환경을 단순화하도록 대화를 설계할 수 있습니다. 사용자가 간단한 예 또는 아니요 질문을 통해 최근 구매 항목을 다시 주문할 수 있는 장바구니 조립 환경을 빌드할 수 있습니다. 상위 '추천' 또는 '추천' 항목의 캐러셀이나 목록 카드를 사용자에게 표시할 수도 있습니다.

리치 응답을 사용하여 사용자의 옵션을 시각적으로 표시하는 동시에 사용자가 자신의 음성만 사용하여 장바구니를 빌드할 수 있도록 대화를 설계하는 것이 좋습니다. 고품질 장바구니 조립 환경의 권장사항과 예는 트랜잭션 설계 가이드라인을 참고하세요.

주문 만들기

대화 중에 사용자가 구매하려는 항목을 수집한 다음 Order 객체를 구성해야 합니다.

Order에는 최소한 다음이 포함되어야 합니다.

  • buyerInfo - 구매하는 사용자에 대한 정보입니다.
  • transactionMerchant - 주문을 지원한 판매자에 대한 정보입니다.
  • contents - lineItems로 표시된 주문의 실제 콘텐츠
  • priceAttributes - 할인 및 세금을 포함한 총 주문 비용을 포함한 주문 가격 세부정보입니다.

장바구니를 구성하려면 Order 응답 문서를 참조하세요. 순서에 따라 다른 필드를 포함해야 할 수도 있습니다.

아래의 샘플 코드는 선택적 필드를 포함한 전체 순서를 보여줍니다.

const order = {
  createTime: '2019-09-24T18:00:00.877Z',
  lastUpdateTime: '2019-09-24T18:00:00.877Z',
  merchantOrderId: orderId, // A unique ID String for the order
  userVisibleOrderId: orderId,
  transactionMerchant: {
    id: 'http://www.example.com',
    name: 'Example Merchant',
  },
  contents: {
    lineItems: [
      {
        id: 'LINE_ITEM_ID',
        name: 'Pizza',
        description: 'A four cheese pizza.',
        priceAttributes: [
          {
            type: 'REGULAR',
            name: 'Item Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 8990000,
            },
            taxIncluded: true,
          },
          {
            type: 'TOTAL',
            name: 'Total Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 9990000,
            },
            taxIncluded: true,
          },
        ],
        notes: [
          'Extra cheese.',
        ],
        purchase: {
          quantity: 1,
          unitMeasure: {
            measure: 1,
            unit: 'POUND',
          },
          itemOptions: [
            {
              id: 'ITEM_OPTION_ID',
              name: 'Pepperoni',
              prices: [
                {
                  type: 'REGULAR',
                  state: 'ACTUAL',
                  name: 'Item Price',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
                {
                  type: 'TOTAL',
                  name: 'Total Price',
                  state: 'ACTUAL',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
              ],
              note: 'Extra pepperoni',
              quantity: 1,
              subOptions: [],
            },
          ],
        },
      },
    ],
  },
  buyerInfo: {
    email: 'janedoe@gmail.com',
    firstName: 'Jane',
    lastName: 'Doe',
    displayName: 'Jane Doe',
  },
  priceAttributes: [
    {
      type: 'SUBTOTAL',
      name: 'Subtotal',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 9990000,
      },
      taxIncluded: true,
    },
    {
      type: 'DELIVERY',
      name: 'Delivery',
      state: 'ACTUAL',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 2000000,
      },
      taxIncluded: true,
    },
    {
      type: 'TAX',
      name: 'Tax',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 3780000,
      },
      taxIncluded: true,
    },
    {
      type: 'TOTAL',
      name: 'Total Price',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 15770000,
      },
      taxIncluded: true,
    },
  ],
  followUpActions: [
    {
      type: 'VIEW_DETAILS',
      title: 'View details',
      openUrlAction: {
        url: 'http://example.com',
      },
    },
    {
      type: 'CALL',
      title: 'Call us',
      openUrlAction: {
        url: 'tel:+16501112222',
      },
    },
    {
      type: 'EMAIL',
      title: 'Email us',
      openUrlAction: {
        url: 'mailto:person@example.com',
      },
    },
  ],
  termsOfServiceUrl: 'http://www.example.com',
  note: 'Sale event',
  promotions: [
    {
      coupon: 'COUPON_CODE',
    },
  ],
  purchase: {
    status: 'CREATED',
    userVisibleStatusLabel: 'CREATED',
    type: 'FOOD',
    returnsInfo: {
      isReturnable: false,
      daysToReturn: 1,
      policyUrl: 'http://www.example.com',
    },
    fulfillmentInfo: {
      id: 'FULFILLMENT_SERVICE_ID',
      fulfillmentType: 'DELIVERY',
      expectedFulfillmentTime: {
        timeIso8601: '2019-09-25T18:00:00.877Z',
      },
      location: location,
      price: {
        type: 'REGULAR',
        name: 'Delivery Price',
        state: 'ACTUAL',
        amount: {
          currencyCode: 'USD',
          amountInMicros: 2000000,
        },
        taxIncluded: true,
      },
      fulfillmentContact: {
        email: 'johnjohnson@gmail.com',
        firstName: 'John',
        lastName: 'Johnson',
        displayName: 'John Johnson',
      },
    },
    purchaseLocationType: 'ONLINE_PURCHASE',
  },
};

주문 및 프레젠테이션 옵션 만들기

사용자가 주문을 확인하기 전에 제안된 주문 카드가 표시됩니다. 다양한 순서와 표시 옵션을 설정하여 이 카드가 사용자에게 표시되는 방식을 맞춤설정할 수 있습니다.

다음은 주문 확인 카드의 사용자 이메일을 포함하여 배송 주소가 필요한 주문을 위한 주문 및 프레젠테이션 옵션입니다.

const orderOptions = {
      'requestDeliveryAddress': true,
      'userInfoOptions': {
        'userInfoProperties': ['EMAIL']
      }
    };

const presentationOptions = {
      'actionDisplayName': 'PLACE_ORDER'
    };

결제 매개변수 만들기

paymentParameters 객체에는 사용자의 주문 결제 수단을 설명하는 필드가 있는 merchantPaymentOption가 포함되어 있습니다. 다음은 Visa 신용카드를 사용한 결제 매개변수의 예입니다.

const paymentParamenters = {
      'merchantPaymentOption': {
        'defaultMerchantPaymentMethodId': '12345678',
        'managePaymentMethodUrl': 'https://example.com/managePayment',
        'merchantPaymentMethod': [{
          'paymentMethodDisplayInfo': {
            'paymentMethodDisplayName': 'VISA **** 1234',
            'paymentType': 'PAYMENT_CARD'
          },
          'paymentMethodGroup': 'Payment method group',
          'paymentMethodId': '12345678',
          'paymentMethodStatus': {
            'status': 'STATUS_OK',
            'statusMessage': 'Status message'
          }
        }]
      }
    };

세션 매개변수에 주문 데이터 저장

처리에서 주문 데이터를 session 매개변수에 저장합니다. 순서 객체는 동일한 세션의 여러 장면에서 사용됩니다.

conv.session.params.order = {
    '@type': 'type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec',
    order: order,
    orderOptions: orderOptions,
    presentationOptions: presentationOptions,
    paymentParameters: paymentParameters
};

주문 제안

주문을 만들었으면 사용자에게 주문을 보여주거나 거부해야 합니다. 이렇게 하려면 트랜잭션 결정을 실행하는 장면으로 전환해야 합니다.

거래 결정 장면 만들기

  1. Scenes 탭에서 이름이 TransactionDecision인 새 장면을 추가합니다.
  2. 슬롯 채우기에서 +를 클릭하여 새 슬롯을 추가합니다.
  3. 유형 선택에서 슬롯 유형으로 actions.type.TransactionDecisionValue를 선택합니다.
  4. 슬롯 이름 필드에 슬롯 이름을 TransactionDecision로 지정합니다.
  5. 슬롯 값 재작성 맞춤설정 체크박스 (기본적으로 사용 설정됨)를 사용 설정합니다.
  6. 슬롯 구성의 드롭다운에서 세션 매개변수 사용을 선택합니다.
  7. 슬롯 구성에서 주문을 텍스트 필드에 저장하는 데 사용되는 세션 매개변수 이름 (예: $session.params.order)을 입력합니다.
  8. 저장을 클릭합니다.

TransactionDecisionValue 슬롯을 채우기 위해 어시스턴트는 개발자가 전달한 Order를 '장바구니 미리보기 카드'에 직접 렌더링하는 내장 환경을 시작합니다. 사용자는 '주문'이라고 말하거나 거래를 거부하거나 신용카드 또는 주소와 같은 결제 옵션을 변경하거나 주문 콘텐츠 변경을 요청할 수 있습니다.

이 시점에서 사용자가 주문 변경을 요청할 수도 있습니다. 이 경우 장바구니 조립 환경을 완료한 후 주문 변경 요청을 처리할 수 있는지 확인해야 합니다.

거래 결정 결과 처리

TransactionDecisionValue 슬롯이 채워지면 사용자의 거래 결정에 대한 답변이 세션 매개변수에 저장됩니다. 이 값에는 다음이 포함됩니다.

  • ORDER_ACCEPTED
  • ORDER_REJECTED
  • DELIVERY_ADDRESS_UPDATED
  • CART_CHANGE_REQUESTED
  • USER_CANNOT_TRANSACT

거래 결정 결과를 처리하는 방법은 다음과 같습니다.

  1. Scenes 탭에서 새로 만든 TransactionDecision 장면을 선택합니다.
  2. 조건에서 +를 클릭하여 새 조건을 추가합니다.
  3. 텍스트 필드에 다음 조건 구문을 입력하여 성공 조건을 확인합니다.

    scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  4. 방금 추가한 조건 위로 커서를 가져간 후 위쪽 화살표를 클릭하여 if scene.slots.status == "FINAL" 앞에 배치합니다.

  5. Send prompt를 사용 설정하고 사용자에게 주문이 완료되었음을 알리는 간단한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction completed! Your order
                $session.params.TransactionDecision.order.merchantOrderId is all
                set!
    
  6. 전환에서 대화 종료를 선택하여 대화를 종료합니다.

  7. 조건에서 +를 클릭하여 새 조건을 추가합니다.

  8. 텍스트 필드에 다음 조건 구문을 입력하여 실패 조건을 확인합니다.

      scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_REJECTED"
    
  9. 방금 추가한 조건 위로 커서를 가져간 후 위쪽 화살표를 클릭하여 if scene.slots.status == "FINAL" 앞에 배치합니다.

  10. Send prompt를 사용 설정하고 사용자에게 주문이 거부되었음을 알리는 간단한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: Look like you don't want to order anything. Goodbye.
    
  11. 전환에서 대화 종료를 선택하여 대화를 종료합니다.

  12. else if scene.slots.status == "FINAL" 조건을 선택합니다.

  13. 메시지 보내기를 사용 설정하고 사용자에게 거래를 할 수 없음을 알리는 간단한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction failed with status
                $session.params.TransactionDecision.transactionDecision
    
  14. 사용자가 거래를 할 수 없는 경우 전환에서 대화 종료를 선택하여 대화를 종료합니다.

주문 완료 및 영수증 전송

TransactionDecisionValue 슬롯이 ORDER_ACCEPTED의 결과를 반환하는 경우 자체 데이터베이스에 유지하고 사용자에게 청구하는 등 주문을 '확인'하는 데 필요한 처리를 즉시 실행해야 합니다.

이 응답으로 대화를 끝낼 수 있지만 대화를 계속 진행하려면 간단한 응답을 포함해야 합니다. 이 초기 orderUpdate를 제공하면 사용자에게 나머지 응답과 함께 '접힌 영수증 카드'가 표시됩니다. 이 카드에는 사용자가 주문 내역에서 찾은 영수증이 반영됩니다.

주문을 확인하는 동안 주문 객체에는 사용자가 주문에 대해 확인하는 userVisibleOrderId인 ID가 포함될 수 있습니다. 이 필드에 merchantOrderId를 재사용할 수 있습니다.

OrderUpdate 객체의 일부에는 사용자가 작업 주문 내역에서 찾을 수 있는 주문 세부정보 하단에 URL 버튼으로 표시되는 후속 작업 객체가 포함되어야 합니다.

  • 각 주문마다 최소한 VIEW_DETAILS 후속 작업은 제공해야 합니다. 여기에는 모바일 앱 또는 웹사이트에서의 주문 표현으로 연결되는 딥 링크가 포함되어야 합니다.
  • 작업과의 대화에서 영수증 카드 외에 거래 실행에 관한 모든 현지 법규를 충족하는 공식 영수증을 이메일로도 보내야 합니다.

초기 주문 업데이트를 보내려면 다음 단계를 따르세요.

  1. Scenes 탭에서 TransactionDecision 장면을 선택합니다.
  2. 조건에서 성공 결과를 확인하는 조건 ORDER_ACCEPTED를 선택합니다.

      scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  3. 이 조건에서 웹훅 호출을 사용 설정하고 인텐트 핸들러 이름(예: update_order)을 지정합니다.

  4. 웹훅 코드에서 초기 주문 업데이트를 전송하기 위한 인텐트 핸들러를 추가합니다.

    app.handle('update_order', conv => {
      const currentTime = new Date().toISOString();
      let order = conv.session.params.TransactionDecision.order;
      conv.add(new OrderUpdate({
        'updateMask': {
          'paths': [
            'purchase.status',
            'purchase.user_visible_status_label'
          ]
        },
        'order': {
          'merchantOrderId': order.merchantOrderId,
          'lastUpdateTime': currentTime,
          'purchase': {
            'status': 'CONFIRMED',
            'userVisibleStatusLabel': 'Order confirmed'
          },
        },
        'reason': 'Reason string
      }));
    });
    

주문 업데이트 보내기

전체 기간 동안 사용자에게 주문 상태를 알려야 합니다. 주문 상태 및 세부정보와 함께 HTTP API 요청을 Orders API에 전송하여 사용자에게 주문 업데이트를 보냅니다.

Orders API에 대한 비동기식 요청 설정

Orders API에 대한 주문 업데이트 요청은 액세스 토큰에 의해 승인됩니다. Orders API로 주문 업데이트를 PATCH하려면 Actions 콘솔 프로젝트와 연결된 JSON 서비스 계정 키를 다운로드한 다음 서비스 계정 키를 HTTP 요청의 Authorization 헤더에 전달할 수 있는 Bearer 토큰으로 교환합니다.

서비스 계정 키를 검색하려면 다음 단계를 수행합니다.

  1. Google Cloud 콘솔에서 메뉴 ☰ > API 및 서비스 > 사용자 인증 정보 만들기 > 서비스 계정 키로 이동합니다.
  2. 서비스 계정에서 새 서비스 계정을 선택합니다.
  3. 서비스 계정을 service-account로 설정합니다.
  4. 역할프로젝트 > 소유자로 설정합니다.
  5. 키 유형을 JSON으로 설정합니다.
  6. 만들기를 선택합니다.
  7. 비공개 JSON 서비스 계정 키가 로컬 머신에 다운로드됩니다.

주문 업데이트 코드에서 Google API 클라이언트 라이브러리와 "https://www.googleapis.com/auth/actions.order.developer" 범위를 사용하여 서비스 키를 Bearer 토큰으로 교환할 수 있습니다. API 클라이언트 라이브러리 GitHub 페이지에서 설치 단계와 예시를 찾을 수 있습니다.

Node.js 샘플order-update.js를 참조하여 키 교환 예시를 확인할 수도 있습니다.

주문 업데이트 보내기

서비스 계정 키를 OAuth Bearer 토큰으로 교환한 후 주문 업데이트를 승인된 PATCH 요청으로 Orders API에 전송할 수 있습니다.

주문 API URL: PATCH https://actions.googleapis.com/v3/orders/${orderId}

요청에 다음 헤더를 제공합니다.

  • "Authorization: Bearer token"을 서비스 계정 키를 교환한 OAuth Bearer 토큰으로 바꿉니다.
  • "Content-Type: application/json"

PATCH 요청은 다음 형식의 JSON 본문을 사용해야 합니다.

{ "orderUpdate": OrderUpdate }

OrderUpdate 객체는 다음과 같은 최상위 필드로 구성됩니다.

  • updateMask - 업데이트하려는 주문의 필드입니다. 주문 상태를 업데이트하려면 값을 purchase.status, purchase.userVisibleStatusLabel로 설정합니다.
  • order - 업데이트의 콘텐츠입니다. 주문의 콘텐츠를 업데이트하는 경우 값을 업데이트된 Order 객체로 설정합니다. 주문 상태를 업데이트하는 경우 (예: "CONFIRMED"에서 "SHIPPED"로) 객체에는 다음 필드가 포함됩니다.

    • merchantOrderId - Order 객체에 설정한 것과 동일한 ID입니다.
    • lastUpdateTime - 이 업데이트의 타임스탬프입니다.
    • purchase - 다음이 포함된 객체입니다.
      • status - PurchaseStatus 형식의 주문 상태입니다(예: 'SHIPPED' 또는 'DELIVERED').
      • userVisibleStatusLabel - '주문 상품이 발송되었으며 배송 중'과 같이 주문 상태에 대한 세부정보를 제공하는 사용자 대상 라벨입니다.
  • userNotification (선택사항) - 이 업데이트가 전송될 때 사용자 기기에 표시될 수 있는 userNotification 객체입니다. 이 객체를 포함한다고 해서 사용자의 기기에 알림이 표시된다고 보장되지는 않습니다.

다음 샘플 코드는 주문 상태를 DELIVERED로 업데이트하는 OrderUpdate 예시를 보여줍니다.

// Import the 'googleapis' module for authorizing the request.
const {google} = require('googleapis');
// Import the 'request-promise' module for sending an HTTP POST request.
const request = require('request-promise');
// Import the OrderUpdate class from the client library.
const {OrderUpdate} = require('@assistant/conversation');

// Import the service account key used to authorize the request.
// Replacing the string path with a path to your service account key.
// i.e. const serviceAccountKey = require('./service-account.json')

// Create a new JWT client for the Actions API using credentials
// from the service account key.
let jwtClient = new google.auth.JWT(
    serviceAccountKey.client_email,
    null,
    serviceAccountKey.private_key,
    ['https://www.googleapis.com/auth/actions.order.developer'],
    null,
);

// Authorize the client
let tokens = await jwtClient.authorize();

// Declare order update
const orderUpdate = new OrderUpdate({
    updateMask: {
      paths: [
        'purchase.status',
        'purchase.user_visible_status_label'
      ]
    },
    order: {
      merchantOrderId: orderId, // Specify the ID of the order to update
      lastUpdateTime: new Date().toISOString(),
      purchase: {
        status: 'DELIVERED',
        userVisibleStatusLabel: 'Order delivered',
      },
    },
    reason: 'Order status updated to delivered.',
});

// Set up the PATCH request header and body,
// including the authorized token and order update.
let options = {
  method: 'PATCH',
  uri: `https://actions.googleapis.com/v3/orders/${orderId}`,
  auth: {
    bearer: tokens.access_token,
  },
  body: {
    header: {
      isInSandbox: true,
    },
    orderUpdate,
  },
  json: true,
};

// Send the PATCH request to the Orders API.
try {
  await request(options);
} catch (e) {
  console.log(`Error: ${e}`);
}
구매 상태 설정

주문 업데이트의 status는 주문의 현재 상태를 설명해야 합니다. 업데이트의 order.purchase.status 필드에서 다음 값 중 하나를 사용합니다.

  • CREATED - 사용자가 주문을 수락하고, 작업의 관점에서 '생성'되지만 백엔드에서 수동 처리가 필요합니다.
  • CONFIRMED - 주문이 활성화되어 있으며 처리를 위해 처리되고 있습니다.
  • IN_PREPARATION - 음식 조리 또는 포장 중인 상품과 같은 배송/배송을 준비 중입니다.
  • READY_FOR_PICKUP - 수취인이 주문 상품을 수령할 수 있습니다.
  • DELIVERED - 주문이 수취인에게 배송되었습니다.
  • OUT_OF_STOCK - 주문에 포함된 항목 중 하나 이상의 재고가 없습니다.
  • CHANGE_REQUESTED - 사용자가 주문 변경을 요청했으며 변경을 처리하는 중입니다.
  • RETURNED - 배송 후 사용자가 주문을 반품했습니다.
  • REJECTED - 주문을 처리하거나 청구하거나 달리 '활성화'할 수 없는 경우
  • CANCELLED - 사용자가 주문을 취소했습니다.

거래와 관련된 각 상태에 대한 주문 업데이트를 전송해야 합니다. 예를 들어, 주문이 완료된 후 주문을 기록하기 위해 트랜잭션에 수동 처리가 필요한 경우 추가 처리가 완료될 때까지 CREATED 주문 업데이트를 전송합니다. 모든 주문에 모든 상태 값이 필요한 것은 아닙니다.

프로젝트 테스트

프로젝트를 테스트할 때 Actions 콘솔에서 샌드박스 모드를 사용 설정하여 결제 수단에 비용을 청구하지 않고 작업을 테스트할 수 있습니다. 샌드박스 모드를 사용 설정하려면 다음 단계를 따르세요.

  1. Actions 콘솔의 탐색 메뉴에서 Test를 클릭합니다.
  2. 설정을 클릭합니다.
  3. 개발 샌드박스 옵션을 사용 설정합니다.

실제 트랜잭션의 경우 샘플에서 isInSandbox 필드를 true로 설정할 수도 있습니다. 이 작업은 Actions 콘솔에서 샌드박스 모드 설정을 사용 설정하는 것과 동일합니다. isInSandbox를 사용하는 코드 스니펫을 보려면 주문 업데이트 보내기 섹션을 참고하세요.

문제 해결

테스트 중에 문제가 발생하면 트랜잭션 문제 해결 단계를 읽어야 합니다.