빌드 예약 (Dialogflow)

이 가이드에서는 작업 프로젝트를 개발하는 과정을 안내합니다. 예약하기 위한 API입니다.

거래 흐름

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

  1. 거래 요구사항 확인 (선택사항) - 거래 요구사항 도우미를 사용합니다. 대화를 시작할 때 매우 중요하며,
  2. 주문하기 - 사용자에게 '장바구니 조립' 예약의 세부정보를 빌드하는 곳입니다.
  3. 주문 제안: '장바구니'에서 완료되면 'order' 예약 제안 ~ 사용자가 맞는지 확인할 수 있습니다. 예약이 확인되면 예약 세부정보가 포함된 응답을 받을 수 있습니다.
  4. 주문 완료 및 영수증 보내기 - 주문이 확인되면 영수증을 전송하고 표시됩니다.
  5. 주문 업데이트 전송 - 예약의 수명 동안 PATCH 요청을 전송하여 사용자 예약 상태 업데이트를 Orders API를 참조하세요.

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

거래 및 Orders API를 사용하는 작업에는 추가 정책이 적용됩니다. 거래가 포함된 작업을 검토하는 데 최대 6주가 걸릴 수 있으므로 출시 일정을 계획할 때 이 시간을 고려하세요. 원활한 검토 절차를 위해 작업을 제출하여 검토받기 전에 거래 정책 및 가이드라인을 준수하는지 확인하세요.

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

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

프로젝트 빌드

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

프로젝트 설정

작업을 만들 때 트랜잭션 수행 여부를 지정해야 합니다. Actions 콘솔을 참조하세요. 또한 Node.JS 클라이언트 라이브러리를 사용하여 최신 API v2를 사용하도록 처리를 Orders API 버전입니다.

프로젝트 및 처리를 설정하려면 다음을 수행합니다.

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

  4. Node.JS 클라이언트 라이브러리를 사용하여 작업의 처리를 빌드하는 경우 처리 코드를 열고 앱 선언을 업데이트하여 ordersv3 플래그를 true로 설정합니다. 다음 코드 스니펫은 예시 앱을 보여줍니다. 선언을 사용하세요.

Node.js

const {dialogflow} = require('actions-on-google');
let app = dialogflow({
  clientId, // If using account linking
  debug: true,
  ordersv3: true,
});

Node.js

const {actionssdk} = require('actions-on-google');
let app = actionssdk({
  clientId, // If using account linking
  debug: true,
  ordersv3: true,
});

1. 거래 요건 확인(선택사항)

사용자 환경

사용자가 예약을 원한다고 표시하는 즉시 actions.intent.TRANSACTION_REQUIREMENTS_CHECK 인텐트를 사용하여 예약을 요청할 수도 있습니다 예를 들어 작업이 호출되면 "좌석을 예약하시겠어요?" 사용자가 다음과 같이 말하는 경우 'yes'인 경우 즉시 이 인텐트를 요청해야 합니다. 이렇게 하면 설정을 수정할 수 있는 기회를 제공하고 거래를 계속할 수 없게 합니다.

거래 요청 요구사항은 다음 결과 중 하나로 인텐트 결과를 확인합니다.

  • 요구사항이 충족되면 처리는 다음과 같은 인텐트가 포함된 인텐트를 수신합니다. 성공 조건이 충족되면 사용자의 주문 작성을 진행할 수 있습니다.
  • 요구사항 중 하나 이상이 충족되지 않으면 처리에서 다음을 수신합니다. 인텐트를 반환합니다. 이 경우 대화를 종료하거나 예약 흐름에서 벗어나게 됩니다

    사용자가 오류를 수정할 수 있는 경우 문제를 해결하라는 메시지가 자동으로 표시됩니다. 확인할 수 있습니다. 대화가 음성 전용 환경에서 이루어지는 경우 스마트 스피커처럼 사용자의 휴대전화로 전달됩니다.

처리

사용자가 거래 요구사항, actions.intent.TRANSACTION_REQUIREMENTS_CHECK 인텐트에 TransactionRequirementsCheckSpec 객체를 확인합니다.

요건 확인하기

사용자가 클라이언트 라이브러리의 예약 요구사항을 충족하는지 확인합니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Node.js
conv.ask(new TransactionRequirements());
드림
<ph type="x-smartling-placeholder">
</ph>
자바
return getResponseBuilder(request)
    .add("Placeholder for transaction requirements text")
    .add(new TransactionRequirements())
    .build();
드림
<ph type="x-smartling-placeholder">
</ph>
Dialogflow JSON

아래 JSON은 웹훅 응답을 설명합니다.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
        }
      }
    }
  }
}
드림
<ph type="x-smartling-placeholder">
</ph>
Actions SDK JSON

아래 JSON은 웹훅 응답을 설명합니다.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
          }
        }
      ]
    }
  ]
}
요구사항 확인 결과 수신

어시스턴트는 인텐트를 처리한 후 처리를 통해 요청을 보냅니다. actions.intent.TRANSACTION_REQUIREMENTS_CHECK 인텐트와 결과 포함 확인합니다.

이 요청을 올바르게 처리하려면 다음에서 트리거한 Dialogflow 인텐트를 선언합니다. actions_intent_TRANSACTION_REQUIREMENTS_CHECK 이벤트 트리거되면 처리에서 이 인텐트를 처리해야 합니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Node.js
const arg = conv.arguments.get('TRANSACTION_REQUIREMENTS_CHECK_RESULT');
if (arg && arg.resultType === 'CAN_TRANSACT') {
  // Normally take the user through cart building flow
  conv.ask(`Looks like you're good to go!`);
} else {
  conv.close('Transaction failed.');
}
드림
<ph type="x-smartling-placeholder">
</ph>
자바
Argument transactionCheckResult = request
    .getArgument("TRANSACTION_REQUIREMENTS_CHECK_RESULT");
boolean result = false;
if (transactionCheckResult != null) {
  Map<String, Object> map = transactionCheckResult.getExtension();
  if (map != null) {
    String resultType = (String) map.get("resultType");
    result = resultType != null && resultType.equals("CAN_TRANSACT");
  }
}
ResponseBuilder responseBuilder = getResponseBuilder(request);
if (result) {
  responseBuilder.add("Looks like you're good to go! Now say 'confirm transaction'");
} else {
  responseBuilder.add("Transaction failed");
}
return responseBuilder.build();
드림
<ph type="x-smartling-placeholder">
</ph>
Dialogflow JSON

아래 JSON은 웹훅 요청을 설명합니다.

{
  "responseId": "",
  "queryResult": {
    "queryText": "",
    "action": "",
    "parameters": {},
    "allRequiredParamsPresent": true,
    "fulfillmentText": "",
    "fulfillmentMessages": [],
    "outputContexts": [],
    "intent": {
      "name": "reservation_transaction_check_complete_df",
      "displayName": "reservation_transaction_check_complete_df"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": ""
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          }
        ]
      },
      "inputs": [
        {
          "rawInputs": [],
          "intent": "",
          "arguments": [
            {
              "extension": {
                "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult",
                "resultType": "CAN_TRANSACT"
              },
              "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT"
            }
          ]
        }
      ],
      "user": {},
      "conversation": {},
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "session": ""
}
드림
<ph type="x-smartling-placeholder">
</ph>
Actions SDK JSON

아래 JSON은 웹훅 요청을 설명합니다.

{
  "user": {},
  "device": {},
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      }
    ]
  },
  "conversation": {},
  "inputs": [
    {
      "rawInputs": [],
      "intent": "reservation_transaction_check_complete_asdk",
      "arguments": [
        {
          "extension": {
            "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult",
            "resultType": "CAN_TRANSACT"
          },
          "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT"
        }
      ]
    }
  ],
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

