빌드 예약

이 가이드에서는 Orders API를 사용하여 예약을 하는 작업 프로젝트를 개발하는 과정을 안내합니다.

거래 흐름

작업 프로젝트가 예약을 처리할 때는 다음 흐름을 사용합니다.

  1. 트랜잭션 요구사항 검증 (선택사항) - 대화를 시작할 때 트랜잭션 요구사항 도우미를 사용하여 사용자가 트랜잭션을 수행할 수 있는지 확인합니다.
  2. 주문 작성 - 사용자에게 예약 세부정보를 작성하는 '장바구니' 과정을 안내합니다.
  3. 주문 제안 - '장바구니'가 완료되면 사용자에게 예약 '주문'을 제안하여 사용자가 올바른지 확인할 수 있도록 합니다. 예약이 확인되면 예약 세부정보가 포함된 응답을 받게 됩니다.
  4. 주문 완료 및 영수증 전송 - 주문이 확인되면 예약 시스템을 업데이트하고 사용자에게 영수증을 보냅니다.
  5. 주문 업데이트 전송 - 예약 수명 기간 동안 PATCH 요청을 Orders API에 전송하여 사용자에게 예약 상태 업데이트를 제공합니다.

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

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

다음 국가에서만 Orders API를 사용하는 작업을 배포할 수 있습니다.

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

프로젝트 빌드

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

설정

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

프로젝트와 처리를 설정하려면 다음을 실행하세요.

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

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

사용자가 예약을 설정하겠다고 표시하면 바로 예약을 요청할 수 있는지 확인해야 합니다. 예를 들어 호출될 때 작업이 "좌석을 예약하시겠어요?"라고 물을 수 있습니다. 사용자가 '예'라고 답하면 계속 진행할 수 있는지 확인하고 거래를 계속하지 못하도록 하는 설정을 수정할 기회를 사용자에게 제공해야 합니다. 이렇게 하려면 트랜잭션 요구사항 확인을 실행하는 장면으로 전환해야 합니다.

거래 요구사항 확인 장면 만들기

  1. Scenes 탭에서 이름이 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: >-
                Looks like you're good to go!.
    
  6. Transition에서 다른 장면을 선택하여 사용자가 대화를 계속하고 트랜잭션을 진행할 수 있도록 합니다.

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

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

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

주문 만들기

필요한 사용자 정보를 확보하면 사용자가 예약을 작성하도록 안내하는 '장바구니 어셈블리' 환경을 빌드합니다. 모든 작업은 서비스에 따라 장바구니 어셈블리 흐름이 약간 다릅니다.

기본 장바구니 조립 환경에서는 사용자가 목록에서 옵션을 선택하여 예약에 추가할 수 있지만, 개발자는 사용자 환경을 간소화하도록 대화를 설계할 수 있습니다. 예를 들어 사용자가 간단한 예 또는 아니요 질문을 통해 월별 예약을 예약할 수 있는 장바구니 조립 환경을 빌드할 수 있습니다. '권장' 예약의 캐러셀이나 목록 카드를 사용자에게 표시할 수도 있습니다.

리치 응답을 사용하여 사용자의 옵션을 시각적으로 표시하는 것이 좋지만 사용자가 음성만 사용하여 장바구니를 만들 수 있도록 대화를 설계하는 것이 좋습니다. 장바구니 조립 환경의 일부 권장사항과 예는 디자인 가이드라인을 참고하세요.

주문 만들기

대화 전반에 걸쳐 사용자의 예약 세부정보를 수집한 다음 Order 객체를 구성합니다.

최소한 Order는 다음을 포함해야 합니다.

  • buyerInfo - 구매하는 사용자에 대한 정보입니다.
  • transactionMerchant - 주문을 처리한 판매자에 관한 정보입니다.
  • contents: lineItems로 나열된 주문의 실제 콘텐츠입니다.

장바구니를 구성하려면 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: 'Dinner reservation',
         description: 'A world of flavors all in one destination.',
         reservation: {
           status: 'PENDING',
           userVisibleStatusLabel: 'Reservation is pending.',
           type: 'RESTAURANT',
           reservationTime: {
             timeIso8601: '2020-01-16T01:30:15.01Z',
           },
           userAcceptableTimeRange: {
             timeIso8601: '2020-01-15/2020-01-17',
           },
           partySize: 6,
           staffFacilitators: [
             {
               name: 'John Smith',
             },
           ],
           location: {
             zipCode: '94086',
             city: 'Sunnyvale',
             postalAddress: {
               regionCode: 'US',
               postalCode: '94086',
               administrativeArea: 'CA',
               locality: 'Sunnyvale',
               addressLines: [
                 '222, Some other Street',
               ],
             },
           },
         },
       },
     ],
   },
   buyerInfo: {
     email: 'janedoe@gmail.com',
     firstName: 'Jane',
     lastName: 'Doe',
     displayName: 'Jane Doe',
   },
   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'
 };

순서 및 프레젠테이션 옵션 만들기

const orderOptions = {
      'requestDeliveryAddress': false,
    };

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

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

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

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

주문 제안

예약 주문을 생성한 후에는 사용자에게 예약 주문을 표시하여 확인하거나 거부해야 합니다. 이렇게 하려면 트랜잭션 결정을 실행하는 장면으로 전환해야 합니다.

트랜잭션 결정 장면 만들기

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

