Ön siparişleri ayrı gönderide tutma

Etiketli ön sipariş ürünlerini ayrı bir ön sipariş lokasyonundan, stoktaki ürünleri diğer lokasyonlardan gönderen Shopify gönderim kısıtı Function’ı.

Function API
Fulfillment Constraints
Hedef (target)
cart.fulfillment-constraints.generate.run
Plan
Herkese açık uygulamada her plan; özel uygulamada Shopify Plus
Uygulama yetkisi
write_fulfillment_constraint_rules
API sürümü
2026-10
Son kontrol

Kısaca

Bu gönderim kısıtı (fulfillment constraints) Function’ı, ön sipariş ürünlerini stoktaki ürünlerden ayırır: ön sipariş etiketli ürünler ayrı bir lokasyondan, diğer her şey öteki lokasyonlarınızdan gönderilir; böylece aynı pakette beklemezler. Fulfillment Constraints API’nin cart.fulfillment-constraints.generate.run hedefini kullanır (sürüm 2026-10) ve herkese açık uygulamada her planda çalışır.

Nasıl kullanılır

  1. Ön sipariş stoku için bir lokasyon oluşturun ve ön sipariş ürünlerini etiketleyin, örneğin pre-order.
  2. Shopify CLI 4.9.0 ya da üstüyle bir uygulama oluşturun, uzantıyı ekleyin (shopify app generate extension --template fulfillment_constraints) ve dosyalarını aşağıdakilerle değiştirin.
  3. Testleri shopify app function run --input tests/mixed-cart.input.json ile çalıştırın, ardından deploy edin.
  4. fulfillmentConstraintRuleCreate ile deliveryMethodTypes: [SHIPPING] vererek etkinleştirin ve metafields içinde {"preorderTags": ["pre-order"], "preorderLocationId": "gid://shopify/Location/1234567890"} gönderin.

Kod

shopify.extension.toml
api_version = "2026-10"

[[extensions]]
name = "Keep pre-orders in a separate shipment"
handle = "pre-orders-separate-shipment"
type = "function"

  [[extensions.targeting]]
  target = "cart.fulfillment-constraints.generate.run"
  input_query = "src/cart_fulfillment_constraints_generate_run.graphql"
  input_variables = { namespace = "$app", key = "function-configuration" }
  export = "cart-fulfillment-constraints-generate-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