2. 주문 만들기

사용자 환경

필요한 사용자 정보가 있으면 '장바구니'를 만드세요. assembly" 환경을 제공합니다. 매회 작업의 적절한 장바구니 조립 흐름은 있습니다.

기본 장바구니 조립 환경에서 사용자가 추가할 옵션을 목록에서 선택 사용자의 예약에 응하도록 할 수 있지만, 사용자가 편리하게 대화할 수 있도록 있습니다. 예를 들어 고객이 Google 쇼핑에서 사용자가 간단한 예 또는 아니요 질문으로 월간 예약을 예약할 수 있습니다. 사용자에게 '추천' 캐러셀 또는 목록 카드를 표시할 수도 있습니다. 예약할 수 있습니다.

리치 미디어 응답을 사용하여 사용자의 옵션을 표시합니다. 시각적으로도 유용하지만, 사용자가 직접 원하는 내용을 구축할 수 있도록 장바구니를 이용할 수 있습니다. 사용 사례에 대한 권장사항과 예시를 트랜잭션 설계 가이드라인을 참고하세요.

처리

대화 전반에서 사용자가 원하는 예약 세부정보 수집하기 그런 다음 Order 객체를 구성합니다.

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

  • buyerInfo - 예약을 예약하는 사용자에 관한 정보입니다.
  • transactionMerchant - 지원하는 판매자에 대한 정보 지정할 수 있습니다
  • contents - lineItems로 나열된 예약의 실제 세부정보입니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.

Order 응답 문서 참고하기 장바구니를 구성합니다. 다른 필드를 포함해야 할 수도 있습니다. 자동으로 조정됩니다

아래 샘플 코드는 선택 필드를 포함하여 전체 예약 주문을 보여줍니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Node.js
app.intent('build_reservation_df', (conv) => {
  const now = new Date().toISOString();
  const order = {
    createTime: now,
    lastUpdateTime: now,
    merchantOrderId: 'UNIQUE_ORDER_ID',
    userVisibleOrderId: 'USER_VISIBLE_ORDER_ID',
    transactionMerchant: {
      id: 'https://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: 'https://example.com',
        },
      },
      {
        type: 'CALL',
        title: 'Call us',
        openUrlAction: {
          url: 'tel:+16501112222',
        },
      },
      {
        type: 'EMAIL',
        title: 'Email us',
        openUrlAction: {
          url: 'mailto:person@example.com',
        },
      },
    ],
    termsOfServiceUrl: 'https://www.example.com',
  };
