########################
## Fulfillment
########################

"Information needed by the selected fulfillment method to properly fulfill the order"
type FulfillmentData {
  "The mailing address to which this fulfillment group should be shipped"
  shippingAddress: Address
}

"A fulfillment option for a cart fulfillment group, which is a method with an associated price"
type FulfillmentOption {
  "The fulfillment method this pricing is for"
  fulfillmentMethod: FulfillmentMethod

  "The additional amount charged for handling"
  handlingPrice: Money!

  "The base price charged"
  price: Money!
}

"""
Links one or more cart items to fulfillment data. The most common example is having one FulfillmentGroup
per shipping address.
"""
type FulfillmentGroup implements Node {
  "The fulfillment ID"
  _id: ID!

  """
  The list of fulfillment options from which the shopper may choose. This list is created by taking
  the full list of registered fulfillment methods, keeping only those that match the fulfillment `type`
  of this group, and then calculating a price and handlingPrice for each based on the `items` in this group.
  """
  availableFulfillmentOptions: [FulfillmentOption]!

  "Information needed by the fulfillment type to properly fulfill the order"
  data: FulfillmentData

  # DB would store only an array of cart item ID
  "The items that are included in this fulfillment group"
  items: [CartItem]!

  "The fulfillment method selected by a shopper for this group, with its associated price"
  selectedFulfillmentOption: FulfillmentOption

  "The shipping address collected for this group, if relevant"
  shippingAddress: Address

  "The shop that owns the items in this group and is responsible for fulfillment"
  shop: Shop!

  """
  The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital`
  """
  type: FulfillmentType!
}

"Input needed when setting the shipping address on a cart"
input SetShippingAddressOnCartInput {
  "The shipping address"
  address: AddressInput!

  "If set, this will be saved as the Address._id. Otherwise an ID will be generated."
  addressId: String

  "The cart to set shipping address on"
  cartId: ID!

  "The token for the cart, required if it is an anonymous cart"
  cartToken: String

  "An optional string identifying the mutation call, which will be returned in the response payload"
  clientMutationId: String
}

"The response from the `setShippingAddressOnCart` mutation"
type SetShippingAddressOnCartPayload {
  "The updated Cart"
  cart: Cart!

  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String
}

"A request to update the available fulfillment options for a single fulfillment group"
input UpdateFulfillmentOptionsForGroupInput {
  "The cart to update fulfillment options for"
  cartId: ID!

  "The token for the cart, required if it is an anonymous cart"
  cartToken: String

  "An optional string identifying the mutation call, which will be returned in the response payload"
  clientMutationId: String

  "The group to update fulfillment options for"
  fulfillmentGroupId: ID!
}

"The response from the `updateFulfillmentOptionsForGroup` mutation"
type UpdateFulfillmentOptionsForGroupPayload {
  "The updated Cart"
  cart: Cart!

  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String
}

"Input needed to select a fulfillment option for a single fulfillment group on a cart"
input SelectFulfillmentOptionForGroupInput {
  "The cart to select this option for"
  cartId: ID!

  "The token for the cart, required if it is an anonymous cart"
  cartToken: String

  "An optional string identifying the mutation call, which will be returned in the response payload"
  clientMutationId: String

  "The group to select this option for"
  fulfillmentGroupId: ID!

  "The fulfillment method ID from the option the shopper selected"
  fulfillmentMethodId: ID!
}

"The response from the `selectFulfillmentOptionForGroup` mutation"
type SelectFulfillmentOptionForGroupPayload {
  "The updated Cart"
  cart: Cart!

  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String
}

########################
## General
########################

"A summary of the totals for this cart"
type CartSummary {
  "The total of all discounts applied, as a positive number"
  discountTotal: Money!

  """
  The calculated tax-exclusive tax rate on all items and fulfillment prices (taxTotal / taxableAmount).
  This may be null, and there is a difference between null and 0. Null means `not able to calculate`,
  such as when no fulfillment method has been selected for some fulfillment groups.
  """
  effectiveTaxRate: Rate

  """
  The total price of all chosen fulfillment methods. This may be null, and there is a difference
  between null and 0. Null means `not able to calculate`, such as when no fulfillment method has
  been selected for some fulfillment groups.
  """
  fulfillmentTotal: Money

  "The combined prices of all cart items"
  itemTotal: Money!

  """
  The total estimated tax that has not already been included in the item prices. This may be null,
  and there is a difference between null and 0. Null means `not able to calculate`, such as when no
  fulfillment methods have been selected or there is some other issue with the tax service.
  """
  taxTotal: Money

  "The total amount that was deemed taxable by the tax service"
  taxableAmount: Money!

  "The sum of `itemTotal`, `fulfillmentTotal`, and `taxTotal`, minus `discountTotal`"
  total: Money!
}

"Holds all information collected for a cart during checkout"
type Checkout {
  "One or more fulfillment groups, for example, mapping certain items to certain shipping addresses"
  fulfillmentGroups: [FulfillmentGroup]!

  "A summary of the totals for this cart"
  summary: CartSummary!
}

extend type Mutation {
  "Select a fulfillment option from the `availableFulfillmentOptions` list for a fulfillment group"
  selectFulfillmentOptionForGroup(
    "Mutation input"
    input: SelectFulfillmentOptionForGroupInput!
  ): SelectFulfillmentOptionForGroupPayload!

  "Set the shipping address for all fulfillment groups"
  setShippingAddressOnCart(
    "Mutation input"
    input: SetShippingAddressOnCartInput!
  ): SetShippingAddressOnCartPayload!

  """
  Clients should call this as necessary during checkout to update the `availableFulfillmentOptions`
  property for all fulfillment groups of the cart with fresh price quotes. These need to be
  recalculated every time the items in that group change. When the order is placed, the chosen
  option for each group will have its prices recalculated one last time. If the prices do not match,
  order creation will fail.
  """
  updateFulfillmentOptionsForGroup(
    "Mutation input"
    input: UpdateFulfillmentOptionsForGroupInput!
  ): UpdateFulfillmentOptionsForGroupPayload!
}
