// Copyright 2021 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
//
//     http://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.

syntax = "proto3";

package google.cloud.retail.v2beta;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/retail/v2beta/export_config.proto";
import "google/cloud/retail/v2beta/import_config.proto";
import "google/cloud/retail/v2beta/product.proto";
import "google/cloud/retail/v2beta/purge_config.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.Retail.V2Beta";
option go_package = "google.golang.org/genproto/googleapis/cloud/retail/v2beta;retail";
option java_multiple_files = true;
option java_outer_classname = "ProductServiceProto";
option java_package = "com.google.cloud.retail.v2beta";
option objc_class_prefix = "RETAIL";
option php_namespace = "Google\\Cloud\\Retail\\V2beta";
option ruby_package = "Google::Cloud::Retail::V2beta";

// Service for ingesting [Product][google.cloud.retail.v2beta.Product]
// information of the customer's website.
service ProductService {
  option (google.api.default_host) = "retail.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Creates a [Product][google.cloud.retail.v2beta.Product].
  rpc CreateProduct(CreateProductRequest) returns (Product) {
    option (google.api.http) = {
      post: "/v2beta/{parent=projects/*/locations/*/catalogs/*/branches/*}/products"
      body: "product"
    };
    option (google.api.method_signature) = "parent,product,product_id";
  }

  // Gets a [Product][google.cloud.retail.v2beta.Product].
  rpc GetProduct(GetProductRequest) returns (Product) {
    option (google.api.http) = {
      get: "/v2beta/{name=projects/*/locations/*/catalogs/*/branches/*/products/**}"
    };
    option (google.api.method_signature) = "name";
  }

  // Gets a list of [Product][google.cloud.retail.v2beta.Product]s.
  rpc ListProducts(ListProductsRequest) returns (ListProductsResponse) {
    option (google.api.http) = {
      get: "/v2beta/{parent=projects/*/locations/*/catalogs/*/branches/*}/products"
    };
    option (google.api.method_signature) = "parent";
  }

  // Updates a [Product][google.cloud.retail.v2beta.Product].
  rpc UpdateProduct(UpdateProductRequest) returns (Product) {
    option (google.api.http) = {
      patch: "/v2beta/{product.name=projects/*/locations/*/catalogs/*/branches/*/products/**}"
      body: "product"
    };
    option (google.api.method_signature) = "product,update_mask";
  }

  // Deletes a [Product][google.cloud.retail.v2beta.Product].
  rpc DeleteProduct(DeleteProductRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v2beta/{name=projects/*/locations/*/catalogs/*/branches/*/products/**}"
    };
    option (google.api.method_signature) = "name";
  }

  // Bulk import of multiple [Product][google.cloud.retail.v2beta.Product]s.
  //
  // Request processing may be synchronous. No partial updating is supported.
  // Non-existing items are created.
  //
  // Note that it is possible for a subset of the
  // [Product][google.cloud.retail.v2beta.Product]s to be successfully updated.
  rpc ImportProducts(ImportProductsRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v2beta/{parent=projects/*/locations/*/catalogs/*/branches/*}/products:import"
      body: "*"
    };
    option (google.longrunning.operation_info) = {
      response_type: "google.cloud.retail.v2beta.ImportProductsResponse"
      metadata_type: "google.cloud.retail.v2beta.ImportMetadata"
    };
  }

  // Updates inventory information for a
  // [Product][google.cloud.retail.v2beta.Product] while respecting the last
  // update timestamps of each inventory field.
  //
  // This process is asynchronous and does not require the
  // [Product][google.cloud.retail.v2beta.Product] to exist before updating
  // fulfillment information. If the request is valid, the update will be
  // enqueued and processed downstream. As a consequence, when a response is
  // returned, updates are not immediately manifested in the
  // [Product][google.cloud.retail.v2beta.Product] queried by
  // [GetProduct][google.cloud.retail.v2beta.ProductService.GetProduct] or
  // [ListProducts][google.cloud.retail.v2beta.ProductService.ListProducts].
  //
  // When inventory is updated with
  // [CreateProduct][google.cloud.retail.v2beta.ProductService.CreateProduct]
  // and
  // [UpdateProduct][google.cloud.retail.v2beta.ProductService.UpdateProduct],
  // the specified inventory field value(s) will overwrite any existing value(s)
  // while ignoring the last update time for this field. Furthermore, the last
  // update time for the specified inventory fields will be overwritten to the
  // time of the
  // [CreateProduct][google.cloud.retail.v2beta.ProductService.CreateProduct] or
  // [UpdateProduct][google.cloud.retail.v2beta.ProductService.UpdateProduct]
  // request.
  //
  // If no inventory fields are set in
  // [CreateProductRequest.product][google.cloud.retail.v2beta.CreateProductRequest.product],
  // then any pre-existing inventory information for this product will be used.
  //
  // If no inventory fields are set in [UpdateProductRequest.set_mask][],
  // then any existing inventory information will be preserved.
  //
  // Pre-existing inventory information can only be updated with
  // [SetInventory][google.cloud.retail.v2beta.ProductService.SetInventory],
  // [AddFulfillmentPlaces][google.cloud.retail.v2beta.ProductService.AddFulfillmentPlaces],
  // and
  // [RemoveFulfillmentPlaces][google.cloud.retail.v2beta.ProductService.RemoveFulfillmentPlaces].
  //
  // This feature is only available for users who have Retail Search enabled.
  // Contact Retail Support (retail-search-support@google.com) if you are
  // interested in using Retail Search.
  rpc SetInventory(SetInventoryRequest) returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v2beta/{inventory.name=projects/*/locations/*/catalogs/*/branches/*/products/**}:setInventory"
      body: "*"
    };
    option (google.api.method_signature) = "inventory,set_mask";
    option (google.longrunning.operation_info) = {
      response_type: "google.cloud.retail.v2beta.SetInventoryResponse"
      metadata_type: "google.cloud.retail.v2beta.SetInventoryMetadata"
    };
  }

  // Incrementally adds place IDs to
  // [Product.fulfillment_info.place_ids][google.cloud.retail.v2beta.FulfillmentInfo.place_ids].
  //
  // This process is asynchronous and does not require the
  // [Product][google.cloud.retail.v2beta.Product] to exist before updating
  // fulfillment information. If the request is valid, the update will be
  // enqueued and processed downstream. As a consequence, when a response is
  // returned, the added place IDs are not immediately manifested in the
  // [Product][google.cloud.retail.v2beta.Product] queried by
  // [GetProduct][google.cloud.retail.v2beta.ProductService.GetProduct] or
  // [ListProducts][google.cloud.retail.v2beta.ProductService.ListProducts].
  //
  // This feature is only available for users who have Retail Search enabled.
  // Contact Retail Support (retail-search-support@google.com) if you are
  // interested in using Retail Search.
  rpc AddFulfillmentPlaces(AddFulfillmentPlacesRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v2beta/{product=projects/*/locations/*/catalogs/*/branches/*/products/**}:addFulfillmentPlaces"
      body: "*"
    };
    option (google.api.method_signature) = "product";
    option (google.longrunning.operation_info) = {
      response_type: "google.cloud.retail.v2beta.AddFulfillmentPlacesResponse"
      metadata_type: "google.cloud.retail.v2beta.AddFulfillmentPlacesMetadata"
    };
  }

  // Incrementally removes place IDs from a
  // [Product.fulfillment_info.place_ids][google.cloud.retail.v2beta.FulfillmentInfo.place_ids].
  //
  // This process is asynchronous and does not require the
  // [Product][google.cloud.retail.v2beta.Product] to exist before updating
  // fulfillment information. If the request is valid, the update will be
  // enqueued and processed downstream. As a consequence, when a response is
  // returned, the removed place IDs are not immediately manifested in the
  // [Product][google.cloud.retail.v2beta.Product] queried by
  // [GetProduct][google.cloud.retail.v2beta.ProductService.GetProduct] or
  // [ListProducts][google.cloud.retail.v2beta.ProductService.ListProducts].
  //
  // This feature is only available for users who have Retail Search enabled.
  // Contact Retail Support (retail-search-support@google.com) if you are
  // interested in using Retail Search.
  rpc RemoveFulfillmentPlaces(RemoveFulfillmentPlacesRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v2beta/{product=projects/*/locations/*/catalogs/*/branches/*/products/**}:removeFulfillmentPlaces"
      body: "*"
    };
    option (google.api.method_signature) = "product";
    option (google.longrunning.operation_info) = {
      response_type: "google.cloud.retail.v2beta.RemoveFulfillmentPlacesResponse"
      metadata_type: "google.cloud.retail.v2beta.RemoveFulfillmentPlacesMetadata"
    };
  }
}

// Request message for [CreateProduct][] method.
message CreateProductRequest {
  // Required. The parent catalog resource name, such as
  // `projects/*/locations/global/catalogs/default_catalog/branches/default_branch`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "retail.googleapis.com/Branch" }
  ];

  // Required. The [Product][google.cloud.retail.v2beta.Product] to create.
  Product product = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The ID to use for the
  // [Product][google.cloud.retail.v2beta.Product], which will become the final
  // component of the [Product.name][google.cloud.retail.v2beta.Product.name].
  //
  // If the caller does not have permission to create the
  // [Product][google.cloud.retail.v2beta.Product], regardless of whether or not
  // it exists, a PERMISSION_DENIED error is returned.
  //
  // This field must be unique among all
  // [Product][google.cloud.retail.v2beta.Product]s with the same
  // [parent][google.cloud.retail.v2beta.CreateProductRequest.parent].
  // Otherwise, an ALREADY_EXISTS error is returned.
  //
  // This field must be a UTF-8 encoded string with a length limit of 128
  // characters. Otherwise, an INVALID_ARGUMENT error is returned.
  string product_id = 3 [(google.api.field_behavior) = REQUIRED];
}

// Request message for [GetProduct][] method.
message GetProductRequest {
  // Required. Full resource name of
  // [Product][google.cloud.retail.v2beta.Product], such as
  // `projects/*/locations/global/catalogs/default_catalog/branches/default_branch/products/some_product_id`.
  //
  // If the caller does not have permission to access the
  // [Product][google.cloud.retail.v2beta.Product], regardless of whether or not
  // it exists, a PERMISSION_DENIED error is returned.
  //
  // If the requested [Product][google.cloud.retail.v2beta.Product] does not
  // exist, a NOT_FOUND error is returned.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "retail.googleapis.com/Product" }
  ];
}

// Request message for [UpdateProduct][] method.
message UpdateProductRequest {
  // Required. The product to update/create.
  //
  // If the caller does not have permission to update the
  // [Product][google.cloud.retail.v2beta.Product], regardless of whether or not
  // it exists, a PERMISSION_DENIED error is returned.
  //
  // If the [Product][google.cloud.retail.v2beta.Product] to update does not
  // exist and
  // [allow_missing][google.cloud.retail.v2beta.UpdateProductRequest.allow_missing]
  // is not set, a NOT_FOUND error is returned.
  Product product = 1 [(google.api.field_behavior) = REQUIRED];

  // Indicates which fields in the provided
  // [Product][google.cloud.retail.v2beta.Product] to update. The immutable and
  // output only fields are NOT supported. If not set, all supported fields (the
  // fields that are neither immutable nor output only) are updated.
  //
  // If an unsupported or unknown field is provided, an INVALID_ARGUMENT error
  // is returned.
  google.protobuf.FieldMask update_mask = 2;

  // If set to true, and the [Product][google.cloud.retail.v2beta.Product] is
  // not found, a new [Product][google.cloud.retail.v2beta.Product] will be
  // created. In this situation, `update_mask` is ignored.
  bool allow_missing = 3;
}

// Request message for [DeleteProduct][] method.
message DeleteProductRequest {
  // Required. Full resource name of
  // [Product][google.cloud.retail.v2beta.Product], such as
  // `projects/*/locations/global/catalogs/default_catalog/branches/default_branch/products/some_product_id`.
  //
  // If the caller does not have permission to delete the
  // [Product][google.cloud.retail.v2beta.Product], regardless of whether or not
  // it exists, a PERMISSION_DENIED error is returned.
  //
  // If the [Product][google.cloud.retail.v2beta.Product] to delete does not
  // exist, a NOT_FOUND error is returned.
  //
  // The [Product][google.cloud.retail.v2beta.Product] to delete can neither be
  // a
  // [Product.Type.COLLECTION][google.cloud.retail.v2beta.Product.Type.COLLECTION]
  // [Product][google.cloud.retail.v2beta.Product] member nor a
  // [Product.Type.PRIMARY][google.cloud.retail.v2beta.Product.Type.PRIMARY]
  // [Product][google.cloud.retail.v2beta.Product] with more than one
  // [variants][google.cloud.retail.v2beta.Product.Type.VARIANT]. Otherwise, an
  // INVALID_ARGUMENT error is returned.
  //
  // All inventory information for the named
  // [Product][google.cloud.retail.v2beta.Product] will be deleted.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "retail.googleapis.com/Product" }
  ];
}

// Request message for
// [ProductService.ListProducts][google.cloud.retail.v2beta.ProductService.ListProducts]
// method.
message ListProductsRequest {
  // Required. The parent branch resource name, such as
  // `projects/*/locations/global/catalogs/default_catalog/branches/0`. Use
  // `default_branch` as the branch ID, to list products under the default
  // branch.
  //
  // If the caller does not have permission to list
  // [Product][google.cloud.retail.v2beta.Product]s under this branch,
  // regardless of whether or not this branch exists, a PERMISSION_DENIED error
  // is returned.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "retail.googleapis.com/Branch" }
  ];

  // Maximum number of [Product][google.cloud.retail.v2beta.Product]s to return.
  // If unspecified, defaults to 100. The maximum allowed value is 1000. Values
  // above 1000 will be coerced to 1000.
  //
  // If this field is negative, an INVALID_ARGUMENT error is returned.
  int32 page_size = 2;

  // A page token
  // [ListProductsResponse.next_page_token][google.cloud.retail.v2beta.ListProductsResponse.next_page_token],
  // received from a previous
  // [ProductService.ListProducts][google.cloud.retail.v2beta.ProductService.ListProducts]
  // call. Provide this to retrieve the subsequent page.
  //
  // When paginating, all other parameters provided to
  // [ProductService.ListProducts][google.cloud.retail.v2beta.ProductService.ListProducts]
  // must match the call that provided the page token. Otherwise, an
  // INVALID_ARGUMENT error is returned.
  string page_token = 3;

  // A filter to apply on the list results. Supported features:
  //
  // * List all the products under the parent branch if
  // [filter][google.cloud.retail.v2beta.ListProductsRequest.filter] is unset.
  // * List
  // [Product.Type.VARIANT][google.cloud.retail.v2beta.Product.Type.VARIANT]
  // [Product][google.cloud.retail.v2beta.Product]s sharing the same
  //   [Product.Type.PRIMARY][google.cloud.retail.v2beta.Product.Type.PRIMARY]
  //   [Product][google.cloud.retail.v2beta.Product]. For example:
  //     `primary_product_id = "some_product_id"`
  // * List [Product][google.cloud.retail.v2beta.Product]s bundled in a
  // [Product.Type.COLLECTION][google.cloud.retail.v2beta.Product.Type.COLLECTION]
  // [Product][google.cloud.retail.v2beta.Product].
  //   For example:
  //     `collection_product_id = "some_product_id"`
  // * List [Product][google.cloud.retail.v2beta.Product]s with a partibular
  // type. For example:
  //     `type = "PRIMARY"`
  //     `type = "VARIANT"`
  //     `type = "COLLECTION"`
  //
  // If the field is unrecognizable, an INVALID_ARGUMENT error is returned.
  //
  // If the specified
  // [Product.Type.PRIMARY][google.cloud.retail.v2beta.Product.Type.PRIMARY]
  // [Product][google.cloud.retail.v2beta.Product] or
  // [Product.Type.COLLECTION][google.cloud.retail.v2beta.Product.Type.COLLECTION]
  // [Product][google.cloud.retail.v2beta.Product] does not exist, a NOT_FOUND
  // error is returned.
  string filter = 4;

  // The fields of [Product][google.cloud.retail.v2beta.Product] to return in
  // the responses. If not set or empty, the following fields are returned:
  //
  // * [Product.name][google.cloud.retail.v2beta.Product.name]
  // * [Product.id][google.cloud.retail.v2beta.Product.id]
  // * [Product.title][google.cloud.retail.v2beta.Product.title]
  // * [Product.uri][google.cloud.retail.v2beta.Product.uri]
  // * [Product.images][google.cloud.retail.v2beta.Product.images]
  // * [Product.price_info][google.cloud.retail.v2beta.Product.price_info]
  // * [Product.brands][google.cloud.retail.v2beta.Product.brands]
  //
  // If "*" is provided, all fields are returned.
  // [Product.name][google.cloud.retail.v2beta.Product.name] is always returned
  // no matter what mask is set.
  //
  // If an unsupported or unknown field is provided, an INVALID_ARGUMENT error
  // is returned.
  google.protobuf.FieldMask read_mask = 5;
}

// Response message for
// [ProductService.ListProducts][google.cloud.retail.v2beta.ProductService.ListProducts]
// method.
message ListProductsResponse {
  // The [Product][google.cloud.retail.v2beta.Product]s.
  repeated Product products = 1;

  // A token that can be sent as
  // [ListProductsRequest.page_token][google.cloud.retail.v2beta.ListProductsRequest.page_token]
  // to retrieve the next page. If this field is omitted, there are no
  // subsequent pages.
  string next_page_token = 2;
}

// Request message for [SetInventory][] method.
message SetInventoryRequest {
  // Required. The inventory information to update. The allowable fields to
  // update are:
  // * [Product.price_info][google.cloud.retail.v2beta.Product.price_info]
  // * [Product.availability][google.cloud.retail.v2beta.Product.availability]
  // * [Product.available_quantity][google.cloud.retail.v2beta.Product.available_quantity]
  // * [Product.fulfillment_info][google.cloud.retail.v2beta.Product.fulfillment_info]
  // The updated inventory fields must be specified in
  // [SetInventoryRequest.set_mask][google.cloud.retail.v2beta.SetInventoryRequest.set_mask].
  //
  // If [SetInventoryRequest.inventory.name][] is empty or invalid, an
  // INVALID_ARGUMENT error is returned.
  //
  // If the caller does not have permission to update the
  // [Product][google.cloud.retail.v2beta.Product] named in
  // [Product.name][google.cloud.retail.v2beta.Product.name], regardless of
  // whether or not it exists, a PERMISSION_DENIED error is returned.
  //
  // If the [Product][google.cloud.retail.v2beta.Product] to update does not
  // have existing inventory information, the provided inventory information
  // will be inserted.
  //
  // If the [Product][google.cloud.retail.v2beta.Product] to update has existing
  // inventory information, the provided inventory information will be merged
  // while respecting the last update time for each inventory field, using the
  // provided or default value for
  // [SetInventoryRequest.set_time][google.cloud.retail.v2beta.SetInventoryRequest.set_time].
  //
  // The last update time is recorded for the following inventory fields:
  // * [Product.price_info][google.cloud.retail.v2beta.Product.price_info]
  // * [Product.availability][google.cloud.retail.v2beta.Product.availability]
  // * [Product.available_quantity][google.cloud.retail.v2beta.Product.available_quantity]
  // * [Product.fulfillment_info][google.cloud.retail.v2beta.Product.fulfillment_info]
  //
  // If a full overwrite of inventory information while ignoring timestamps is
  // needed, [UpdateProduct][] should be invoked instead.
  Product inventory = 1 [(google.api.field_behavior) = REQUIRED];

  // Indicates which inventory fields in the provided
  // [Product][google.cloud.retail.v2beta.Product] to update. If not set or set
  // with empty paths, all inventory fields will be updated.
  //
  // If an unsupported or unknown field is provided, an INVALID_ARGUMENT error
  // is returned and the entire update will be ignored.
  google.protobuf.FieldMask set_mask = 2;

  // The time when the request is issued, used to prevent
  // out-of-order updates on inventory fields with the last update time
  // recorded. If not provided, the internal system time will be used.
  google.protobuf.Timestamp set_time = 3;

  // If set to true, and the [Product][google.cloud.retail.v2beta.Product] with
  // name [Product.name][google.cloud.retail.v2beta.Product.name] is not found,
  // the inventory update will still be processed and retained for at most 1 day
  // until the [Product][google.cloud.retail.v2beta.Product] is created. If set
  // to false, an INVALID_ARGUMENT error is returned if the
  // [Product][google.cloud.retail.v2beta.Product] is not found.
  bool allow_missing = 4;
}

// Metadata related to the progress of the SetInventory operation.
// Currently empty because there is no meaningful metadata populated from the
// [SetInventory][] method.
message SetInventoryMetadata {}

// Response of the SetInventoryRequest.  Currently empty because
// there is no meaningful response populated from the [SetInventory][]
// method.
message SetInventoryResponse {}

// Request message for [AddFulfillmentPlaces][] method.
message AddFulfillmentPlacesRequest {
  // Required. Full resource name of
  // [Product][google.cloud.retail.v2beta.Product], such as
  // `projects/*/locations/global/catalogs/default_catalog/branches/default_branch/products/some_product_id`.
  //
  // If the caller does not have permission to access the
  // [Product][google.cloud.retail.v2beta.Product], regardless of whether or not
  // it exists, a PERMISSION_DENIED error is returned.
  string product = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "retail.googleapis.com/Product" }
  ];

  // Required. The fulfillment type, including commonly used types (such as
  // pickup in store and same day delivery), and custom types.
  //
  // Supported values:
  //
  // * "pickup-in-store"
  // * "ship-to-store"
  // * "same-day-delivery"
  // * "next-day-delivery"
  // * "custom-type-1"
  // * "custom-type-2"
  // * "custom-type-3"
  // * "custom-type-4"
  // * "custom-type-5"
  //
  // If this field is set to an invalid value other than these, an
  // INVALID_ARGUMENT error is returned.
  //
  // This field directly corresponds to [Product.fulfillment_info.type][].
  string type = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The IDs for this
  // [type][google.cloud.retail.v2beta.AddFulfillmentPlacesRequest.type], such
  // as the store IDs for "pickup-in-store" or the region IDs for
  // "same-day-delivery" to be added for this
  // [type][google.cloud.retail.v2beta.AddFulfillmentPlacesRequest.type].
  // Duplicate IDs will be automatically ignored.
  //
  // At least 1 value is required, and a maximum of 2000 values are allowed.
  // Each value must be a string with a length limit of 10 characters, matching
  // the pattern [a-zA-Z0-9_-]+, such as "store1" or "REGION-2". Otherwise, an
  // INVALID_ARGUMENT error is returned.
  //
  // If the total number of place IDs exceeds 2000 for this
  // [type][google.cloud.retail.v2beta.AddFulfillmentPlacesRequest.type] after
  // adding, then the update will be rejected.
  repeated string place_ids = 3 [(google.api.field_behavior) = REQUIRED];

  // The time when the fulfillment updates are issued, used to prevent
  // out-of-order updates on fulfillment information. If not provided, the
  // internal system time will be used.
  google.protobuf.Timestamp add_time = 4;

  // If set to true, and the [Product][google.cloud.retail.v2beta.Product] is
  // not found, the fulfillment information will still be processed and retained
  // for at most 1 day and processed once the
  // [Product][google.cloud.retail.v2beta.Product] is created. If set to false,
  // an INVALID_ARGUMENT error is returned if the
  // [Product][google.cloud.retail.v2beta.Product] is not found.
  bool allow_missing = 5;
}

// Metadata related to the progress of the AddFulfillmentPlaces operation.
// Currently empty because there is no meaningful metadata populated from the
// [AddFulfillmentPlaces][] method.
message AddFulfillmentPlacesMetadata {}

// Response of the RemoveFulfillmentPlacesRequest.  Currently empty because
// there is no meaningful response populated from the [AddFulfillmentPlaces][]
// method.
message AddFulfillmentPlacesResponse {}

// Request message for [RemoveFulfillmentPlaces][] method.
message RemoveFulfillmentPlacesRequest {
  // Required. Full resource name of
  // [Product][google.cloud.retail.v2beta.Product], such as
  // `projects/*/locations/global/catalogs/default_catalog/branches/default_branch/products/some_product_id`.
  //
  // If the caller does not have permission to access the
  // [Product][google.cloud.retail.v2beta.Product], regardless of whether or not
  // it exists, a PERMISSION_DENIED error is returned.
  string product = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "retail.googleapis.com/Product" }
  ];

  // Required. The fulfillment type, including commonly used types (such as
  // pickup in store and same day delivery), and custom types.
  //
  // Supported values:
  //
  // * "pickup-in-store"
  // * "ship-to-store"
  // * "same-day-delivery"
  // * "next-day-delivery"
  // * "custom-type-1"
  // * "custom-type-2"
  // * "custom-type-3"
  // * "custom-type-4"
  // * "custom-type-5"
  //
  // If this field is set to an invalid value other than these, an
  // INVALID_ARGUMENT error is returned.
  //
  // This field directly corresponds to [Product.fulfillment_info.type][].
  string type = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The IDs for this
  // [type][google.cloud.retail.v2beta.RemoveFulfillmentPlacesRequest.type],
  // such as the store IDs for "pickup-in-store" or the region IDs for
  // "same-day-delivery", to be removed for this
  // [type][google.cloud.retail.v2beta.RemoveFulfillmentPlacesRequest.type].
  //
  // At least 1 value is required, and a maximum of 2000 values are allowed.
  // Each value must be a string with a length limit of 10 characters, matching
  // the pattern [a-zA-Z0-9_-]+, such as "store1" or "REGION-2". Otherwise, an
  // INVALID_ARGUMENT error is returned.
  repeated string place_ids = 3 [(google.api.field_behavior) = REQUIRED];

  // The time when the fulfillment updates are issued, used to prevent
  // out-of-order updates on fulfillment information. If not provided, the
  // internal system time will be used.
  google.protobuf.Timestamp remove_time = 4;

  // If set to true, and the [Product][google.cloud.retail.v2beta.Product] is
  // not found, the fulfillment information will still be processed and retained
  // for at most 1 day and processed once the
  // [Product][google.cloud.retail.v2beta.Product] is created. If set to false,
  // an INVALID_ARGUMENT error is returned if the
  // [Product][google.cloud.retail.v2beta.Product] is not found.
  bool allow_missing = 5;
}

// Metadata related to the progress of the RemoveFulfillmentPlaces operation.
// Currently empty because there is no meaningful metadata populated from the
// [RemoveFulfillmentPlaces][] method.
message RemoveFulfillmentPlacesMetadata {}

// Response of the RemoveFulfillmentPlacesRequest. Currently empty because there
// is no meaningful response populated from the [RemoveFulfillmentPlaces][]
// method.
message RemoveFulfillmentPlacesResponse {}