드림
<ph type="x-smartling-placeholder">
</ph>
자바
private static OrderV3 createOrder() {
  // Transaction Merchant
  MerchantV3 transactionMerchant = new MerchantV3()
      .setId("http://www.example.com")
      .setName("Example Merchant");

  // Line Item

  // Reservation Item Extension
  ReservationItemExtension reservationItemExtension = new ReservationItemExtension()
      .setStatus("PENDING")
      .setUserVisibleStatusLabel("Reservation pending.")
      .setType("RESTAURANT")
      .setReservationTime(new TimeV3()
          .setTimeIso8601("2020-01-16T01:30:15.01Z"))
      .setUserAcceptableTimeRange(new TimeV3()
          .setTimeIso8601("2020-01-15/2020-01-17"))
      .setPartySize(6)
      .setStaffFacilitators(Collections.singletonList(new StaffFacilitator()
          .setName("John Smith")))
      .setLocation(new Location()
          .setZipCode("94086")
          .setCity("Sunnyvale")
          .setPostalAddress(new PostalAddress()
              .setRegionCode("US")
              .setPostalCode("94086")
              .setAdministrativeArea("CA")
              .setLocality("Sunnyvale")
              .setAddressLines(
                  Collections.singletonList("222, Some other Street"))));

  LineItemV3 lineItem = new LineItemV3()
      .setId("LINE_ITEM_ID")
      .setName("Dinner reservation")
      .setDescription("A world of flavors all in one destination.")
      .setReservation(reservationItemExtension);

  // Order Contents
  OrderContents contents = new OrderContents()
      .setLineItems(Collections.singletonList(lineItem));

  // User Info
  UserInfo buyerInfo = new UserInfo()
      .setEmail("janedoe@gmail.com")
      .setFirstName("Jane")
      .setLastName("Doe")
      .setDisplayName("Jane Doe");

  // Follow up actions
  Action viewDetails = new Action()
      .setType("VIEW_DETAILS")
      .setTitle("View details")
      .setOpenUrlAction(new OpenUrlAction()
          .setUrl("https://example.com"));

  Action call = new Action()
      .setType("CALL")
      .setTitle("Call us")
      .setOpenUrlAction(new OpenUrlAction()
          .setUrl("tel:+16501112222"));

  Action email = new Action()
      .setType("EMAIL")
      .setTitle("Email us")
      .setOpenUrlAction(new OpenUrlAction()
          .setUrl("mailto:person@example.com"));

  // Terms of service and order note
  String termsOfServiceUrl = "https://example.com";

  String now = Instant.now().toString();

  OrderV3 order = new OrderV3()
      .setCreateTime(now)
      .setLastUpdateTime(now)
      .setMerchantOrderId("UNIQUE_ORDER_ID")
      .setUserVisibleOrderId("UNIQUE_USER_VISIBLE_ORDER_ID")
      .setTransactionMerchant(transactionMerchant)
      .setContents(contents)
      .setBuyerInfo(buyerInfo)
      .setFollowUpActions(Arrays.asList(
          viewDetails,
          call,
          email
      ))
      .setTermsOfServiceUrl(termsOfServiceUrl);

  return order;
}
드림
<ph type="x-smartling-placeholder">
</ph>
JSON

아래 JSON은 웹훅 응답을 설명합니다.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
          "order": {
            "createTime": "2019-07-17T18:25:30.182Z",
            "lastUpdateTime": "2019-07-17T18:25:30.182Z",
            "merchantOrderId": "UNIQUE_ORDER_ID",
            "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
            "transactionMerchant": {
              "id": "https://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": "https://example.com"
                }
              },
              {
                "type": "CALL",
                "title": "Call us",
                "openUrlAction": {
                  "url": "tel:+16501112222"
                }
              },
              {
                "type": "EMAIL",
                "title": "Email us",
                "openUrlAction": {
                  "url": "mailto:person@example.com"
                }
              }
            ],
            "termsOfServiceUrl": "https://www.example.com"
          },
          "orderOptions": {
            "requestDeliveryAddress": false,
            "userInfoOptions": {
              "userInfoProperties": [
                "EMAIL"
              ]
            }
          },
          "presentationOptions": {
            "actionDisplayName": "RESERVE"
          }
        }
      }
    }
  }
}

3. 주문 제안

사용자가 확인할 수 있도록 예약 주문을 사용자에게 제시합니다. 거부합니다. actions.intent.TRANSACTION_DECISION 요청 인텐트를 호출하고 개발자가 빌드한 Order를 제공해야 합니다.

사용자 환경

actions.intent.TRANSACTION_DECISION 인텐트를 요청하면 어시스턴트는 Order가 다음과 같은 내장된 환경을 시작합니다. '장바구니 미리보기 카드'에 직접 렌더링됩니다. 사용자가 "예약 예약해 줘"라고 말하면 거래를 거부하거나 예약 세부정보 변경을 요청할 수 없습니다.

이 시점에서 사용자가 주문 변경을 요청할 수도 있습니다. 이 경우 처리에서 주문 변경 요청을 처리할 수 있는지 마무리하는 단계입니다

처리

귀하가 actions.intent.TRANSACTION_DECISION 인텐트가 포함된 경우 Order가 포함된 TransactionDecisionorderOptions

