# Alışverişe hediye ürün

> Sepetin geri kalanı bir eşiğe ulaşınca bir hediye ürünü bedava yapan Shopify indirim Function’ı. Hediye ürün sepette olmalıdır.

Sayfa: https://lintelagency.com/tr/kaynaklar/shopify-functions/alisverise-hediye-urun

## Kısaca

Bu indirim Function’ı, sepetin geri kalanı bir eşiğe (varsayılan olarak mağaza para biriminde 75) ulaşınca hediye ürünün bir adedini bedava yapar. Hediyeyi sepete ekleyemez: indirim Function’ı yalnızca sepette olan satırlara indirim uygular; ekleme işini tema, Storefront API ya da bir cart transform yapmalıdır. cart.lines.discounts.generate.run hedefini kullanır, Discount Function API 2026-10.

## Bilgiler

- **Function API:** Discount
- **Hedef (target):** cart.lines.discounts.generate.run
- **İndirim sınıfı:** PRODUCT
- **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. Hediyeyi bir ürün varyantı olarak oluşturun ve koleksiyonlarınızın dışında tutun.
2. Shopify CLI ile bir uygulama oluşturun, uzantıyı ekleyin (shopify app generate extension --template discount) ve dosyalarını aşağıdakilerle değiştirin.
3. Testleri shopify app function run --input tests/threshold-met.input.json ile çalıştırın, ardından deploy edin.
4. discountAutomaticAppCreate ile discountClasses: [PRODUCT] olan otomatik bir indirim oluşturun ve metafield’ına {"giftVariantId": "gid://shopify/ProductVariant/1234567890", "minimumAmount": 75} yazın.
5. Eşik aşıldığında hediyeyi temadan sepete ekleyin (örneğin /cart/add.js ile), sepet eşiğin altına düşünce çıkarın.

## Kod

### shopify.extension.toml

