// Copyright 2026 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.commerceproducer.v1beta;

import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/timestamp.proto";
import "google/type/datetime.proto";
import "google/type/decimal.proto";
import "google/type/money.proto";

option csharp_namespace = "Google.Cloud.CommerceProducer.V1Beta";
option go_package = "cloud.google.com/go/commerceproducer/apiv1beta/commerceproducerpb;commerceproducerpb";
option java_multiple_files = true;
option java_outer_classname = "PrivateOfferProto";
option java_package = "com.google.cloud.commerceproducer.v1beta";
option php_namespace = "Google\\Cloud\\CommerceProducer\\V1beta";
option ruby_package = "Google::Cloud::CommerceProducer::V1beta";

// Message describing PrivateOffer resource.
//
// Note on OPTIONAL fields: To facilitate saving incomplete draft offers, most
// fields are categorized as OPTIONAL irrespective of whether they are necessary
// for a private offer to be valid. Many fields labeled OPTIONAL must be set to
// publish the offer.
message PrivateOffer {
  option (google.api.resource) = {
    type: "commerceproducer.googleapis.com/PrivateOffer"
    pattern: "projects/{project}/locations/{location}/privateOffers/{private_offer}"
    plural: "privateOffers"
    singular: "privateOffer"
  };

  // Information about the Google review process.
  message PublishRequirementGoogleReview {
    // Output only. The approval time of the Google review process.
    google.protobuf.Timestamp review_approve_time = 2
        [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Contact information for a reseller.
  message ResellerContact {
    // Output only. The name of the reseller contact for this offer.
    string contact = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. The email of the reseller contact for this offer.
    string email = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Contact information for the partner representative.
  message PartnerContact {
    // Optional. Display text identifying the partner sales contact.
    // Displayed to the customer.
    // Must be provided when publishing the offer.
    // Maximum length: 256 characters.
    string contact = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. The email address of the partner sales contact.
    // Displayed to the customer.
    // The format of the provided email address is validated when publishing the
    // offer, but no verification is performed that the email address actually
    // exists, accepts email, or is otherwise functional.
    string email = 2 [(google.api.field_behavior) = OPTIONAL];
  }

  // Information about the customer.
  message Customer {
    // Optional. A string identifying the customer's entity (for example, the
    // customer's organization or company name). Must be provided when
    // publishing the offer. Maximum length: 256 characters.
    string entity_title = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. A string identifying the customer contact.
    // Must be provided when publishing the offer.
    // Maximum length: 256 characters.
    string contact = 2 [(google.api.field_behavior) = OPTIONAL];

    // Optional. Email of customer contact.
    // If provided, it must be a well-formed email address.
    string email = 3 [(google.api.field_behavior) = OPTIONAL];

    // Output only. Legal address of the customer organization.
    // This field can no longer be set, but it is preserved to return the
    // data from existing offers where address is set.
    string address = 4
        [deprecated = true, (google.api.field_behavior) = OUTPUT_ONLY];

    // Optional. The customer's billing account targeted by the offer.
    // The private offer once published can be accepted by a billing
    // administrator of the target billing account. If the customer accepts the
    // offer and later moves the resulting order to a new billing account, this
    // field will continue to reflect the original billing account to which the
    // private offer was extended. Must be provided when publishing the offer.
    //
    // To publish this private offer:
    //
    // * The billing account must exist.
    // * The billing account must not be in a free trial.
    // * The billing account must comply with Marketplace Reselling Policies.
    // * Reseller parent billing accounts are prohibited. Reseller subaccounts
    //   are prohibited unless the service is enabled for reselling.
    //
    // Format: billingAccounts/012345-567890-ABCDEF
    string target_billing_account = 5 [
      (google.api.field_behavior) = OPTIONAL,
      (google.api.resource_reference) = {
        type: "cloudbilling.googleapis.com/BillingAccount"
      }
    ];
  }

  // Configurations for the offer term and renewal options.
  // Extending a private offer to a customer that covers a given term
  // constitutes a guarantee to the customer that the product will remain
  // available to them for the duration of the term.
  message Term {
    // Defines when an offer should start.
    enum StartPolicy {
      // Default value. This value is unused.
      START_POLICY_UNSPECIFIED = 0;

      // The resulting order starts immediately upon the customer's acceptance
      // of the offer, if no partner approval is required, or else immediately
      // after the partner approves the purchase if order approval is required.
      // This enum value cannot be combined with `term.scheduled_start_time`.
      IMMEDIATE = 1;

      // The resulting order starts at the scheduled start time.
      SCHEDULED_START_TIME = 2;
    }

    // Defines when an offer should end.
    enum EndPolicy {
      // Default value. This value is unused.
      END_POLICY_UNSPECIFIED = 0;

      // Offer ends after the specified duration.
      // If this is set, then `duration_months` must be positive.
      AFTER_DURATION = 1;

      // Offer ends at the schduled time.
      SCHEDULED_END_TIME = 2;

      // Offer coterms to the amended offer - the offer ends at the end of the
      // amended offer's term
      //
      // For example, if the amended offer starts on 01/15/24, and has a
      // duration of 6 months, then it ends on 07/15/24. If the current offer
      // coterms to the previous offer, and the current offer starts on
      // 05/06/24, then it will still end on 07/15/24. Assuming the current
      // offer renews 3 times, then the terms on the current offer will be:
      //
      // 1. 05/06/24 - 07/15/24 (First term, ends on 07/15 to coterm with the
      //    amended offer)
      // 2. 07/15/24 - 01/15/25 (First renewal term)
      // 3. 01/15/25 - 07/15/25 (Second renewal term)
      // 4. 07/15/25 - 01/15/26 (Third renewal term)
      //
      // As a contrast, if the current offer does not coterm with the amended
      // offer (such as when `end_policy` is `AFTER_DURATION`), then the
      // terms will be:
      //
      // 1. 05/06/24 - 11/06/24 (First term, ends on 11/06, no coterming)
      // 2. 11/06/24 - 05/06/25 (First renewal term)
      // 3. 05/06/25 - 11/06/25 (Second renewal term)
      // 4. 11/06/25 - 05/06/26 (Third renewal term)
      //
      // If this is set, then the following conditions must be met:
      //
      // * `single_product_offer.amended_private_offer` must be set, and the
      //   amended private offer must not be ended.
      // * The proration policy must not change (e.g., you cannot switch
      //   between `MONTHLY_PRORATED` and `MONTHLY_NOT_PRORATED`).
      // * The current offer must not have custom intervals (where
      //   `custom_interval_price` is set).
      // * `term.duration_months` must match the amended private offer's
      //   duration.
      // * The amended private offer must not have a standard interval
      //   of `MONTHLY_POSTPAY`.
      //
      // This is currently not supported.
      MATCH_AMENDED_OFFER = 3;
    }

    // Extra data for the end policy.
    oneof end_policy_data {
      // Optional. Duration in months of the offer term.
      // The offer will end on the same day of the month after this duration. If
      // that date is not available, the offer will end on the last day of the
      // month. For example, if the offer starts on 01/31/2024 and the duration
      // is 13 months, the offer will end on 02/28/2025.
      // Must be set to publish the offer if the end policy is `AFTER_DURATION`
      // or `MATCH_AMENDED_OFFER`, and must be a positive value.
      //
      // The maximum possible offer duration, including all renewal terms,
      // cannot exceed 7 years. For example, if `duration_months` is 9 and
      // `term.max_renewal_count` is 9, then the maximum possible offer duration
      // is 90 months and exceeds the 7 year limit.
      int32 duration_months = 4 [(google.api.field_behavior) = OPTIONAL];

      // Optional. Specified end time of the offer.
      // Must be set to publish the offer if the end policy is
      // `SCHEDULED_END_TIME`.
      // When set, the time must be in the future and at a day boundary in the
      // America/Los_Angeles time zone, and must be after
      // `term.scheduled_start_time` if applicable.
      google.type.DateTime scheduled_end_time = 5
          [(google.api.field_behavior) = OPTIONAL];
    }

    // Defines the renewal policy for the offer.
    oneof renewal {
      // Optional. The max number of renewals allowed, after the initial term
      // ends. This field is only relevant to standard interval offers with
      // interval of 'MONTHLY_PRORATED', 'MONTHLY_NOT_PRORATED',
      // 'QUARTERLY_NOT_PRORATED' or 'YEARLY_NOT_PRORATED'. Other types of
      // offers cannot be renewed.
      //
      // For example, if the initial term is 1 year and the max renewals is 3,
      // the customer can renew the offer for up to 3 additional years after the
      // initial term ends. Customers control whether they renew the offer.
      //
      // Allowing a customer to renew an offer does not constitute a guarantee
      // to the customer that the offered product will still be available to be
      // renewed at the renewal date.
      //
      // An offer with a max renewal count of 0 cannot be renewed.
      // Must be non-negative.
      int32 max_renewal_count = 6 [(google.api.field_behavior) = OPTIONAL];

      // Output only. Deprecated: This field can only be true on existing offers
      // with standard interval of 'MONTHLY_POSTPAY'. As of May 2024, we no
      // longer allow unlimited renewals.
      bool unlimited_renewal = 7
          [deprecated = true, (google.api.field_behavior) = OUTPUT_ONLY];
    }

    // Optional. Defines when the resulting order should start.
    // Must be set when publishing the offer.
    StartPolicy start_policy = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. The scheduled start time of the offer. Cannot exceed one year
    // from the time of publish.
    //
    // If the start policy is `SCHEDULED_START_TIME`, a future time at a day
    // boundary in the America/Los_Angeles time zone must be provided when
    // publishing the offer.
    //
    // If the offer amends another private or standard offer, then the
    // scheduled start time must be:
    //
    // * Before or equal to the amended offer's end time if the offer's
    //   end policy is not MATCH_AMENDED_OFFER. Otherwise, it has to be
    //   strictly before the amended offer's end time.
    // * Before or equal to the start time of the next pending installment of
    //   the amended offer, if amending a private offer with custom
    //   installments. For example, if the amended offer has installments on
    //   01/01, 02/01, 03/01, 04/01, and today is 02/15, then the new offer's
    //   `scheduled_start_time` must be at or before 03/01.
    google.type.DateTime scheduled_start_time = 2
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. Defines when an offer should end.
    // Must be set when publishing the offer.
    EndPolicy end_policy = 3 [(google.api.field_behavior) = OPTIONAL];

    // Output only. The expected end time of the current offer term.
    //
    // At the end of each offer term, an offer associated with an active
    // order will either renew or end. When an offer renews, a new term begins
    // and this value changes to reflect the end time of the new term.
    // When an offer ends this value is no longer set and instead `end_time` is
    // set.
    //
    // When the term of an offer ends and the offer does not renew, the
    // associated order also ends if the base standard offer has a
    // subscription price model. Otherwise, the associated order does not end
    // and remains active.
    //
    // Not included for PRIVATE_OFFER_VIEW_BASIC.
    // Included for PRIVATE_OFFER_VIEW_FULL when the offer has not ended and
    // either the offer has started or the value can be derived from other
    // fields.
    //
    // For offers that have not started, this field is set when one of the
    // following conditions is true.
    //
    // * The offer sets `term.scheduled_end_time`.
    // * The offer sets `term.scheduled_start_time` and `term.duration_months`,
    //   the offer's `term.end_policy` is not `MATCH_AMENDED_OFFER`, and the
    //   offer does not have standard_interval set to `MONTHLY_POSTPAY`.
    google.type.DateTime effective_term_end_time = 8
        [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Configurations for the offer that is associated with a single product.
  message SingleProductOffer {
    // Additional details used to describe customization of the service level.
    //
    // Features are used to distinguish service levels of the same product.
    // When a product has a single service level, all details can be contained
    // in the product documentation. When a product has multiple service levels,
    // each service level can be assigned a distinct set of features to
    // distinguish the key differences between the service levels.
    //
    // In addition to customizing pricing and other transaction details, a
    // private offer may include customization of partner-managed product
    // behavior. When this is the case, the details of the custom behavior are
    // described using features.
    message Feature {
      // Optional. Human readable display text characterizing the feature.
      // Should be sufficiently detailed to identify the feature, allowing
      // features to be correlated across separate offers and service levels.
      // Must be non-empty to publish the offer.
      // The maximum allowed length is 128 characters.
      // Allows characters from the following Unicode Property Classes:
      // Letters, Numbers, Punctuation, Symbols, and Separators
      string display_name = 1 [(google.api.field_behavior) = OPTIONAL];

      // Optional. Human readable display text reflecting the value of the
      // feature. Used for variable features not captured by the display_name
      // alone. The maximum allowed length is 3000 characters. Allows characters
      // from the following Unicode Property Classes: Letters, Numbers,
      // Punctuation, Symbols, and Separators
      string value = 2 [(google.api.field_behavior) = OPTIONAL];
    }

    // The price model of the private offer.
    //
    // Private offers are referred to as having different kinds of price models
    // based on the combination of fields set in the price model. The following
    // terminology is used in documentation and other reference material.
    //
    // * Usage-based: the price model does not set `flat_fee`
    // * Usage-only: the price model sets only `usage`
    // * CUD (committed use discount): the price model sets `commitment`
    //     * Commitment discount with additional usage at list price:
    //       The price model sets `commitment` and not `usage`.
    //     * Commitment with all usage discounted: The price model sets
    //       `commitment` and `usage`.
    // * Flat fee: the price model sets only `flat_fee`
    // * Flat fee with usage: the price model sets `flat_fee` and `usage`
    //
    // See
    // https://docs.cloud.google.com/marketplace/docs/partners/offers/select-pricing-model#CUD
    // for the price models.
    message PriceModel {
      // The discount for a specific SKU.
      message SkuDiscount {
        // Required. The SKU to which the discount applies.
        oneof target {
          // Optional. The name of a partner SKU from this API.
          //
          // Must refer to a SKU in the price model of the base standard offer.
          // Inclusion in the base price model can occur either directly or
          // indirectly via inclusion in an included SkuGroup.
          //
          // Currently, standard offer price models include only partner SKUs
          // in the same project as the standard offer. This may change.
          //
          // Format:
          // projects/{project}/locations/{location}/services/{service}/skus/{sku}
          string sku = 1 [
            (google.api.field_behavior) = OPTIONAL,
            (google.api.resource_reference) = {
              type: "commerceproducer.googleapis.com/Sku"
            }
          ];

          // Optional. The name of a Google SKU from the Cloud Billing API.
          //
          // Used for partner products sold by Google, such as Premium Operating
          // System Images sold for use in Compute Engine. This is not common.
          // SKUs of this type are not present on this API and can instead be
          // found on the Cloud Billing API or at https://cloud.google.com/skus.
          //
          // Must refer to a SKU in the price model of the base standard offer.
          // Google SKUs are always referenced in standard offers via SkuGroups.
          //
          // Format: services/{service}/skus/{sku}
          string cloud_billing_sku = 3 [(google.api.field_behavior) = OPTIONAL];
        }

        // The discount for the SKU.
        oneof discount {
          // Optional. The discount percent for the SKU.
          // For example, `10` means a discount of 10%. If the original SKU
          // price is $100/hour then the discounted price will be $90/hour.
          //
          // Must be between 0 and 100 inclusive, with precision up to 2 decimal
          // places. If this field is set, then the allowed pattern for 'value'
          // is `^([0-9]{1,2}(\\.\\d{1,2})?|100(\\.0{1,2})?)$`.
          //
          // Examples of valid values: "0", "100.0", "12.34", "40.0".
          // Example of invalid values: ".3", "-1", "100.1", "12.345", "+12",
          // and "".
          // Must be present to publish the offer.
          google.type.Decimal discount_percent = 2
              [(google.api.field_behavior) = OPTIONAL];
        }
      }

      // The price for the usage SKUs.
      message Usage {
        // Optional. The default discount percent for usage SKUs.
        // An unset default discount percent is equivalent to 0 (no discount).
        //
        // Must be between 0 and 100 inclusive, with precision up to 2 decimal
        // places. If this field is set, then the allowed pattern for 'value'
        // is `^([0-9]{1,2}(\\.\\d{1,2})?|100(\\.0{1,2})?)$`.
        // Examples of valid values: "0", "100.0", "12.34", "40.0".
        // Example of invalid values: ".3", "-1", "100.1", "12.345", "+12", "".
        google.type.Decimal default_discount_percent = 1
            [(google.api.field_behavior) = OPTIONAL];

        // Optional. The discounts for the specific SKUs that override the
        // `default_discount_percent`.
        repeated SkuDiscount sku_discounts = 2
            [(google.api.field_behavior) = OPTIONAL];
      }

      // The price configurations for the flat fee subscriptions.
      message FlatFee {
        // Optional. Flat fee overriding the default flat fee in the base
        // standard offer. Value cannot be negative. The currency must be "USD"
        // and precision is limited to cents. Must be present to publish the
        // offer, if the parent message is set. The maximum allowed value is
        // 1,000,000,000 USD.
        google.type.Money flat_fee_override = 1
            [(google.api.field_behavior) = OPTIONAL];
      }

      // The price configurations for the commitment based subscriptions.
      message Commitment {
        // Optional. The commitment balance that the customer will receive.
        // Value cannot be negative.
        // The currency must be "USD" and precision is limited to cents.
        // Must be present to publish the offer, if the parent message is set.
        // The maximum allowed value is 1,000,000,000 USD.
        //
        // If the current offer amends a private offer where the term has not
        // ended, and if the field
        // `single_product_offer.standard_interval_price.price_model.commitment.commitment_amount`
        // is set on both the current offer and the amended private offer, then
        // the commitment amount must be equal or higher on the current offer,
        // compared to the amended private offer.
        google.type.Money commitment_amount = 1
            [(google.api.field_behavior) = OPTIONAL];

        // Optional. The discount percent on `commitment_amount`.
        //
        // For example, `10` means a discount of 10%. If the original
        // `commitment_amount` is $100 then the discounted amount will be $90.
        // The customer is charged $90 and receives $100 in credits.
        //
        // All reported usage will be charged at the standard price.
        // If this field is set, the `price_model.usage` must be unset. A
        // private offer can apply a discount to all usage or to a usage
        // commitment, but not both.
        //
        // Must be between 0 and 100 inclusive, with precision up to 2 decimal
        // places. If this field is set, then the allowed pattern for 'value'
        // is `^([0-9]{1,2}(\\.\\d{1,2})?|100(\\.0{1,2})?)$`.
        // Examples of valid values: "0", "100.0", "12.34", "40.0".
        // Example of invalid values: ".3", "-1", "100.1", "12.345", "+12", "".
        //
        // Must be present to publish the offer.
        google.type.Decimal discount_percent = 2
            [(google.api.field_behavior) = OPTIONAL];

        // Optional. Additional credit granted to the customer.
        // Additional credits are only supported for custom interval offers.
        // Equivalent behavior can be achieved for standard interval offers by
        // varying the `commitment_amount` and `discount_percent`.
        //
        // Value cannot be negative.
        // The currency must be "USD" and precision is limited to cents.
        // The maximum allowed value is 1,000,000 USD.
        google.type.Money additional_credit = 3
            [(google.api.field_behavior) = OPTIONAL];

        // Optional. Whether to discard the previous credit balance when the
        // associated installment starts. If not set, the previous credit
        // balance will be rolled over to the current installment.
        //
        // If there are no previous installments, then the value of this field
        // will not matter - since it has no effect when no credits exist.
        bool discard_previous_credit_balance = 4
            [(google.api.field_behavior) = OPTIONAL];
      }

      // The price configurations for the subscription part.
      oneof subscription {
        // Optional. The price configurations for the flat fee subscription.
        // Must be unset when the base standard offer's price model does not
        // include subscription SKUs.
        FlatFee flat_fee = 2 [(google.api.field_behavior) = OPTIONAL];

        // Optional. The price configurations for the commitment based
        // subscription. Must be unset when the base standard offer's price
        // model includes subscription SKUs.
        Commitment commitment = 3 [(google.api.field_behavior) = OPTIONAL];
      }

      // Optional. The price configurations for the usage part.
      // If this field is set, the `Commitment.discount_percent` must be unset.
      // A private offer can apply a discount to all usage or to a usage
      // commitment, but not both.
      // Must be unset when the base standard offer's price model includes no
      // usage SKUs.
      Usage usage = 1 [(google.api.field_behavior) = OPTIONAL];
    }

    // Price configurations for offers with standard intervals.
    message StandardIntervalPrice {
      // The options for offers with standard intervals.
      enum StandardInterval {
        // The private offer does not have an interval.
        // If this is set, then the offer is "usage-only".
        // Field `term.duration_months` must be positive.
        STANDARD_INTERVAL_UNSPECIFIED = 0;

        // The schedule of the monthly postpay offers.
        // This type of offer has "Monthly" billing frequency (see
        // https://docs.cloud.google.com/marketplace/docs/partners/offers/select-payment-schedule).
        // No longer supported as of May 2024. Cannot be used to publish
        // new offers.
        MONTHLY_POSTPAY = 1 [deprecated = true];

        // Monthly installments with proration.
        // This type of offer has "Monthly" billing frequency (see
        // https://docs.cloud.google.com/marketplace/docs/partners/offers/select-payment-schedule).
        // For example, if the offer starts on 04/15, and the offer duration is
        // 3 months, the following installments will be created:
        // # 1: from 04/15 to 05/01, at the prorated price for April.
        //
        // # 2: from 05/01 to 06/01, at the full monthly price for May.
        //
        // # 3: from 06/01 to 07/01, at the full monthly price for June.
        //
        // # 4: from 07/01 to 07/15, at the prorated price for July.
        //
        // All dates represent the start of that day in the America/Los_Angeles
        // time zone.
        //
        // If this is set:
        //
        // * The `PriceModel.subscription` oneof must be set.
        // * Field `term.duration_months` must be positive.
        MONTHLY_PRORATED = 2;

        // Monthly installments without proration.
        // This type of offer has "Monthly" billing frequency (see
        // https://docs.cloud.google.com/marketplace/docs/partners/offers/select-payment-schedule).
        // For example, if the offer starts on 04/15, and the offer duration is
        // 3 months, the following installments will be created:
        // # 1: from 04/15 to 05/15, at the full monthly price.
        //
        // # 2: from 05/15 to 06/15, at the full monthly price.
        //
        // # 3: from 06/15 to 07/15, at the full monthly price.
        //
        // All dates represent the start of that day in the America/Los_Angeles
        // time zone.
        //
        // If this is set:
        //
        // * The `PriceModel.subscription` oneof must be set.
        // * Field `term.duration_months` must be positive.
        MONTHLY_NOT_PRORATED = 3;

        // Quarterly installments which are not prorated.
        // This type of offer has "Quarterly" billing frequency (see
        // https://docs.cloud.google.com/marketplace/docs/partners/offers/select-payment-schedule).
        // For example, if the offer starts on 01/15, and the offer duration is
        // 3 quarters, the following installments will be created:
        // # 1: from 01/15 to 04/15, at the full quarterly price.
        //
        // # 2: from 04/15 to 07/15, at the full quarterly price.
        //
        // # 3: from 07/15 to 10/15, at the full quarterly price.
        //
        // All dates represent the start of that day in the America/Los_Angeles
        // time zone.
        //
        // If this is set:
        //
        // * The `PriceModel.subscription` oneof must be set.
        // * Field `term.duration_months` must be positive.
        QUARTERLY_NOT_PRORATED = 4;

        // Yearly installments which are not prorated.
        // This type of offer has "Yearly" billing frequency (see
        // https://docs.cloud.google.com/marketplace/docs/partners/offers/select-payment-schedule).
        // For example, if the offer starts on 01/15/2025, and the offer
        // duration is 3 years, the following installments will be created:
        // # 1: from 01/15/2025 to 01/15/2026, at the full yearly price.
        //
        // # 2: from 01/15/2026 to 01/15/2027, at the full yearly price.
        //
        // # 3: from 01/15/2027 to 01/15/2028, at the full yearly price.
        //
        // All dates represent the start of that day in the America/Los_Angeles
        // time zone.
        //
        // If this is set:
        //
        // * The `PriceModel.subscription` oneof must be set.
        // * Field `term.duration_months` must be positive.
        YEARLY_NOT_PRORATED = 5;
      }

      // Optional. The standard interval of the offer.
      // Must be present to publish unless the price model is usage-only.
      StandardInterval standard_interval = 1
          [(google.api.field_behavior) = OPTIONAL];

      // Optional. The price model of the offer.
      // Must be present to publish the offer.
      PriceModel price_model = 2 [(google.api.field_behavior) = OPTIONAL];
    }

    // An installment of the offer.
    message Installment {
      // Optional. The start time of the installment.
      // Each installment must have a unique start time with one exception:
      // When the `term.start_policy` of the offer's term is `IMMEDIATE`,
      // the `start_time` of the first installment must be unset.
      // The actual start time is not recorded in the offer and instead is
      // determined by the time the resulting order became active.
      //
      // When the `term.start_policy` of the offer's term is
      // `SCHEDULED_START_TIME`, then the first installment's `start_time` must
      // match `term.scheduled_start_time`.
      //
      // If the `term.end_policy` of the offer's term is `SCHEDULED_END_TIME`,
      // then installment `start_time` must be before `term.scheduled_end_time`.
      // If it's `AFTER_DURATION`, then installment `start_time` must be before
      // the time calculated by adding the `term.duration_months` to
      // the start time of the offer.
      //
      // The `start_time` of the installments cannot be before the
      // `accept_deadline_time` of the offer.
      //
      // Installment start times must be in strictly increasing chronological
      // order.
      google.type.DateTime start_time = 1
          [(google.api.field_behavior) = OPTIONAL];

      // Optional. The price model of the installment.
      // All installments must have the same form of price model.
      PriceModel price_model = 2 [(google.api.field_behavior) = OPTIONAL];
    }

    // Price configurations for offers with custom intervals.
    message CustomIntervalPrice {
      // Optional. The installments that make up the installment timeline.
      // All installments must have the same form of price model (e.g.
      // all commitment, or all flat fee). A subscription must be present
      // under the price model for every installment.
      //
      // Must contain at least one installment to publish the offer.
      repeated Installment installments = 1
          [(google.api.field_behavior) = OPTIONAL];
    }

    // The contract value of the offer.
    message ContractValue {
      // Output only. The total contract value of the offer.
      // This will be set for all non-draft private offers, as long as
      // 'PRIVATE_OFFER_VIEW_FULL' is requested. For DRAFT private offers,
      // this will be populated only when the end user's billing account is
      // set and when the pricing and term configuration is sufficiently
      // complete to allow for a calculation.
      google.type.Money total_contract_value = 1
          [(google.api.field_behavior) = OUTPUT_ONLY];
    }

    // Revenue Share information for a Private Offer.
    // For more details about the revenue share, including how the value is
    // determined, see
    // https://docs.cloud.google.com/marketplace/docs/partners/revenue-share-scenarios.
    //
    // Not included for `PRIVATE_OFFER_VIEW_BASIC`, or for DRAFT private offers.
    //
    // For non-draft private offers, these fields are populated based on the
    // following:
    //
    // * Offers published after April 20, 2025 will always have revenue
    //   share fields populated.
    // * Offers published on or before April 20, 2025 will only have revenue
    //   share fields populated if they were associated with an active,
    //   unexpired order on that date.
    message RevenueShare {
      // Output only. The revenue share currently in effect.
      //
      // The range of the value is between 0 and 100. For example, 80
      // means the Vendor's current term revenue share is 80%. The vendor
      // will keep 80% of the revenue.
      // .
      google.type.Decimal current_term_vendor_net_revenue_percent = 1
          [(google.api.field_behavior) = OUTPUT_ONLY];

      // Output only. The expected revenue share for the renewal term.
      // Not included if the offer does not have renewal terms.
      //
      // The range of the value is between 0 and 100. For example, 80
      // means the Vendor's current term revenue share is 80%. The vendor
      // will keep 80% of the revenue after renewal.
      // .
      google.type.Decimal renewal_term_vendor_net_revenue_percent = 2
          [(google.api.field_behavior) = OUTPUT_ONLY];
    }

    // Additional contract value that represents a spend obligation or target
    // contract value tracked out-of-band by the partner.
    message AdditionalContractValue {
      // Optional. The absolute, cumulative contract value of the customer's
      // spend obligation that is added on top of the automatically billed fees
      // from Google. This amount is not automatically billed or invoiced by
      // Google; instead, it is tracked as a legal spend guarantee to be met via
      // usage reporting and manually trued-up by partners.
      //
      // The overall total contract value of the offer is calculated as the
      // sum of Google-billed fees (from installments), plus this additional
      // contract value.
      //
      // For amendments, this field must be set to the new cumulative
      // additional total.
      //
      // For example:
      //
      // * Initial Offer: 3 installments of $15 (total $45 billed by Google)
      //   plus an `additional_contract_value` of $100 (billed by Partner, with
      //   true-ups happening at the end of the offer's term).
      //   The overall total contract value of the offer is $145 ($45 + $100).
      // * Amended Offer: 6 installments of $15 (total $90 billed by Google)
      //   plus an `additional_contract_value` of $70 (billed by Partner, with
      //   true-ups happening at the end of the offer's term).
      //   The overall total contract value of the amended offer is $160
      //   ($90 + $70).
      //
      // Must be non-negative. The maximum allowed value is 1,000,000,000 USD.
      google.type.Money contract_value = 1
          [(google.api.field_behavior) = OPTIONAL];

      // Optional. The resource names of the SKUs whose tracked usage is
      // eligible to contribute toward satisfying this additional contract value
      // obligation.
      //
      // This list explicitly separates core spend obligations from exclusions
      // like overage fees, which do not count toward meeting the customer's
      // legal spend commitment.
      //
      // Must be non-empty for the offer to be published.
      //
      // Format:
      // projects/{project}/locations/{location}/services/{service}/skus/{sku}
      repeated string eligible_skus = 2 [
        (google.api.field_behavior) = OPTIONAL,
        (google.api.resource_reference) = {
          type: "commerceproducer.googleapis.com/Sku"
        }
      ];
    }

    // An existing offer to be superseded by this private offer.
    oneof amended_offer {
      // Optional. An existing private offer that will be superseded by this
      // offer. Unless the private offer is for a product type that supports
      // [multiple active
      // orders](https://cloud.google.com/marketplace/docs/partners/offers/multiple-offers),
      // an amendment private offer must be transacted if and only if the
      // destination customer billing account already contains an active order
      // for the same product. The offer to be superseded must be the offer
      // associated with an active order.
      //
      // Amendments generally fall into one of two scenarios:
      //
      // 1. **Active Order / Ended Offer**: The term of the amended offer has
      //    ended but it is still associated with an active order. The new
      //    offer must amend the ended private offer.
      // 2. **Active Order / Active Offer**: The term of the amended offer is
      //    still active and the associated order is active. Similar to above,
      //    the new offer must amend the currently active offer (unless
      //    "multiple active orders" are supported).
      //
      // If this is set, then the `base_standard_offer` parent service must
      // match the parent service of the `base_standard_offer` in the
      // `amended_private_offer`.
      //
      // **Active Term Restrictions**:
      // If the term of the amended private offer has *NOT* ended, then the
      // following compatibility rules apply:
      //
      // * **Price Model Compatibility**:
      //     * Flat Fee (with or without usage) offers can amend Flat Fee
      //       offers.
      //     * Usage-only or CUD offers can amend usage-only offers.
      //     * Commitment-based offers must amend offers of the same price
      //       model subtype (e.g., "additional usage at list price" vs "all
      //       usage discounted").
      // * **Billing Frequency Compatibility**: Determined by
      //   `standard_interval` or `custom_interval_price`.
      //     * If the amended offer has a custom billing frequency, the new
      //       offer must also have a custom frequency.
      //     * If the amended offer has a standard frequency (Monthly,
      //       Quarterly, or Yearly), the new offer must maintain the same
      //       frequency or transition to a custom frequency.
      //     * Switching between different standard frequencies (e.g., Monthly
      //       to Quarterly) is not supported.
      //     * For Monthly frequency, switching between `MONTHLY_PRORATED`
      //       and `MONTHLY_NOT_PRORATED` is supported, unless the offer's
      //       `term.end_policy` is `MATCH_AMENDED_OFFER`.
      //     * For usage-only offers, there are no billing frequency
      //       restrictions.
      //
      // Other criteria for offer amendment are detailed elsewhere.
      string amended_private_offer = 3 [
        (google.api.field_behavior) = OPTIONAL,
        (google.api.resource_reference) = {
          type: "commerceproducer.googleapis.com/PrivateOffer"
        }
      ];

      // Optional. An existing standard offer that will be superseded by this
      // offer. An amendment private offer must be transacted if the destination
      // customer billing account already contains an active order for the same
      // product, and otherwise cannot be transacted. The offer to be superseded
      // must be the offer associated with the active order.
      //
      // If this is set, then the `base_standard_offer` must contain the same
      // parent service as the parent service of the `amended_standard_offer`.
      // The price model of this offer must be compatible with the price model
      // of the `amended_standard_offer`:
      //
      // * Flat Fee, or Flat Fee with usage offers can amend Flat Fee or Flat
      //   Fee with usage standard offers.
      // * Usage-only offers, or CUD offers can amend usage-only standard
      //   offers.
      //
      // Other criteria for offer amendment are detailed elsewhere.
      string amended_standard_offer = 4 [
        (google.api.field_behavior) = OPTIONAL,
        (google.api.resource_reference) = {
          type: "commerceproducer.googleapis.com/StandardOffer"
        }
      ];
    }

    // The price of the offer.
    // A price must be set when publishing the offer.
    oneof price {
      // Optional. Price configurations for offers with standard intervals.
      // A price must be set when publishing the offer.
      StandardIntervalPrice standard_interval_price = 5
          [(google.api.field_behavior) = OPTIONAL];

      // Optional. Price configurations for offers with custom intervals.
      // Custom interval corresponds to "custom billing frequency",
      // see
      // https://docs.cloud.google.com/marketplace/docs/partners/offers/select-payment-schedule.
      // A price must be set when publishing the offer.
      CustomIntervalPrice custom_interval_price = 6
          [(google.api.field_behavior) = OPTIONAL];
    }

    // Optional. The StandardOffer this PrivateOffer is based on.
    // Must be in the same project as the private offer, and must be effective
    // at the time of publishing. Must be present to publish the offer.
    //
    // Format:
    // projects/{project}/locations/{location}/services/{service}/standardOffers/{standard_offer}
    string base_standard_offer = 1 [
      (google.api.field_behavior) = OPTIONAL,
      (google.api.resource_reference) = {
        type: "commerceproducer.googleapis.com/StandardOffer"
      }
    ];

    // Output only. The service level (also known as the 'plan') of the base
    // standard offer. The value is populated at publish time from the base
    // standard offer.
    string service_level = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Present for offers created by a reseller from a reseller
    // private offer plan (RPOP). When set, contains the ID of the originating
    // RPOP. Not included for `PRIVATE_OFFER_VIEW_BASIC`.
    string reseller_private_offer_plan_id = 10
        [(google.api.field_behavior) = OUTPUT_ONLY];

    // Optional. The custom product features to display for this offer.
    // Feature `display_name` values must be unique to publish the offer.
    // The set of features specified here should generally include all features
    // included in the base service level, with optionally customized values,
    // but is not required to match exactly and may include additional features.
    repeated Feature features = 8 [(google.api.field_behavior) = OPTIONAL];

    // Output only. The effective installment timeline of the offer.
    // Not included for `PRIVATE_OFFER_VIEW_BASIC`.
    // Included for `PRIVATE_OFFER_VIEW_FULL` if all necessary information is
    // available to generate the timeline, and if the offer has
    // 'standard_interval_price' of 'MONTHLY_PRORATED', 'MONTHLY_NOT_PRORATED',
    // 'QUARTERLY_NOT_PRORATED', or 'YEARLY_NOT_PRORATED'.
    repeated Installment effective_installment_timeline = 7
        [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Contract value of the offer.
    // Not included for `PRIVATE_OFFER_VIEW_BASIC`.
    ContractValue contract_value = 11
        [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Revenue share information for this Private Offer.
    // Not included for `PRIVATE_OFFER_VIEW_BASIC`.
    RevenueShare revenue_share = 12 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Optional. Additional contract value that the customer is legally
    // obligated to spend on the product over the duration of the offer.
    AdditionalContractValue additional_contract_value = 13
        [(google.api.field_behavior) = OPTIONAL];
  }

  // State of an offer.
  enum State {
    // Default value. This value is unused.
    STATE_UNSPECIFIED = 0;

    // The default state after creation when the offer can be edited.
    // In all other states, the contents of the offer cannot be edited.
    DRAFT = 1;

    // The offer is publishing.
    // Publishing will complete when all publishing requirements are satisfied.
    PUBLISHING = 2;

    // The offer has been published and is available to the customer to accept.
    PUBLISHED = 3;

    // The offer has been accepted by the customer.
    ACCEPTED = 4;

    // The offer was cancelled by the provider before it was transacted.
    // Cancelled offers can no longer be accepted by the customer.
    CANCELLED = 5;

    // The offer expired without being accepted by the customer.
    // Expired offers can no longer be accepted by the customer.
    EXPIRED = 6;

    // The offer has ended.
    //
    // Ended offers were accepted and active in the past, but have now reached
    // the end of their term or have been terminated.
    ENDED = 7;
  }

  // The type of the deal transacted with the offer. The deal type of an offer
  // is a factor in determining the offer's revenue share.
  enum OfferDealType {
    // Default value. This value is unused.
    OFFER_DEAL_TYPE_UNSPECIFIED = 0;

    // The offer corresponds to a preexisting commercial arrangement for a
    // workload on Google Cloud that is being transferred to the Cloud
    // Marketplace.
    CHANNEL_SHIFT = 1;

    // The offer corresponds to a preexisting commercial arrangement for a
    // workload previously not on Google Cloud that is being transferred to
    // Google Cloud.
    MIGRATION = 2;

    // The offer corresponds to a renewal of a deal initially transacted on
    // the Google Cloud Marketplace.
    NATIVE_RENEWAL = 3;

    // The offer corresponds to a new deal transacted on the Google Cloud
    // Marketplace.
    //
    // This value is not allowed if the offer amends another private offer
    // where the term has not ended, and the amended private offer has a deal
    // type of `MIGRATION`, `CHANNEL_SHIFT` or `NATIVE_RENEWAL`.
    NEW = 4;
  }

  // The content for the offer.
  // Additional forms of content may be supported in future.
  // To publish the offer a content value must be provided.
  oneof content {
    // Optional. Configurations for the offer that is associated with a single
    // product.
    SingleProductOffer single_product_offer = 12
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Identifier. Name of the resource.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. The state of the private offer.
  State state = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Information about the Google review process.
  // Present only when the offer is determined to require review by Google.
  PublishRequirementGoogleReview publish_requirement_google_review = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The creation time.
  google.protobuf.Timestamp create_time = 6
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The last update time.
  google.protobuf.Timestamp update_time = 7
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the offer transitioned to PUBLISHED state.
  google.protobuf.Timestamp publish_time = 8
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the offer transitioned to ACCEPTED state.
  google.protobuf.Timestamp accept_time = 9
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the offer transited to CANCELLED state.
  google.protobuf.Timestamp cancel_time = 10
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time when the offer ended. This can only be set for offers
  // with `ENDED` state.
  google.protobuf.Timestamp end_time = 22
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Internal note supplied when the offer was cancelled.
  // Present only for cancelled offers and only if a note was supplied.
  string cancellation_note = 11 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Information about the reseller contact.
  // Present only for offers created by a reseller.
  ResellerContact reseller_contact = 20
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Unstructured text content that is not visible to the customer.
  // Intended to be used by partners for storing notes about the private offer.
  // Maximum length: 1500 characters.
  string internal_note = 16 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The type of the deal transacted with the offer.
  //
  // The deal type is not visible to customers.
  //
  // Must be present to publish the offer.
  OfferDealType offer_deal_type = 21 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A title that describes the offer and helps your customers
  // identify it. This title will be visible to the customer. Maximum length:
  // 256 characters. Must be present to publish the offer.
  string title = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Unstructured text content that is visible to the customer.
  // Maximum length: 120 characters.
  string customer_note = 17 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Information about the partner contact.
  // Must be provided when publishing the offer.
  PartnerContact partner_contact = 14 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Information identifying the intended recipient of the offer.
  // Must be provided when publishing the offer.
  Customer customer = 13 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Deadline for acceptance of published offers.
  // A published offer not accepted by this time will expire.
  // Only day boundaries in the America/Los_Angeles time zone are supported.
  // Must be present to publish the offer.
  //
  // When publishing an offer the deadline must be set to a time in the future
  // not more than 3 months from the time of publishing. For example, if the
  // offer is published on 03/05 at 1PM, then the deadline must be at or before
  // 06/05 12AM America/Los_Angeles time.
  //
  // The deadline must also be:
  //
  // * Before or equal to the scheduled start time of this offer (if
  //   `term.scheduled_start_time` is set and the term's start policy is
  //   `SCHEDULED_START_TIME`).
  // * Before or equal to the scheduled end time of this offer, if
  //   `term.scheduled_end_time` is set and the term's end policy is
  //   `SCHEDULED_END_TIME`.
  // * Before or equal to the upcoming installment start times on this offer.
  // * Before or equal to the amended offer's end time, if the offer amends
  //   another private or standard offer.
  // * Before or equal to the start time of the next pending installment of the
  //   amended offer, if amending a private offer with custom installments. For
  //   example, if the amended offer has installments on 01/01, 02/01, 03/01,
  //   04/01, and today is 02/15, then this offer's `accept_deadline_time`
  //   must be at or before 03/01.
  //
  // In addition, if the offer amends another private offer, but there is
  // already an accepted upcoming amendment against that private offer, then
  // this deadline must be before or equal to the start time of the accepted
  // upcoming offer.
  // For example, today is 02/15, and this offer (offer C) amends private offer
  // A, and private offer B has already been accepted which also amends private
  // offer A. Private offer B has a start time of 03/01. Then this deadline
  // must be at or before 03/01. Otherwise, on 03/01, private offer B would
  // take effect, superseding offer A. This would mean offer C is no longer
  // amending the currently active offer (Offer A), which is required for
  // valid amendments.
  //
  // Once the offer is published, this field is still updatable to extend the
  // deadline of the offer. However, the extension is still limited to be
  // at most 3 months from the time of publishing.
  google.type.DateTime accept_deadline_time = 5
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Configuration for the offer term.
  // Must be set when publishing the offer.
  Term term = 15 [(google.api.field_behavior) = OPTIONAL];
}

// Message describing the PrivateOfferDocument resource.
// Used to attach documents to a private offer in state DRAFT.
// Once a private offer is no longer in state DRAFT, the set of child documents
// is immutable. Existing documents cannot be updated or deleted, and new
// documents cannot be added.
//
// A private offer must include a EULA, either by assigning a standard EULA
// or attaching a custom EULA document, or a statement of work document.
message PrivateOfferDocument {
  option (google.api.resource) = {
    type: "commerceproducer.googleapis.com/PrivateOfferDocument"
    pattern: "projects/{project}/locations/{location}/privateOffers/{private_offer}/documents/{document}"
    plural: "privateOfferDocuments"
    singular: "privateOfferDocument"
  };

  // Supported types of documents.
  // Additional document types may be added in future. Further editions of the
  // Google Cloud Marketplace Standard EULA may be published in future, which
  // may result in changes to the subset of Standard EULA versions permitted
  // to be used in new offers.
  enum DocumentType {
    // The default / unset value. Do not use.
    DOCUMENT_TYPE_UNSPECIFIED = 0;

    // The document is a custom EULA used in place of the standard product EULA.
    // A private offer may not have more than one custom EULA document.
    //
    // If this enum value is set, then mime_type and inline_content must
    // be set.
    CUSTOM_END_USER_LICENSE_AGREEMENT = 1;

    // The document is the statement of work required by the [Cloud Marketplace
    // Product Specific
    // Terms](https://cloud.google.com/terms/marketplace-product-terms) for all
    // Professional Services product private offers.
    // This document type is not permitted for private offers of any other
    // product type.
    // A private offer may not have more than one statement of work document.
    //
    // The mime_type and inline_content fields must be set.
    STATEMENT_OF_WORK = 2;

    // The document is the Marketplace standard EULA, with the following link:
    // https://cloud.google.com/terms/marketplace/eula-standard-v1-12102020.
    // Existing offers may have this document type, but this is not permitted
    // for new offers.
    STANDARD_END_USER_LICENSE_AGREEMENT_V1 = 3;

    // The document is the Marketplace standard EULA, with the following link:
    // https://cloud.google.com/terms/marketplace/eula-standard-v2-01272021
    //
    // New offers using Standard EULAs should set this enum value. This is not
    // permitted for Professional Services products.
    //
    // The mime_type and inline_content fields must not be set.
    STANDARD_END_USER_LICENSE_AGREEMENT_V2 = 4;
  }

  // Mechanism for storing the document content.
  oneof content {
    // Optional. Byte content of an unstructured document.
    // Max size: 4MB
    bytes inline_content = 6 [(google.api.field_behavior) = OPTIONAL];
  }

  // Identifier. Name of the resource.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. The creation time of the resource.
  google.protobuf.Timestamp create_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The last update time of the resource.
  google.protobuf.Timestamp update_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. The classification type of the document.
  // Used to distinguish between different types of documents that may be
  // attached to a private offer for different business purposes.
  DocumentType document_type = 4 [(google.api.field_behavior) = REQUIRED];

  // Optional. The MIME type of the document.
  // Used to distinguish between different document formats.
  // Supported formats (which may be expanded in the future)
  //
  // - 'application/pdf'
  string mime_type = 5 [(google.api.field_behavior) = OPTIONAL];
}