다음 코드는 주문의 TransactionsDecision 예를 보여줍니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Node.js
conv.ask(new TransactionDecision({
  orderOptions: {
    requestDeliveryAddress: 'false',
  },
  presentationOptions: {
    actionDisplayName: 'RESERVE',
  },
  order: order,
}));
드림
<ph type="x-smartling-placeholder">
</ph>
자바
// Create order options
OrderOptionsV3 orderOptions = new OrderOptionsV3()
    .setRequestDeliveryAddress(false)
    .setUserInfoOptions(new UserInfoOptions()
        .setUserInfoProperties(Collections.singletonList("EMAIL")));

// Create presentation options
PresentationOptionsV3 presentationOptions = new PresentationOptionsV3()
    .setActionDisplayName("RESERVE");

// Ask for transaction decision
return getResponseBuilder(request)
    .add("Placeholder for transaction decision text")
    .add(new TransactionDecision()
        .setOrder(order)
        .setOrderOptions(orderOptions)
        .setPresentationOptions(presentationOptions)
    )
    .build();
드림
<ph type="x-smartling-placeholder">
</ph>
Dialogflow JSON

아래 JSON은 웹훅 응답을 설명합니다.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
          "orderOptions": {
            "requestDeliveryAddress": "false"
          },
          "presentationOptions": {
            "actionDisplayName": "RESERVE"
          },
          "order": {
            "createTime": "2019-07-17T18:25:30.184Z",
            "lastUpdateTime": "2019-07-17T18:25:30.184Z",
            "merchantOrderId": "UNIQUE_ORDER_ID",
            "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
            "transactionMerchant": {
              "id": "https://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": "https://example.com"
                }
              },
              {
                "type": "CALL",
                "title": "Call us",
                "openUrlAction": {
                  "url": "tel:+16501112222"
                }
              },
              {
                "type": "EMAIL",
                "title": "Email us",
                "openUrlAction": {
                  "url": "mailto:person@example.com"
                }
              }
            ],
            "termsOfServiceUrl": "https://www.example.com"
          }
        }
      }
    }
  }
}
드림
<ph type="x-smartling-placeholder">
</ph>
Actions SDK JSON

아래 JSON은 웹훅 응답을 설명합니다.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_DECISION",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
            "orderOptions": {
              "requestDeliveryAddress": "false"
            },
            "presentationOptions": {
              "actionDisplayName": "RESERVE"
            },
            "order": {
              "createTime": "2019-07-17T18:25:30.057Z",
              "lastUpdateTime": "2019-07-17T18:25:30.057Z",
              "merchantOrderId": "UNIQUE_ORDER_ID",
              "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
              "transactionMerchant": {
                "id": "https://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": "https://example.com"
                  }
                },
                {
                  "type": "CALL",
                  "title": "Call us",
                  "openUrlAction": {
                    "url": "tel:+16501112222"
                  }
                },
                {
                  "type": "EMAIL",
                  "title": "Email us",
                  "openUrlAction": {
                    "url": "mailto:person@example.com"
                  }
                }
              ],
              "termsOfServiceUrl": "https://www.example.com"
            }
          }
        }
      ]
    }
  ]
}
사용자 결정 처리

사용자가 제안된 주문에 응답하면 주문 처리에서는 다음을 포함하는 인수가 있는 actions_intent_TRANSACTION_DECISION 인텐트 TransactionDecisionValue입니다. 이 값에는 다음이 포함됩니다.

  • transactionDecision - 제안된 광고에 대한 사용자의 결정 있습니다. 가능한 값은 ORDER_ACCEPTED, ORDER_REJECTED, CART_CHANGE_REQUESTED, USER_CANNOT_TRANSACT

