用于针对账号问题触发操作的 Merchant API 代码示例
Java
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shopping.merchant.samples.issueresolution.v1beta;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.issueresolution.v1beta.AccountName;
import com.google.shopping.merchant.issueresolution.v1beta.Action;
import com.google.shopping.merchant.issueresolution.v1beta.ActionFlow;
import com.google.shopping.merchant.issueresolution.v1beta.ActionInput;
import com.google.shopping.merchant.issueresolution.v1beta.BuiltInUserInputAction;
import com.google.shopping.merchant.issueresolution.v1beta.InputField;
import com.google.shopping.merchant.issueresolution.v1beta.InputField.ChoiceInput;
import com.google.shopping.merchant.issueresolution.v1beta.InputField.ChoiceInput.ChoiceInputOption;
import com.google.shopping.merchant.issueresolution.v1beta.InputValue;
import com.google.shopping.merchant.issueresolution.v1beta.InputValue.CheckboxInputValue;
import com.google.shopping.merchant.issueresolution.v1beta.InputValue.ChoiceInputValue;
import com.google.shopping.merchant.issueresolution.v1beta.InputValue.TextInputValue;
import com.google.shopping.merchant.issueresolution.v1beta.IssueResolutionServiceClient;
import com.google.shopping.merchant.issueresolution.v1beta.IssueResolutionServiceSettings;
import com.google.shopping.merchant.issueresolution.v1beta.RenderAccountIssuesRequest;
import com.google.shopping.merchant.issueresolution.v1beta.RenderAccountIssuesResponse;
import com.google.shopping.merchant.issueresolution.v1beta.RenderIssuesRequestPayload;
import com.google.shopping.merchant.issueresolution.v1beta.RenderedIssue;
import com.google.shopping.merchant.issueresolution.v1beta.TriggerActionPayload;
import com.google.shopping.merchant.issueresolution.v1beta.TriggerActionRequest;
import com.google.shopping.merchant.issueresolution.v1beta.TriggerActionResponse;
import com.google.shopping.merchant.issueresolution.v1beta.UserInputActionRenderingOption;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;
/**
* This class demonstrates how to trigger an action on account-level issues for a given Merchant
* Center account.
*
* <p>The example first calls the `renderAccountIssues` to obtain live issues for the account. The
* user can select the issue, they want to trigger an action for. The program will ask them to
* provide all required user input, specific for the selected action. Once the input is collected,
* the program build the request and calls the `triggerAction`
*
* <p>NOTE: the access to `triggerAction` is currently limited. To obtain access follow steps in the
* development guide.
*/
public class TriggerActionForAccountIssueSample {
private static void renderAccountIssuesAndTriggerAction(
Config config,
String languageCode,
String timeZone,
UserInputActionRenderingOption userInputActionOption,
Scanner scanner)
throws IOException {
// Obtains OAuth token based on the user's configuration.
GoogleCredentials credential = new Authenticator().authenticate();
IssueResolutionServiceSettings settings =
IssueResolutionServiceSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credential))
.build();
String accountId = config.getAccountId().toString();
String name = AccountName.newBuilder().setAccount(accountId).build().toString();
try (IssueResolutionServiceClient client = IssueResolutionServiceClient.create(settings)) {
// First, we call the `renderAccountIssues` to obtain live issues for the account. The
// `userInputActionOption` specifies how the complex Built-In actions should be rendered. For
// this example, the option is set to `REDIRECT_TO_MERCHANT_CENTER`, so the
// complex actions will be rendered as `BuiltInUserInputAction` that can be started by calling
// the `triggerAction` method.
RenderAccountIssuesRequest request =
RenderAccountIssuesRequest.newBuilder()
.setName(name)
.setLanguageCode(languageCode)
.setTimeZone(timeZone)
.setPayload(
RenderIssuesRequestPayload.newBuilder()
.setUserInputActionOption(userInputActionOption)
.build())
.build();
System.out.println("Sending RenderAccountIssues request");
RenderAccountIssuesResponse response = client.renderAccountIssues(request);
System.out.println("The full response:");
System.out.println(response);
System.out.println("-----------------------------------------------------------------");
System.out.println("Summary: ");
System.out.println(response.getRenderedIssuesCount() + " issues found for the account");
// Filter all issues that have at least one action that is available and has a built-in user
// input action.
List<RenderedIssue> issuesWithTriggerableAction =
response.getRenderedIssuesList().stream()
.filter(
issue ->
issue.getActionsList().stream()
.anyMatch(
action ->
action.getIsAvailable() && action.hasBuiltinUserInputAction()))
.collect(Collectors.toList());
if (issuesWithTriggerableAction.isEmpty()) {
System.out.println("There is currently no issue that has a triggerable action");
return; // Early exit as there is no action to be triggered.
}
System.out.println(
issuesWithTriggerableAction.size()
+ " issues have an action that could be started with the `triggerAction` method:");
// The user should select the issue for which they will trigger an action
for (int i = 0; i < issuesWithTriggerableAction.size(); i++) {
System.out.println(" [" + i + "] " + issuesWithTriggerableAction.get(i).getTitle());
}
int selectedIssueId =
requestUserInputAsNumber(0, issuesWithTriggerableAction.size() - 1, "issue", scanner);
RenderedIssue issue = issuesWithTriggerableAction.get(selectedIssueId);
System.out.println("You selected '" + issue.getTitle() + "' issue.");
List<Action> actions =
issue.getActionsList().stream()
.filter(it -> it.getIsAvailable() && it.hasBuiltinUserInputAction())
.collect(Collectors.toList());
// There could be multiple actions that can be triggered for a given issue. The user should
// select the action they want to trigger.
Action action;
if (actions.size() == 1) {
action = actions.get(0);
System.out.println(
"There is only one action '" + action.getButtonLabel() + "' that can be triggered.");
} else {
for (int i = 0; i < actions.size(); i++) {
System.out.println(" [" + i + "] " + actions.get(i).getButtonLabel());
}
int selectedActionId = requestUserInputAsNumber(0, actions.size() - 1, "action", scanner);
action = actions.get(selectedActionId);
System.out.println("You selected '" + action.getButtonLabel() + "' action.");
}
BuiltInUserInputAction triggerableAction = action.getBuiltinUserInputAction();
// There could be multiple action flows for a given action. The user should select the
// specific action flow they want to trigger.
ActionFlow actionFlow;
if (triggerableAction.getFlowsList().size() > 1) {
System.out.println(
"For the '"
+ action.getButtonLabel()
+ "' there are "
+ triggerableAction.getFlowsCount()
+ " flows available:");
for (int i = 0; i < triggerableAction.getFlowsCount(); i++) {
System.out.println(" [" + i + "] " + triggerableAction.getFlowsList().get(i).getLabel());
}
int selectedFlowId =
requestUserInputAsNumber(0, triggerableAction.getFlowsCount() - 1, "flow", scanner);
actionFlow = triggerableAction.getFlows(selectedFlowId);
System.out.println("You selected '" + actionFlow.getLabel() + "' flow");
} else {
actionFlow = triggerableAction.getFlowsList().get(0);
}
// For each flow, additional content needs to be shown to the user. There should be a dialog
// with user input form and additional content. The content is defined by the
// `dialog_title`, `dialog_callout` and `dialog_message` fields.
System.out.println();
System.out.println("Additional content to display to the merchant (as a dialog):");
System.out.println(actionFlow.getDialogTitle());
if (actionFlow.hasDialogCallout()) {
System.out.println(actionFlow.getDialogCallout().getFullMessage().getSimpleValue());
}
System.out.println(actionFlow.getDialogMessage().getSimpleValue());
// Collect user input values, that may be required to trigger the action (flow). This would be
// displayed as a form to the user.
List<InputValue> inputValues = new ArrayList<>();
if (actionFlow.getInputsCount() > 0) {
System.out.println();
System.out.println("User input form:");
for (InputField field : actionFlow.getInputsList()) {
System.out.print("field [" + field.getId() + "]: " + field.getLabel().getSimpleValue());
if (field.getRequired()) {
System.out.print(" (required)");
}
// checkbox field
if (field.hasCheckboxInput()) {
// The user should confirm the checkbox.
System.out.println(" [checkbox]");
System.out.print(" Enter 'true' to confirm: ");
String input = scanner.nextLine();
if ("true".equals(input.toLowerCase())) {
inputValues.add(
InputValue.newBuilder()
.setInputFieldId(field.getId())
.setCheckboxInputValue(CheckboxInputValue.newBuilder().setValue(true).build())
.build());
} else {
System.out.println("Wrong value");
if (field.getRequired()) {
System.out.println("The action can not be triggered without a required value");
return;
}
}
// select field
} else if (field.hasChoiceInput()) {
// For the ChoiceInput, there are multiple predefined options. The user should select
// one of the predefined options.
System.out.println(" [select]");
ChoiceInput choiceInput = field.getChoiceInput();
for (int i = 0; i < choiceInput.getOptionsCount(); i++) {
System.out.println(
" ["
+ i
+ "] "
+ choiceInput.getOptions(i).getLabel().getSimpleValue()
+ " ["
+ choiceInput.getOptions(i).getId()
+ "]");
}
int selectedOptionId =
requestUserInputAsNumber(0, choiceInput.getOptionsCount() - 1, "option", scanner);
ChoiceInputOption selectedOption = choiceInput.getOptions(selectedOptionId);
System.out.println("You selected '" + selectedOption.getLabel().getSimpleValue() + "'");
inputValues.add(
InputValue.newBuilder()
.setInputFieldId(field.getId())
.setChoiceInputValue(
ChoiceInputValue.newBuilder()
.setChoiceInputOptionId(selectedOption.getId())
.build())
.build());
// text input field
} else if (field.hasTextInput()) {
// For the TextInput, the user should enter the text.
System.out.println(" [text]");
System.out.print(" Enter the text: ");
String input = scanner.nextLine();
inputValues.add(
InputValue.newBuilder()
.setInputFieldId(field.getId())
.setTextInputValue(TextInputValue.newBuilder().setValue(input).build())
.build());
}
System.out.println();
}
}
// Build the request to trigger the action.
TriggerActionRequest triggerActionRequest =
TriggerActionRequest.newBuilder()
.setLanguageCode(languageCode)
.setName(name)
.setPayload(
TriggerActionPayload.newBuilder()
// set the action context for selected action
.setActionContext(triggerableAction.getActionContext())
// set the action inputs
.setActionInput(
ActionInput.newBuilder()
// set the FlowId for the selected action flow
.setActionFlowId(actionFlow.getId())
// set user input for all (required) user input fields
.addAllInputValues(inputValues)
.build())
.build())
.build();
System.out.println("-----------------------------------------------------------------");
System.out.println("Calling `triggerAction` with request: ");
System.out.println(triggerActionRequest);
TriggerActionResponse triggerActionResponse = client.triggerAction(triggerActionRequest);
System.out.println("The full response:");
System.out.println(triggerActionResponse);
} catch (Exception e) {
System.out.println("An error has occured: ");
System.out.println(e);
if (e.getMessage()
.contains(
"PERMISSION_DENIED: This API endpoint is not enabled for your cloud project id.")) {
System.out.println("The access to the `triggerAction` method is currently limited.");
System.out.println(
"To get the access, you need to first, submit a request. A link to the form can be"
+ " found in the development guide");
}
}
}
private static int requestUserInputAsNumber(int min, int max, String itemName, Scanner scanner) {
while (true) {
System.out.print(
"Enter a number from <" + min + "-" + max + "> to select the " + itemName + ": ");
try {
int value = scanner.nextInt();
if (value >= min && value <= max) {
scanner.nextLine();
return value;
} else {
System.out.println("Invalid input.");
}
} catch (java.util.InputMismatchException e) {
System.out.println("Invalid input. Please enter a valid number.");
scanner.nextLine(); // Clear the invalid input from the scanner
}
}
}
public static void main(String[] args) throws Exception {
Config config = Config.load();
String timeZone = "Europe/Zurich";
String languageCode = "en_GB";
// To implement complex troubleshooting actions directly in your app,
// the RenderAccountIssuesRequest must have set the `userInputActionOption` as
// `BUILT_IN_USER_INPUT_ACTIONS`. Otherwise, these actions would be handled as redirects to
// the Merchant Center (by default).
UserInputActionRenderingOption inputActionOption =
UserInputActionRenderingOption.BUILT_IN_USER_INPUT_ACTIONS;
try (Scanner scanner = new Scanner(System.in)) {
renderAccountIssuesAndTriggerAction(
config, languageCode, timeZone, inputActionOption, scanner);
}
}
}