# Koleksiyon hariç, tutar üstü ücretsiz kargo

> Sepet tutarı bir sınırı aşınca ücretsiz kargo veren, hariç tutulan koleksiyonlardaki ürünleri bu tutara saymayan Shopify indirim Function’ı.

Sayfa: https://lintelagency.com/tr/kaynaklar/shopify-functions/koleksiyon-haric-tutar-ustu-ucretsiz-kargo

## Kısaca

Bu indirim Function’ı, sepet bir eşiğe (varsayılan olarak mağaza para biriminde 1.000) ulaşınca ücretsiz kargo verir; tutara yalnızca hariç tuttuğunuz koleksiyonların dışındaki ürünleri sayar. Koleksiyonlar sorguya input değişkeni olarak gider. Discount Function API’nin cart.delivery-options.discounts.generate.run hedefini kargo indirim sınıfıyla (SHIPPING) kullanır, sürüm 2026-10.

## Bilgiler

- **Function API:** Discount
- **Hedef (target):** cart.delivery-options.discounts.generate.run
- **İndirim sınıfı:** SHIPPING
- **Plan:** Herkese açık uygulamada her plan; özel uygulamada Shopify Plus
- **Uygulama yetkisi:** write_discounts
- **API sürümü:** 2026-10
- **Son kontrol:** 2 Kasım 2026

## Nasıl kullanılır

1. Shopify CLI 4.9.0 ya da üstüyle bir uygulama oluşturun ve uzantıyı ekleyin: shopify app generate extension --template discount, dil olarak JavaScript.
2. Yalnızca teslimat hedefini bırakın: shopify.extension.toml ve src/ dosyalarını aşağıdakilerle değiştirin.
3. Testleri çalıştırın: shopify app function run --input tests/above-threshold.input.json.
4. shopify app deploy ile deploy edin ve discountAutomaticAppCreate ile discountClasses: [SHIPPING] olan otomatik bir indirim oluşturun.
5. İndirimin $app:function-configuration metafield’ını ayarlayın; örneğin {"minimumAmount": 100, "excludedCollectionIds": ["gid://shopify/Collection/1234567890"]}.

## Kod

### shopify.extension.toml

```toml
api_version = "2026-10"

[[extensions]]
name = "Free shipping above a total, excluding a collection"
handle = "free-shipping-excluding-collection"
type = "function"

  [[extensions.targeting]]
  target = "cart.delivery-options.discounts.generate.run"
  input_query = "src/cart_delivery_options_discounts_generate_run.graphql"
  input_variables = { namespace = "$app", key = "function-configuration" }
  export = "cart-delivery-options-discounts-generate-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
```

### src/cart_delivery_options_discounts_generate_run.graphql

```graphql
query CartDeliveryOptionsDiscountsGenerateRunInput($excludedCollectionIds: [ID!]) {
  cart {
    lines {
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        __typename
        ... on ProductVariant {
          product {
            inAnyCollection(ids: $excludedCollectionIds)
          }
        }
      }
    }
    deliveryGroups {
      id
    }
  }
  presentmentCurrencyRate
  discount {
    discountClasses
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
```

### src/cart_delivery_options_discounts_generate_run.js

```js
// @ts-check

/**
 * @typedef {import("../generated/api").CartDeliveryOptionsDiscountsGenerateRunInput} CartDeliveryOptionsDiscountsGenerateRunInput
 * @typedef {import("../generated/api").CartDeliveryOptionsDiscountsGenerateRunResult} CartDeliveryOptionsDiscountsGenerateRunResult
 */

/**
 * Settings stored as JSON in the discount's metafield. The same metafield
 * feeds the query's $excludedCollectionIds variable (see input_variables in
 * shopify.extension.toml), so Shopify checks collection membership.
 */
const DEFAULT_CONFIG = {
  // In the store's currency; converted to the customer's currency below.
  minimumAmount: 1000,
  message: "Free shipping",
};

/** @type {CartDeliveryOptionsDiscountsGenerateRunResult} */
const NO_DISCOUNT = { operations: [] };

/**
 * @param {CartDeliveryOptionsDiscountsGenerateRunInput} input
 * @returns {CartDeliveryOptionsDiscountsGenerateRunResult}
 */
export function cartDeliveryOptionsDiscountsGenerateRun(input) {
  // A Function may only return operations for the classes the discount was created with.
  if (!input.discount.discountClasses.includes("SHIPPING")) return NO_DISCOUNT;
  const config = { ...DEFAULT_CONFIG, ...input.discount.metafield?.jsonValue };

  // Products in an excluded collection (gift cards, sale items, oversized goods)
  // don't count towards the threshold.
  const qualifyingSubtotal = input.cart.lines
    .filter((line) => !(line.merchandise.__typename === "ProductVariant" && line.merchandise.product.inAnyCollection))
    .reduce((sum, line) => sum + Number(line.cost.subtotalAmount.amount), 0);
  const minimum = config.minimumAmount * Number(input.presentmentCurrencyRate);
  if (qualifyingSubtotal < minimum || input.cart.deliveryGroups.length === 0) return NO_DISCOUNT;

  return {
    operations: [
      {
        deliveryDiscountsAdd: {
          candidates: [
            {
              message: config.message,
              targets: input.cart.deliveryGroups.map((group) => ({ deliveryGroup: { id: group.id } })),
              value: { percentage: { value: "100" } },
            },
          ],
          selectionStrategy: "ALL",
        },
      },
    ],
  };
}
```