이 요청을 처리하려면 다음에서 트리거한 Dialogflow 인텐트를 선언합니다. actions_intent_TRANSACTION_DECISION 이벤트 이 인텐트를 다음에서 처리 다음과 같습니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Node.js
const arg = conv.arguments.get('TRANSACTION_DECISION_VALUE');
if (arg && arg.transactionDecision === 'ORDER_ACCEPTED') {
  console.log('order accepted');
  const order = arg.order;
}
드림
<ph type="x-smartling-placeholder">
</ph>
자바
Argument transactionDecisionValue = request
    .getArgument("TRANSACTION_DECISION_VALUE");
Map<String, Object> extension = null;
if (transactionDecisionValue != null) {
  extension = transactionDecisionValue.getExtension();
}

String transactionDecision = null;
if (extension != null) {
  transactionDecision = (String) extension.get("transactionDecision");
}
if ((transactionDecision != null && transactionDecision.equals("ORDER_ACCEPTED"))) {
  OrderV3 order = ((OrderV3) extension.get("order"));
}
드림
<ph type="x-smartling-placeholder">
</ph>
Dialogflow JSON

아래 JSON은 웹훅 요청을 설명합니다.

{
  "responseId": "",
  "queryResult": {
    "queryText": "",
    "action": "",
    "parameters": {},
    "allRequiredParamsPresent": true,
    "fulfillmentText": "",
    "fulfillmentMessages": [],
    "outputContexts": [],
    "intent": {
      "name": "reservation_get_transaction_decision_df",
      "displayName": "reservation_get_transaction_decision_df"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": ""
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          }
        ]
      },
      "inputs": [
        {
          "rawInputs": [],
          "intent": "",
          "arguments": []
        }
      ],
      "user": {},
      "conversation": {},
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "session": ""
}
드림
<ph type="x-smartling-placeholder">
</ph>
Actions SDK JSON

아래 JSON은 웹훅 요청을 설명합니다.

{
  "user": {},
  "device": {},
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      }
    ]
  },
  "conversation": {},
  "inputs": [
    {
      "rawInputs": [],
      "intent": "reservation_get_transaction_decision_asdk",
      "arguments": []
    }
  ],
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

4. 예약 완료 및 영수증 보내기

actions.intent.TRANSACTION_DECISION 인텐트가 transactionDecision ORDER_ACCEPTED에서 원하는 값을 예약 실행 (예: 예약 데이터 세트)을 자체 데이터베이스)

간단한 응답 보내기 대화를 이어 나가세요 사용자에게 '접힌 영수증 카드'가 표시됨 답변도 함께 첨부합니다

처리

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Node.js
// Set lastUpdateTime and update status of reservation
order.lastUpdateTime = new Date().toISOString();
order.reservation.status = 'CONFIRMED';
order.reservation.userVisibleStatusLabel = 'Reservation confirmed';
order.reservation.confirmationCode = '123ABCDEFGXYZ';

// Send synchronous order update
conv.ask(`Transaction completed! You're all set!`);
conv.ask(new OrderUpdate({
  type: 'SNAPSHOT',
  reason: 'Reason string',
  order: order,
}));
드림
<ph type="x-smartling-placeholder">
</ph>
자바
ResponseBuilder responseBuilder = getResponseBuilder(request);
order.setLastUpdateTime(Instant.now().toString());

// Set reservation status to confirmed and provide confirmation code
LineItemV3 lineItem = order.getContents().getLineItems().get(0);
ReservationItemExtension reservationItemExtension = lineItem.getReservation();
reservationItemExtension.setStatus("CONFIRMED");
reservationItemExtension.setUserVisibleStatusLabel("Reservation confirmed.");
reservationItemExtension.setConfirmationCode("123ABCDEFGXYZ");
lineItem.setReservation(reservationItemExtension);
order.getContents().getLineItems().set(0, lineItem);

// Order update
OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setType("SNAPSHOT")
    .setReason("Reason string")
    .setOrder(order);

responseBuilder
    .add("Transaction completed! You're all set! Would you like to do anything else?")
    .add(new StructuredResponse().setOrderUpdateV3(orderUpdate));