src/cart_fulfillment_constraints_generate_run.graphql
query CartFulfillmentConstraintsGenerateRunInput($preorderTags: [String!]) {
  cart {
    deliverableLines {
      id
      merchandise {
        __typename
        ... on ProductVariant {
          product {
            hasAnyTag(tags: $preorderTags)
          }
        }
      }
    }
  }
  locations {
    id
  }
  fulfillmentConstraintRule {
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
src/cart_fulfillment_constraints_generate_run.js
// @ts-check

/**
 * @typedef {import("../generated/api").CartFulfillmentConstraintsGenerateRunInput} CartFulfillmentConstraintsGenerateRunInput
 * @typedef {import("../generated/api").CartFulfillmentConstraintsGenerateRunResult} CartFulfillmentConstraintsGenerateRunResult
 */

/**
 * Settings stored as JSON in the rule's metafield. `preorderTags` in the same
 * JSON feeds the query variable (see input_variables in the toml), e.g.
 * { "preorderTags": ["pre-order"], "preorderLocationId": "gid://shopify/Location/1234567890" }.
 */
const DEFAULT_CONFIG = {
  // The location that holds (or will receive) pre-order stock.
  preorderLocationId: /** @type {string | null} */ (null),
};

/** @type {CartFulfillmentConstraintsGenerateRunResult} */
const NO_CONSTRAINTS = { operations: [] };

/**
 * @param {CartFulfillmentConstraintsGenerateRunInput} input
 * @returns {CartFulfillmentConstraintsGenerateRunResult}
 */
export function cartFulfillmentConstraintsGenerateRun(input) {
  const config = { ...DEFAULT_CONFIG, ...input.fulfillmentConstraintRule?.metafield?.jsonValue };
  const preorderLocationId = config.preorderLocationId;
  if (!preorderLocationId) return NO_CONSTRAINTS;

  const isPreorder = (/** @type {(typeof input.cart.deliverableLines)[number]} */ line) =>
    line.merchandise.__typename === "ProductVariant" && line.merchandise.product.hasAnyTag;
  const preorderLineIds = input.cart.deliverableLines.filter(isPreorder).map((line) => line.id);
  const inStockLineIds = input.cart.deliverableLines.filter((line) => !isPreorder(line)).map((line) => line.id);
  if (preorderLineIds.length === 0) return NO_CONSTRAINTS;

  const operations = [
    { deliverableLinesMustFulfillFromAdd: { deliverableLineIds: preorderLineIds, locationIds: [preorderLocationId] } },
  ];

  // Keeping the in-stock items away from the pre-order location is what
  // splits the order: they can no longer wait in the same package.
  const otherLocationIds = input.locations.map((location) => location.id).filter((id) => id !== preorderLocationId);
  if (inStockLineIds.length > 0 && otherLocationIds.length > 0) {
    operations.push({
      deliverableLinesMustFulfillFromAdd: { deliverableLineIds: inStockLineIds, locationIds: otherLocationIds },
    });
  }

  return { operations };
}
Test girdisi ve beklenen çıktı
tests/mixed-cart.input.json
{
  "cart": {
    "deliverableLines": [
      { "id": "gid://shopify/DeliverableCartLine/1", "merchandise": { "__typename": "ProductVariant", "product": { "hasAnyTag": false } } },
      { "id": "gid://shopify/DeliverableCartLine/2", "merchandise": { "__typename": "ProductVariant", "product": { "hasAnyTag": true } } }
    ]
  },
  "locations": [
    { "id": "gid://shopify/Location/1111111111" },
    { "id": "gid://shopify/Location/2222222222" },
    { "id": "gid://shopify/Location/3333333333" }
  ],
  "fulfillmentConstraintRule": {
    "metafield": {
      "jsonValue": { "preorderTags": ["pre-order"], "preorderLocationId": "gid://shopify/Location/3333333333" }
    }
  }
}
tests/mixed-cart.output.json
{
  "operations": [
    {
      "deliverableLinesMustFulfillFromAdd": {
        "deliverableLineIds": ["gid://shopify/DeliverableCartLine/2"],
        "locationIds": ["gid://shopify/Location/3333333333"]
      }
    },
    {
      "deliverableLinesMustFulfillFromAdd": {
        "deliverableLineIds": ["gid://shopify/DeliverableCartLine/1"],
        "locationIds": ["gid://shopify/Location/1111111111", "gid://shopify/Location/2222222222"]
      }
    }
  ]
}
tests/no-location-configured.input.json
{
  "cart": {
    "deliverableLines": [
      { "id": "gid://shopify/DeliverableCartLine/1", "merchandise": { "__typename": "ProductVariant", "product": { "hasAnyTag": true } } }
    ]
  },
  "locations": [{ "id": "gid://shopify/Location/1111111111" }],
  "fulfillmentConstraintRule": { "metafield": null }
}
tests/no-location-configured.output.json
{ "operations": [] }
tests/only-in-stock-items.input.json
{
  "cart": {
    "deliverableLines": [
      { "id": "gid://shopify/DeliverableCartLine/1", "merchandise": { "__typename": "ProductVariant", "product": { "hasAnyTag": false } } }
    ]
  },
  "locations": [
    { "id": "gid://shopify/Location/1111111111" },
    { "id": "gid://shopify/Location/2222222222" },
    { "id": "gid://shopify/Location/3333333333" }
  ],
  "fulfillmentConstraintRule": {
    "metafield": {
      "jsonValue": { "preorderTags": ["pre-order"], "preorderLocationId": "gid://shopify/Location/3333333333" }
    }
  }
}
tests/only-in-stock-items.output.json
{ "operations": [] }

Lintel tarafından yazıldı. MIT lisansı: kendi mağazanızda da müşteri işlerinizde de ücretsiz kullanabilirsiniz.

Sınırlar ve özel durumlar

  • Kısıtlı bir ürün izin verilen lokasyonlarda stokta değilse checkout kargo seçeneği göstermez ve tamamlanamaz. Ön sipariş stokunu ön sipariş lokasyonunda tutun.
  • Birbirini dışlayan kısıtlar da tüm kargo seçeneklerini kaldırır; her ürün tipini içeren sepetlerle test edin.
  • Kural, Function’ın adı ve açıklamasıyla Ayarlar › Kargo ve teslimat › Sipariş yönlendirme (Order routing) altında görünür.
  • Bir mağazada en fazla 25 gönderim kısıtı Function’ı etkin olabilir.

Sık sorulan sorular

Shopify’da ön siparişleri stoktaki ürünlerden ayrı nasıl gönderirim?
Ön sipariş stokunu ayrı bir lokasyonda tutun ve bu örnekteki gibi ön sipariş satırlarını o lokasyona, diğer satırları geri kalan lokasyonlara bağlayan bir gönderim kısıtı Function’ı kullanın.
Mağazadan teslim siparişlerine de uygulanır mı?
Yalnızca fulfillmentConstraintRuleCreate’e verdiğiniz teslimat yöntemi tiplerine uygulanır. Bu örnek SHIPPING kullanır; mağazadan teslim siparişleri kısıtlanmaz.
Ön siparişleri etiket olmadan tespit edebilir miyim?
Teslim edilebilir satırlar (deliverable lines) satış planını göstermediği için bu örnek ürün etiketi kullanır. İsterseniz bir varyant metafield’ı da işinizi görür.
  • Function API sürümü 2026-10 için yazıldı ve gösterilen tarihte Shopify’ın başvuru belgeleriyle karşılaştırıldı. Shopify her çeyrekte yeni bir sürüm yayımlar.
  • Function içeren özel (custom) uygulamalar yalnızca Shopify Plus mağazalarında çalışır. Aynı Function herkese açık bir uygulamada, sayfada aksi yazmıyorsa her planda çalışır.
  • Her örnek test verileriyle gelir ve yayımlamadan önce bu testleri çalıştırırız. Kodu değiştirdikten sonra testleri tekrar çalıştırın: shopify app function run.
  • MIT lisansı. Kodu kendi mağazanızda da müşteri işlerinizde de kullanabilirsiniz.

Mağazanız için kurulmasını, test edilmesini ve bakımını isterseniz: Shopify Functions geliştirme.

Geliştirmek istediğiniz bir şey mi var? Gelin, birlikte konuşalım.

Aynı anda sınırlı sayıda proje alıyoruz.

Gencer KarakayaShopify mühendisi

Proje özetinizi bir mühendis okur; size e-postayla yanıt veririz.