## Test girdisi ve beklenen çıktı

### tests/above-threshold.input.json

```json
{
  "cart": {
    "lines": [
      { "cost": { "subtotalAmount": { "amount": "80.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } },
      { "cost": { "subtotalAmount": { "amount": "35.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } }
    ],
    "deliveryGroups": [{ "id": "gid://shopify/CartDeliveryGroup/1" }]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": {
    "discountClasses": ["SHIPPING"],
    "metafield": { "jsonValue": { "minimumAmount": 100, "excludedCollectionIds": ["gid://shopify/Collection/1234567890"] } }
  }
}
```

### tests/above-threshold.output.json

```json
{
  "operations": [
    {
      "deliveryDiscountsAdd": {
        "candidates": [
          {
            "message": "Free shipping",
            "targets": [{ "deliveryGroup": { "id": "gid://shopify/CartDeliveryGroup/1" } }],
            "value": { "percentage": { "value": "100" } }
          }
        ],
        "selectionStrategy": "ALL"
      }
    }
  ]
}
```

### tests/excluded-items-dont-count.input.json

```json
{
  "cart": {
    "lines": [
      { "cost": { "subtotalAmount": { "amount": "80.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } },
      { "cost": { "subtotalAmount": { "amount": "60.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": true } } }
    ],
    "deliveryGroups": [{ "id": "gid://shopify/CartDeliveryGroup/1" }]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": {
    "discountClasses": ["SHIPPING"],
    "metafield": { "jsonValue": { "minimumAmount": 100, "excludedCollectionIds": ["gid://shopify/Collection/1234567890"] } }
  }
}
```

### tests/excluded-items-dont-count.output.json

```json
{ "operations": [] }
```

### tests/no-shipping-class.input.json

```json
{
  "cart": {
    "lines": [
      { "cost": { "subtotalAmount": { "amount": "1500.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } }
    ],
    "deliveryGroups": [{ "id": "gid://shopify/CartDeliveryGroup/1" }]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": { "discountClasses": ["ORDER"], "metafield": null }
}
```

### tests/no-shipping-class.output.json

```json
{ "operations": [] }
```

## Sınırlar ve özel durumlar

- Satır ara toplamları müşterinin para birimindedir; minimum presentmentCurrencyRate ile çevrilir.
- İndirim her teslimat grubuna, gruptaki tüm seçeneklerle birlikte uygulanır. Yalnızca en ucuz seçeneğe vermek için deliveryOption handle’larını hedefleyin.
- Liste tipindeki bir input değişkeni en fazla 100 koleksiyon kimliği alabilir.

## Sorular

### Shopify’da ücretsiz kargo sınırından bazı ürünleri nasıl hariç tutarım?

Bu örnekteki gibi, toplamı hesaplarken seçtiğiniz koleksiyonlardaki satırları dışarıda bırakan bir kargo indirimi Function’ı kullanın.

### Ücretsiz kargo yalnızca standart gönderime uygulanabilir mi?

Evet. deliveryOptions’ı handle ve title ile sorgulayın ve yalnızca eşleşen seçeneği deliveryOption: {handle} ile hedefleyin.

### Eşik birden fazla para birimiyle çalışır mı?

Evet. Eşiği mağaza para biriminde belirleyin; Function sepetle karşılaştırmadan önce onu presentmentCurrencyRate ile çarpar.

## Shopify belgeleri

- [Discount Function API](https://shopify.dev/docs/api/functions/latest/discount)
- [Variables in input queries](https://shopify.dev/docs/apps/build/functions/input-queries/use-variables-input-queries)

## İlgili içerikler

- [Bir indirim Function’ını otomatik indirim olarak etkinleştirme](https://lintelagency.com/tr/kaynaklar/graphql/function-tabanli-otomatik-indirim)
- [Metafield ile ayarlanan tek bir indirim Function’ı](https://lintelagency.com/tr/kaynaklar/shopify-functions/metafield-ile-ayarlanan-indirim)
- [Tek bir Shopify mağazasından birçok para biriminde satış](https://lintelagency.com/tr/blog/shopify-markets-ile-coklu-para-birimi)
- [Function’ları metafield (meta alan) ile yapılandırmak: kuralı yeni sürüm yayınlamadan değiştirin](https://lintelagency.com/tr/blog/shopify-functions-metafield-ile-yapilandirma)

Lisans: MIT. Kendi mağazanızda da müşteri işlerinizde de ücretsiz kullanabilirsiniz.