return responseBuilder.build();
드림
<ph type="x-smartling-placeholder">
</ph>
Dialogflow JSON

아래 JSON은 웹훅 응답을 설명합니다.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "richResponse": {
        "items": [
          {
            "simpleResponse": {
              "textToSpeech": "Transaction completed! You're all set!"
            }
          },
          {
            "structuredResponse": {
              "orderUpdateV3": {
                "type": "SNAPSHOT",
                "reason": "Reason string",
                "order": {
                  "merchantOrderId": "UNIQUE_ORDER_ID",
                  "reservation": {
                    "status": "CONFIRMED",
                    "userVisibleStatusLabel": "Reservation confirmed",
                    "confirmationCode": "123ABCDEFGXYZ"
                  },
                  "lastUpdateTime": "2019-07-17T18:25:30.187Z"
                }
              }
            }
          }
        ]
      }
    }
  }
}
드림
<ph type="x-smartling-placeholder">
</ph>
Actions SDK JSON

아래 JSON은 웹훅 응답을 설명합니다.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TEXT"
        }
      ],
      "inputPrompt": {
        "richInitialPrompt": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "Transaction completed! You're all set!"
              }
            },
            {
              "structuredResponse": {
                "orderUpdateV3": {
                  "type": "SNAPSHOT",
                  "reason": "Reason string",
                  "order": {
                    "merchantOrderId": "UNIQUE_ORDER_ID",
                    "reservation": {
                      "status": "CONFIRMED",
                      "userVisibleStatusLabel": "Reservation confirmed",
                      "confirmationCode": "123ABCDEFGXYZ"
                    },
                    "lastUpdateTime": "2019-07-17T18:25:30.059Z"
                  }
                }
              }
            }
          ]
        }
      }
    }
  ]
}

5. 주문 업데이트 보내기

예약 상태는 변경할 수 있습니다 HTTP로 사용자에게 예약 주문 업데이트 전송 주문 상태 및 세부정보가 포함된 Orders API에 대한 PATCH 요청입니다.

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

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

서비스 계정 키를 가져오려면 다음 단계를 수행합니다.

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

주문 업데이트 코드에서 서비스 키를 Bearer 토큰으로 교환 Google API 클라이언트 라이브러리 및 &quot;https://www.googleapis.com/auth/actions.order.developer&quot; 범위 사용 설치 단계와 API 클라이언트 라이브러리 GitHub 페이지의 예시

다음에 대한 Node.jsJava 샘플에서 order-update.js를 참조합니다. 예시 키 교환입니다

주문 업데이트 보내기

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

Orders API URL: <ph type="x-smartling-placeholder"> PATCH https://actions.googleapis.com/v3/orders/${orderId} </ph>

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

  • "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 - 다음을 포함하는 객체입니다. <ph type="x-smartling-placeholder">
        </ph>
      • status - 주문의 상태(ReservationStatus)입니다. 예: 'CONFIRMED' 또는 'CANCELLED'.
      • userVisibleStatusLabel - 다음에 관한 세부정보를 제공하는 사용자 대상 라벨입니다. 주문 상태(예: '예약이 확인되었습니다')
  • userNotification (선택사항) - userNotification 이 업데이트가 전송될 때 사용자 기기에 표시될 수 있는 객체입니다. 참고 이 객체를 포함한다고 해서 알림이 반드시 사용자의 기기에서 시작됩니다.