```toml
api_version = "2026-10"

[[extensions]]
name = "Free gift with purchase"
handle = "free-gift-with-purchase"
type = "function"

  [[extensions.targeting]]
  target = "cart.lines.discounts.generate.run"
  input_query = "src/cart_lines_discounts_generate_run.graphql"
  export = "cart-lines-discounts-generate-run"

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

### src/cart_lines_discounts_generate_run.graphql

```graphql
query CartLinesDiscountsGenerateRunInput {
  cart {
    lines {
      id
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        __typename
        ... on ProductVariant {
          id
        }
      }
    }
  }
  presentmentCurrencyRate
  discount {
    discountClasses
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
```

### src/cart_lines_discounts_generate_run.js

```js
// @ts-check

/**
 * @typedef {import("../generated/api").CartLinesDiscountsGenerateRunInput} CartLinesDiscountsGenerateRunInput
 * @typedef {import("../generated/api").CartLinesDiscountsGenerateRunResult} CartLinesDiscountsGenerateRunResult
 */

/**
 * Settings stored as JSON in the discount's metafield. A discount Function
 * can't add lines to the cart: the gift has to be added by the theme, the
 * Storefront API or a cart transform. This Function only makes it free.
 */
const DEFAULT_CONFIG = {
  giftVariantId: /** @type {string | null} */ (null),
  // Spend on other products, in the store's currency, that unlocks the gift.
  minimumAmount: 75,
  message: "Free gift",
};

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

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

  /** @param {(typeof input.cart.lines)[number]} line */
  const isGift = (line) => line.merchandise.__typename === "ProductVariant" && line.merchandise.id === config.giftVariantId;
  const giftLine = input.cart.lines.find(isGift);
  if (!giftLine) return NO_DISCOUNT;

  // The gift itself doesn't count towards the threshold.
  const spend = input.cart.lines
    .filter((line) => !isGift(line))
    .reduce((sum, line) => sum + Number(line.cost.subtotalAmount.amount), 0);
  if (spend < config.minimumAmount * Number(input.presentmentCurrencyRate)) return NO_DISCOUNT;

  // Only one unit is free; extra units of the gift are charged normally.
  return {
    operations: [
      {
        productDiscountsAdd: {
          candidates: [
            {
              message: config.message,
              targets: [{ cartLine: { id: giftLine.id, quantity: 1 } }],
              value: { percentage: { value: "100" } },
            },
          ],
          selectionStrategy: "FIRST",
        },
      },
    ],
  };
}
```

## Test girdisi ve beklenen çıktı

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

```json
{
  "cart": {
    "lines": [
      { "id": "gid://shopify/CartLine/1", "cost": { "subtotalAmount": { "amount": "60.0" } }, "merchandise": { "__typename": "ProductVariant", "id": "gid://shopify/ProductVariant/1111111111" } },
      { "id": "gid://shopify/CartLine/2", "cost": { "subtotalAmount": { "amount": "15.0" } }, "merchandise": { "__typename": "ProductVariant", "id": "gid://shopify/ProductVariant/1234567890" } }
    ]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": {
    "discountClasses": ["PRODUCT"],
    "metafield": { "jsonValue": { "giftVariantId": "gid://shopify/ProductVariant/1234567890", "minimumAmount": 75, "message": "Free tote bag" } }
  }
}
```

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

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

### tests/gift-not-in-cart.input.json

```json
{
  "cart": {
    "lines": [
      { "id": "gid://shopify/CartLine/1", "cost": { "subtotalAmount": { "amount": "120.0" } }, "merchandise": { "__typename": "ProductVariant", "id": "gid://shopify/ProductVariant/1111111111" } }
    ]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": {
    "discountClasses": ["PRODUCT"],
    "metafield": { "jsonValue": { "giftVariantId": "gid://shopify/ProductVariant/1234567890", "minimumAmount": 75, "message": "Free tote bag" } }
  }
}
```

### tests/gift-not-in-cart.output.json

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

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

```json
{
  "cart": {
    "lines": [
      { "id": "gid://shopify/CartLine/1", "cost": { "subtotalAmount": { "amount": "80.0" } }, "merchandise": { "__typename": "ProductVariant", "id": "gid://shopify/ProductVariant/1111111111" } },
      { "id": "gid://shopify/CartLine/2", "cost": { "subtotalAmount": { "amount": "15.0" } }, "merchandise": { "__typename": "ProductVariant", "id": "gid://shopify/ProductVariant/1234567890" } }
    ]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": {
    "discountClasses": ["PRODUCT"],
    "metafield": { "jsonValue": { "giftVariantId": "gid://shopify/ProductVariant/1234567890", "minimumAmount": 75, "message": "Free tote bag" } }
  }
}
```

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

```json
{
  "operations": [
    {
      "productDiscountsAdd": {
        "candidates": [
          {
            "message": "Free tote bag",
            "targets": [{ "cartLine": { "id": "gid://shopify/CartLine/2", "quantity": 1 } }],
            "value": { "percentage": { "value": "100" } }
          }
        ],
        "selectionStrategy": "FIRST"
      }
    }
  ]
}
```

## Sınırlar ve özel durumlar

- İndirim Function’ları sepet satırı oluşturamaz. Hediyeyi ekleyen bir tema ya da uygulama adımı yoksa hiçbir şey olmaz.
- Yalnızca bir adet bedavadır; hediyenin fazladan adetleri normal fiyattan ücretlendirilir.
- Hediyenin kendisi eşiğe sayılmaz; yani hediye, kampanyayı kendi tutarıyla tetikleyemez.

## Sorular

### Bir Shopify Function sepete bedava ürün ekleyebilir mi?

İndirim Function’ı ekleyemez; yalnızca mevcut satırlara indirim uygular. Bir cart transform, satın alınan ürünü ek bileşen satırlarına açabilir; tema ya da Storefront API de hediyeyi ayrı bir satır olarak ekleyebilir.

### Hediye eklendikten sonra müşteri ürün çıkarırsa ne olur?

Function yeniden çalışır ve hediyedeki indirimi kaldırır; hediye ücretlendirilir. Sürpriz olmasın diye temada hediyeyi çıkarın ya da müşteriye haber verin.

### Hediyeyi sipariş başına bir adetle sınırlayabilir miyim?

Evet, bu kod zaten bir adede indirim verir. Fazladan adetleri engellemek için temada da adedi sınırlayın.

## Shopify belgeleri

- [Discount Function API](https://shopify.dev/docs/api/functions/latest/discount)
- [Cart Transform Function API](https://shopify.dev/docs/api/functions/latest/cart-transform)

## İlgili içerikler

- [Bir indirim Function’ını otomatik indirim olarak etkinleştirme](https://lintelagency.com/tr/kaynaklar/graphql/function-tabanli-otomatik-indirim)
- [Paketi bileşenlerine ayırma](https://lintelagency.com/tr/kaynaklar/shopify-functions/paketi-bilesenlerine-ayirma)
- [Shopify’da Cart Transform ile ürün paketleri: Plus ne zaman gerekir?](https://lintelagency.com/tr/blog/shopify-paketleri-ve-cart-transform)
- [X alana Y indirimi](https://lintelagency.com/tr/kaynaklar/shopify-functions/x-alana-y-indirimi)

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