TransactionDecisionValue 슬롯을 채우기 위해 어시스턴트는 전달된 Order가 '장바구니 미리보기 카드'에 직접 렌더링되는 내장 환경을 시작합니다. 사용자는 "예약 예약"이라고 말하거나, 거래를 거부하거나, 예약 세부정보 변경을 요청할 수 있습니다.

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

트랜잭션 결정 결과 처리

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

  • ORDER_ACCEPTED,
  • ORDER_REJECTED,
  • 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. 메시지 전송을 사용 설정하고 사용자에게 예약이 완료되었음을 알리는 간단한 메시지를 제공합니다.

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction completed! Your reservation
                $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. 메시지 보내기를 사용 설정하고 사용자에게 주문이 거부되었음을 알리는 간단한 메시지를 제공합니다.

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

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

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

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

예약을 완료하고 영수증 보내기

TransactionDecisionValue 슬롯이 ORDER_ACCEPTED의 결과를 반환하면 개발자는 예약을 예약하는 데 필요한 모든 처리 (예: 자체 데이터베이스에 보존)를 즉시 수행해야 합니다.

간단한 응답을 보내 대화를 이어가세요. 사용자는 응답과 함께 '접힌 영수증 카드'를 받게 됩니다.

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

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

    scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  3. 이 조건의 경우 Call your webhook(웹훅 호출)을 사용 설정하고 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': [
            'reservation.status',
            'reservation.user_visible_status_label',
            'reservation.confirmation_code'
          ]
        },
        'order': {
          'merchantOrderId': order.merchantOrderId,
          'lastUpdateTime': currentTime,
          'reservation': {
            'status': 'CONFIRMED',
            'userVisibleStatusLabel': 'Reservation confirmed',
            'confirmationCode': '123ABCDEFGXYZ',
          },
        },
        'reason': 'Reason string'
      }));
    });
    

주문 업데이트 보내기

예약 상태는 전체 기간 동안 변경됩니다. 주문 상태와 세부정보가 포함된 HTTP PATCH 요청과 함께 사용자 예약 주문 업데이트를 Orders API에 전송합니다.

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

Orders API에 대한 주문 업데이트 요청은 액세스 토큰으로 승인됩니다. Orders API에 주문 업데이트를 PATCH하려면 Actions Console 프로젝트와 연결된 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에 전송합니다.

Order 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 - 업데이트하는 주문의 필드입니다. 예약 상태를 업데이트하려면 값을 reservation.status, reservation.userVisibleStatusLabel로 설정합니다.
  • order - 업데이트 콘텐츠입니다. 예약의 콘텐츠를 업데이트하려면 업데이트된 Order 객체로 값을 설정합니다. 예약 상태만 업데이트하는 경우 (예: "PENDING"에서 "FULFILLED"로) 객체에는 다음 필드가 포함됩니다.

    • merchantOrderId: Order 객체에서 설정한 것과 동일한 ID입니다.
    • lastUpdateTime - 이 업데이트의 타임스탬프입니다.
    • purchase - 다음을 포함하는 객체입니다.
      • status - 주문 상태를 ReservationStatus로 나타냅니다(예: 'CONFIRMED' 또는 'CANCELLED').
      • userVisibleStatusLabel - '예약이 확인되었습니다'와 같이 주문 상태의 세부정보를 제공하는 사용자 대상 라벨입니다.
  • userNotification 객체. 이 객체를 포함한다고 해서 알림이 사용자 기기에 표시되는 것은 아닙니다.

다음 샘플 코드는 예약 주문의 상태를 FULFILLED로 업데이트하는 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 the ID of the order to update.
const orderId = '<UNIQUE_MERCHANT_ORDER_ID>';

// Declare order update
const orderUpdate = new OrderUpdate({
   updateMask: {
     paths: [
       'contents.lineItems.reservation.status',
       'contents.lineItems.reservation.userVisibleStatusLabel'
     ]
   },
   order: {
     merchantOrderId: orderId, // Specify the ID of the order to update
     lastUpdateTime: new Date().toISOString(),
     contents: {
       lineItems: [
         {
           reservation: {
             status: 'FULFILLED',
             userVisibleStatusLabel: 'Reservation fulfilled',
           },
         }
       ]
     },
   },
   reason: 'Reservation status was updated to fulfilled.',
});

// 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}`);
}

예약 상태 설정

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

  • PENDING - 작업에서 예약이 '생성'되었지만 백엔드에서 추가 처리가 필요합니다.
  • CONFIRMED - 예약 백엔드에서 예약이 확인됩니다.
  • CANCELLED - 사용자가 예약을 취소했습니다.
  • FULFILLED - 서비스에서 사용자의 예약이 처리되었습니다.
  • CHANGE_REQUESTED - 사용자가 예약 변경을 요청했으며 변경사항을 처리하는 중입니다.
  • REJECTED - 예약을 처리하거나 확인할 수 없는 경우

예약과 관련된 각 상태에 대한 주문 업데이트를 전송합니다. 예를 들어 예약이 요청된 후 예약을 확인하기 위해 수동 처리가 필요한 경우 추가 처리가 완료될 때까지 PENDING 주문 업데이트를 전송합니다. 모든 예약에 모든 상태 값이 필요한 것은 아닙니다.

프로젝트 테스트

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

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

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

문제 해결

테스트 중에 문제가 발생하면 트랜잭션의 문제 해결 단계를 읽어보세요.