다음 샘플 코드는 OrderUpdate FULFILLED에 예약 주문 상태를 전송합니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Node.js
// Import the 'googleapis' module for authorizing the request.
const {google} = require('googleapis');
// Import the 'request' module for sending an HTTP POST request.
const request = require('request');
// Import the OrderUpdate class from the Actions on Google client library.
const {OrderUpdate} = require('actions-on-google');
// Import the service account key used to authorize the request. Replace the string path with a path to your service account key.
const key = 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(
    key.client_email,
    null,
    key.private_key,
    ['https://www.googleapis.com/auth/actions.order.developer'],
    null
);
// Authorize the client asynchronously, passing in a callback to run upon authorization.
jwtClient.authorize((err, tokens) => {
    if (err) {
        console.log(err);
        return;
    }
    // Declare the ID of the order to update.
    const orderId = '<UNIQUE_MERCHANT_ORDER_ID>';

    const orderUpdateJson = new OrderUpdate({
        updateMask: [
          'lastUpdateTime',
          'contents.lineItems.reservation.status',
          'contents.lineItems.reservation.userVisibleStatusLabel',
      ].join(','),
        order: {
          merchantOrderId: orderId,
          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.
    const bearer = 'Bearer ' + tokens.access_token;
    const options = {
        method: 'PATCH',
        url: `https://actions.googleapis.com/v3/orders/${orderId}`,
        headers: {
          'Authorization': bearer,
        },
        body: {
          header: {
            'isInSandbox': true,
          },
          orderUpdate: orderUpdateJson,
        },
        json: true,
      };
    // Send the PATCH request to the Orders API.
    request.patch(options, (err, httpResponse, body) => {
        if (err) {
            console.log('There was an error...');
            console.log(err);
            return;
        }
    });
});
드림
<ph type="x-smartling-placeholder">
</ph>
자바
// Create order update
FieldMask fieldMask = FieldMask.newBuilder().addAllPaths(Arrays.asList(
    "lastUpdateTime",
    "contents.lineItems.reservation.status",
    "contents.lineItems.reservation.userVisibleStatusLabel"))
    .build();

OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setOrder(new OrderV3()
        .setMerchantOrderId(orderId)
        .setLastUpdateTime(Instant.now().toString())
        .setContents(new OrderContents()
        .setLineItems(Collections.singletonList(new LineItemV3()
            .setReservation(new ReservationItemExtension()
                .setStatus("FULFILLED")
                .setUserVisibleStatusLabel("Reservation fulfilled."))))))
    .setUpdateMask(FieldMaskUtil.toString(fieldMask))
    .setReason("Reservation status was updated to fulfilled.");

// Setup JSON body containing order update
JsonParser parser = new JsonParser();
JsonObject orderUpdateJson =
    parser.parse(new Gson().toJson(orderUpdate)).getAsJsonObject();
JsonObject body = new JsonObject();
body.add("orderUpdate", orderUpdateJson);
JsonObject header = new JsonObject();
header.addProperty("isInSandbox", true);
body.add("header", header);
StringEntity entity = new StringEntity(body.toString());
entity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
request.setEntity(entity);

// Make request
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse response = httpClient.execute(request);
예약 상태 설정

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

  • PENDING - 예약이 '생성'되었습니다. 사용자의 작업 또는 백엔드에서 추가 처리를 거쳐야 합니다
  • CONFIRMED: 일정 백엔드에서 예약이 확인되었습니다.
  • CANCELLED - 사용자가 예약을 취소했습니다.
  • FULFILLED - 서비스에서 사용자의 예약을 처리했습니다.
  • CHANGE_REQUESTED - 사용자가 예약 변경을 요청했으며 변경이 다음과 같음 있습니다.
  • REJECTED - 처리할 수 없거나 기타 방법으로 처리할 수 없는 경우 예약을 확인합니다

판매자와 관련된 각 상태에 대한 주문 업데이트를 예약입니다. 예를 들어 예약에 수동 처리가 필요한 경우 요청한 다음 예약을 확인하고, 다음 시점까지 PENDING 주문 업데이트를 전송합니다. 추가 처리가 이루어집니다. 모든 예약에 모든 상태 값이 필요한 것은 아닙니다.

문제 해결

테스트 중에 문제가 발생하면 문제 해결 단계를 참고하세요. 100% 업타임 체크를 제공합니다