type Query {
    "List Products"
    products(options: ProductListOptions): ProductList!
    "Get a Product either by id or slug. If neither id nor slug is specified, an error will result."
    product(id: ID, slug: String): Product
    "List ProductVariants either all or for the specific product."
    productVariants(options: ProductVariantListOptions, productId: ID): ProductVariantList!
    "Get a ProductVariant by id"
    productVariant(id: ID!): ProductVariant
}

type Mutation {
    "Create a new Product"
    createProduct(input: CreateProductInput!): Product!

    "Update an existing Product"
    updateProduct(input: UpdateProductInput!): Product!

    "Update multiple existing Products"
    updateProducts(input: [UpdateProductInput!]!): [Product!]!

    "Delete a Product"
    deleteProduct(id: ID!): DeletionResponse!

    "Delete multiple Products"
    deleteProducts(ids: [ID!]!): [DeletionResponse!]!

    "Add an OptionGroup to a Product"
    addOptionGroupToProduct(productId: ID!, optionGroupId: ID!): Product!

    """
    Remove an OptionGroup from a Product. If the OptionGroup is in use by any ProductVariants
    the mutation will return a ProductOptionInUseError, and the OptionGroup will not be removed.
    Setting the `force` argument to `true` will override this and remove the OptionGroup anyway,
    as well as removing any of the group's options from the Product's ProductVariants.
    """
    removeOptionGroupFromProduct(productId: ID!, optionGroupId: ID!, force: Boolean): RemoveOptionGroupFromProductResult!

    "Create a set of ProductVariants based on the OptionGroups assigned to the given Product"
    createProductVariants(input: [CreateProductVariantInput!]!): [ProductVariant]!

    "Update existing ProductVariants"
    updateProductVariants(input: [UpdateProductVariantInput!]!): [ProductVariant]!

    "Delete a ProductVariant"
    deleteProductVariant(id: ID!): DeletionResponse!

    "Delete multiple ProductVariants"
    deleteProductVariants(ids: [ID!]!): [DeletionResponse!]!

    "Assigns all ProductVariants of Product to the specified Channel"
    assignProductsToChannel(input: AssignProductsToChannelInput!): [Product!]!

    "Removes all ProductVariants of Product from the specified Channel"
    removeProductsFromChannel(input: RemoveProductsFromChannelInput!): [Product!]!

    "Assigns ProductVariants to the specified Channel"
    assignProductVariantsToChannel(input: AssignProductVariantsToChannelInput!): [ProductVariant!]!

    "Removes ProductVariants from the specified Channel"
    removeProductVariantsFromChannel(input: RemoveProductVariantsFromChannelInput!): [ProductVariant!]!
}

input StockMovementListOptions {
    type: StockMovementType
    skip: Int
    take: Int
}

# generated by generateListOptions function
input ProductListOptions

input ProductFilterParameter {
    facetValueId: IDOperators
    sku: StringOperators
}

# generated by generateListOptions function
input ProductVariantListOptions

input ProductVariantFilterParameter {
    facetValueId: IDOperators
}

input ProductTranslationInput {
    id: ID
    languageCode: LanguageCode!
    name: String
    slug: String
    description: String
}

input CreateProductInput {
    featuredAssetId: ID
    enabled: Boolean
    assetIds: [ID!]
    facetValueIds: [ID!]
    translations: [ProductTranslationInput!]!
}

input UpdateProductInput {
    id: ID!
    enabled: Boolean
    featuredAssetId: ID
    assetIds: [ID!]
    facetValueIds: [ID!]
    translations: [ProductTranslationInput!]
}

input ProductVariantTranslationInput {
    id: ID
    languageCode: LanguageCode!
    name: String
}

input ProductOptionTranslationInput {
    id: ID
    languageCode: LanguageCode!
    name: String
}

input CreateProductVariantOptionInput {
    optionGroupId: ID!
    code: String!
    translations: [ProductOptionTranslationInput!]!
}

input StockLevelInput {
    stockLocationId: ID!
    stockOnHand: Int!
}

"""
Used to set up update the price of a ProductVariant in a particular Channel.
If the `delete` flag is `true`, the price will be deleted for the given Channel.
"""
input ProductVariantPriceInput {
    currencyCode: CurrencyCode!
    price: Money!
    delete: Boolean
}

input CreateProductVariantInput {
    productId: ID!
    translations: [ProductVariantTranslationInput!]!
    facetValueIds: [ID!]
    sku: String!
    price: Money
    taxCategoryId: ID
    optionIds: [ID!]
    featuredAssetId: ID
    assetIds: [ID!]
    stockOnHand: Int
    stockLevels: [StockLevelInput!]
    outOfStockThreshold: Int
    useGlobalOutOfStockThreshold: Boolean
    trackInventory: GlobalFlag
}

input UpdateProductVariantInput {
    id: ID!
    enabled: Boolean
    translations: [ProductVariantTranslationInput!]
    facetValueIds: [ID!]
    optionIds: [ID!]
    sku: String
    taxCategoryId: ID
    """
    Sets the price for the ProductVariant in the Channel's default currency
    """
    price: Money
    """
    Allows multiple prices to be set for the ProductVariant in different currencies.
    """
    prices: [ProductVariantPriceInput!]
    featuredAssetId: ID
    assetIds: [ID!]
    stockOnHand: Int
    stockLevels: [StockLevelInput!]
    outOfStockThreshold: Int
    useGlobalOutOfStockThreshold: Boolean
    trackInventory: GlobalFlag
}

input AssignProductsToChannelInput {
    productIds: [ID!]!
    channelId: ID!
    priceFactor: Float
}

input RemoveProductsFromChannelInput {
    productIds: [ID!]!
    channelId: ID!
}

input AssignProductVariantsToChannelInput {
    productVariantIds: [ID!]!
    channelId: ID!
    priceFactor: Float
}

input RemoveProductVariantsFromChannelInput {
    productVariantIds: [ID!]!
    channelId: ID!
}

type ProductOptionInUseError implements ErrorResult {
    errorCode: ErrorCode!
    message: String!
    optionGroupCode: String!
    productVariantCount: Int!
}

union RemoveOptionGroupFromProductResult = Product | ProductOptionInUseError
