Skip to content

Add shipping cost & delivery date preview composable (useShippingCost) #2498

Description

Describe the feature

Shopware 6.7.11.0 adds two new Store API endpoints (core PR shopware/shopware#15827, "delivery cost route") for calculating shipping costs without going through checkout:

  • GET /store-api/shipping-cost/product/{productId} - shipping cost + delivery window for a single product
  • GET /store-api/shipping-cost/cart - shipping cost across all available shipping methods for the current cart

Both return an array of:

{
  shippingCost: Schemas["CalculatedPrice"];
  deliveryDate: { earliest?: string; latest?: string }; // ISO date-time
  shippingMethod: Schemas["ShippingMethod"];
}[]

Notes from the spec:

  • sw-language-id is an optional header on both endpoints.
  • The product endpoint additionally supports a criteria query (criteria-based shipping method selection).

Add a composable (e.g. useShippingCost) to @shopware/composables that wraps both endpoints and exposes a reactive result.

WHY do we need that?

These endpoints are not yet exposed by @shopware/frontends - the committed Store API schema is still 6.7.10.0 (see the recurring schema-bump tickets #2444 / #2409), so neither the typed api-client nor any composable knows about them.

Wrapping them unlocks UX that today requires adding to cart / reaching checkout:

  • PDP "delivery from X, arrives by {date}" badges without a cart.
  • Cart / mini-cart shipping estimator and shipping-method comparison before login/checkout.

The two referenced schemas (CalculatedPrice, ShippingMethod) already exist in the committed schema, so the type surface is cheap to add.

Acceptance Criteria

  • The two endpoints are available in the typed api-client. Since they referenced existing component schemas, they can be added to packages/api-client/api-types/storeApiSchema.overrides.json and picked up by pnpm run generate-types (regenerating storeApiTypes.d.ts), so they survive a future full schema bump to 6.7.11.0. Generated operation keys:
    • readShippingCostByProduct get /shipping-cost/product/{productId}
    • readShippingCostsByCart get /shipping-cost/cart
  • A useShippingCost composable in packages/composables/src/useShippingCost/ exposing:
    • getProductShippingCosts(productId, criteria?)
    • getCartShippingCosts()
    • a reactive shippingCosts ref with the latest result
  • Composable exported from packages/composables/src/index.ts (auto-imported via the nuxt-module).
  • Unit tests mocking apiClient.invoke (the package enforces a 100% coverage threshold).
  • Changeset added (@shopware/api-client + @shopware/composables, patch).
  • (Optional) Usage example for a PDP delivery badge and a cart shipping estimator.

Technical notes / implementation sketch

The endpoints reference only schemas that already exist in the committed 6.7.10.0 schema (CalculatedPrice, ShippingMethod), so no new component definitions are required - just the two paths in the overrides file, then regenerate. The product endpoint's criteria group expands to the existing #/components/parameters/criteria* refs (same shape as readCountryGet get /country).

Composable shape (mirroring useCountries / useNewsletter conventions):

import { encodeForQuery } from "@shopware/api-client/helpers";
import { ref } from "vue";
import type { Ref } from "vue";
import { useShopwareContext } from "#imports";
import type { Schemas, operations } from "#shopware";

export type ShippingCostQuote =
  operations["readShippingCostsByCart get /shipping-cost/cart"]["response"][number];

/**
 * Composable for calculating shipping costs and delivery dates for a product
 * or the current cart, before checkout.
 * @public
 * @category Cart & Checkout
 */
export function useShippingCost() {
  const { apiClient } = useShopwareContext();
  const shippingCosts: Ref<ShippingCostQuote[]> = ref([]);

  async function getCartShippingCosts() {
    const { data } = await apiClient.invoke(
      "readShippingCostsByCart get /shipping-cost/cart",
    );
    shippingCosts.value = data;
    return data;
  }

  async function getProductShippingCosts(
    productId: string,
    criteria?: Schemas["Criteria"],
  ) {
    const { data } = await apiClient.invoke(
      "readShippingCostByProduct get /shipping-cost/product/{productId}",
      {
        pathParams: { productId },
        ...(criteria && { query: { _criteria: encodeForQuery(criteria) } }),
      },
    );
    shippingCosts.value = data;
    return data;
  }

  return { shippingCosts, getCartShippingCosts, getProductShippingCosts };
}

Additional information

  • I want to implement this feature.

Checks

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions