> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Объект корзины

> Структура корзины Aftersell Cart SDK и её позиций: каждое поле корзины, позиции корзины, комплекты и планы продаж.

Одна структура объекта проходит через весь SDK. Это то, что возвращает [`getCart()`](/ru/aftersell/cart/sdk-actions#getcart), что [`cart_loaded` и `cart_updated`](/ru/aftersell/cart/sdk-events) передают вашему обработчику и что получает [блок Custom code](/ru/aftersell/cart/custom-code-blocks).

<Note>
  **Все денежные суммы указаны в минимальных единицах валюты** (центы для USD), никогда — в виде отформатированной строки. `5779` — это \$57.79. Используйте [`formatMoney`](/ru/aftersell/cart/sdk-actions#formatmoneycents) для отображения.
</Note>

<div id="the-cart">
  ## Корзина
</div>

| Поле                   | Тип                      | Описание                                                                                                                                                  |
| ---------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `token`                | `string`                 | Токен корзины Shopify.                                                                                                                                    |
| `items`                | `AftersellCartLine[]`    | Позиции корзины. См. [позиции корзины](#cart-lines).                                                                                                      |
| `itemCount`            | `number`                 | Общее количество товаров, как его видит покупатель.                                                                                                       |
| `hasSubscriptionItems` | `boolean`                | `true`, когда хотя бы одна позиция в `items` имеет план продаж, включая позиции-дополнения, которые `itemCount` не учитывает. `false` для пустой корзины. |
| `totalPrice`           | `number`                 | Текущая итоговая сумма, в центах.                                                                                                                         |
| `originalTotalPrice`   | `number`                 | Итоговая сумма до скидок, в центах.                                                                                                                       |
| `totalDiscount`        | `number`                 | Сумма скидок, в центах.                                                                                                                                   |
| `compareAtTotalPrice`  | `number \| null`         | Сумма compare-at (MSRP) каждой позиции × количество, в центах. `null`, если недоступно — тогда используйте `originalTotalPrice`.                          |
| `currency`             | `string`                 | Код валюты.                                                                                                                                               |
| `discountCodes`        | `string[]`               | Промокоды, принятые в корзине, отсортированы. `[]`, если их нет.                                                                                          |
| `attributes`           | `Record<string, string>` | Атрибуты корзины. Только для чтения из SDK.                                                                                                               |

<Warning>
  **`itemCount` не всегда равен сумме `items`.** `items` отражает реальную корзину Shopify, включая позиции-дополнения, которые drawer скрывает, например защиту доставки. `itemCount` — это число для покупателя, соответствующее значку корзины. Для «сколько вещей выбрал покупатель» используйте `itemCount`; для перебора позиций, которые отрисовывает корзина, используйте `items`.

  Две вещи полностью отсутствуют в `items`: позиции, скрытые через [`setHidden`](/ru/aftersell/cart/sdk-hooks#registerlinetransform), и [дочерние позиции комплектов](#bundles), которые переносятся на свой якорь. Обе всё равно учитываются в итогах корзины, которые приходят напрямую из Shopify.
</Warning>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_updated', (state) => {
  console.log(state.itemCount, 'items');
  console.log('Total:', window.aftersell.cart.actions.formatMoney(state.totalPrice));
  console.log('Saved:', window.aftersell.cart.actions.formatMoney(state.totalDiscount));
  console.log('Codes:', state.discountCodes.join(', ') || 'none');
});
```

<div id="cart-lines">
  ## Позиции корзины
</div>

Каждая запись в `items`, а также `item` в [`item_added`](/ru/aftersell/cart/sdk-events#item_added) и [`item_removed`](/ru/aftersell/cart/sdk-events#item_removed):

| Поле                  | Тип                              | Описание                                                                                                                                                              |
| --------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `key`                 | `string`                         | Ключ позиции в Shopify. Передавайте его в [действия](/ru/aftersell/cart/sdk-actions) с позициями.                                                                     |
| `productId`           | `number`                         | ID товара Shopify.                                                                                                                                                    |
| `variantId`           | `number`                         | ID варианта Shopify.                                                                                                                                                  |
| `handle`              | `string`                         | Handle товара.                                                                                                                                                        |
| `title`               | `string`                         | Отображаемое название.                                                                                                                                                |
| `productTitle`        | `string`                         | Название товара без варианта.                                                                                                                                         |
| `variantTitle`        | `string \| null`                 | Надпись варианта или `null`.                                                                                                                                          |
| `variantOptions`      | `Array<{ name, value }>`         | Выбранные опции, например `[{ name: 'Size', value: 'Medium' }]`. Shopify выдаёт `Title: Default Title` для товара с единственным вариантом.                           |
| `quantity`            | `number`                         | Количество этой позиции.                                                                                                                                              |
| `linePrice`           | `number`                         | Цена позиции, в центах.                                                                                                                                               |
| `finalLinePrice`      | `number`                         | Цена позиции после скидок, в центах.                                                                                                                                  |
| `originalLinePrice`   | `number`                         | Цена позиции до скидок, в центах.                                                                                                                                     |
| `compareAtPrice`      | `number \| null`                 | Compare-at (MSRP) варианта **за единицу**, в центах. `null`, если отсутствует.                                                                                        |
| `properties`          | `Record<string, string> \| null` | Свойства line item.                                                                                                                                                   |
| `internalProperties`  | `Record<string, string>`         | Слой только для отрисовки из [`registerLineTransform`](/ru/aftersell/cart/sdk-hooks#registerlinetransform). Никогда не сохраняется в Shopify. `{}`, если отсутствует. |
| `discountAllocations` | `Array<{ title, amount }>`       | Скидки, применённые к этой позиции. `amount` в центах. `[]`, если их нет.                                                                                             |
| `isGiftCard`          | `boolean`                        | Является ли позиция подарочной картой.                                                                                                                                |
| `sellingPlan`         | `{ id, name } \| null`           | Активный план подписки или `null` для разовой покупки.                                                                                                                |
| `bundle`              | `AftersellCartBundle \| null`    | Модель представления [комплекта](#bundles) на якорной позиции; `null` для позиций вне комплектов и дочерних позиций.                                                  |
| `metadata`            | `Record<string, unknown>`        | Данные [обогащения](/ru/aftersell/cart/sdk-hooks#registercartenricher) с ключами по `id` обогатителя. `{}`, пока обогатитель их не заполнит.                          |

<Warning>
  `properties` может содержать введённые покупателем данные, например поле пользовательского текста из формы товара. Отображайте их как текст, никогда — как необработанный HTML.
</Warning>

<div id="identifying-a-line">
  ### Идентификация позиции
</div>

Используйте `key` для всего, что действует на позицию, и `variantId` или `productId` для всего, что идентифицирует *товар*:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// ✅ Acting on a line: use key.
window.aftersell.cart.actions.removeItem(line.key);

// ✅ Recognising a product: use variantId.
const hasGift = state.items.some((line) => line.variantId === GIFT_VARIANT_ID);
```

Один и тот же вариант может присутствовать в нескольких позициях, когда свойства различаются. Две кружки с гравировкой с разными текстами гравировки — это две позиции с одним `variantId`. Именно поэтому действия принимают `key`.

<div id="prices-on-a-line">
  ### Цены позиции
</div>

Три цены, которые легко перепутать:

| Нужно                                | Используйте                   |
| ------------------------------------ | ----------------------------- |
| Что покупатель платит за эту позицию | `finalLinePrice`              |
| Сколько она стоила до скидок корзины | `originalLinePrice`           |
| Зачёркнутая цена MSRP, за единицу    | `compareAtPrice` × `quantity` |

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Is this line discounted?
const isDiscounted = line.finalLinePrice < line.originalLinePrice;

// Is it free? (A common way to detect a gift line.)
const isFree = line.finalLinePrice === 0;
```

<div id="bundles">
  ## Комплекты
</div>

Когда позиции сгруппированы в комплект, **якорная** позиция несёт объект `bundle`. Дочерние позиции сворачиваются в него и больше не появляются в `items` самостоятельно. О том, как настраивается группировка, см. [Группировка позиций комплектов из другого приложения](/ru/aftersell/cart/sdk-use-case-bundles).

| Поле           | Тип                      | Описание                                                          |
| -------------- | ------------------------ | ----------------------------------------------------------------- |
| `id`           | `string`                 | Идентификатор комплекта.                                          |
| `source`       | `'native' \| 'grouped'`  | Нативный комплект Shopify или позиции, сгруппированные Aftersell. |
| `memberKeys`   | `string[]`               | `key` каждой позиции в комплекте.                                 |
| `children`     | `AftersellBundleChild[]` | Содержимое комплекта.                                             |
| `displayPrice` | `number`                 | Цена, отображаемая для комплекта, в центах.                       |

Каждая дочерняя позиция несёт `key` (`null` для нативного компонента), `title`, `variantTitle`, `quantity`, `perAnchorQty`, `imageUrl`, `finalLinePrice`, `originalLinePrice` и `compareAtPrice`.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Skip bundle children when totalling your own line list.
const topLevel = state.items.filter((line) => !isBundleChild(line, state));
```

<div id="subscription-plans">
  ## Планы подписки
</div>

Активный план позиции — `sellingPlan`, или `null` для разовой покупки. Для ответа по всей корзине читайте `hasSubscriptionItems`, а не сканируйте позиции самостоятельно, поскольку он также учитывает позиции-дополнения, которые `items` показывает, но `itemCount` пропускает:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
if (state.hasSubscriptionItems) {
  // The cart contains at least one subscription line.
}

const subscriptions = state.items.filter((line) => line.sellingPlan);
console.log(subscriptions.length, 'subscription lines');
```

*Доступные* планы позиции, те, что в селекторе, отсутствуют в объекте корзины. Формируйте их с помощью [`registerSubscriptionOptionsTransform`](/ru/aftersell/cart/sdk-hooks#registersubscriptionoptionstransform) и [`registerDefaultSubscriptionOptionSelector`](/ru/aftersell/cart/sdk-hooks#registerdefaultsubscriptionoptionselector).

<div id="where-to-go-next">
  ## Что дальше
</div>

* **[Действия](/ru/aftersell/cart/sdk-actions)**: чтение и изменение корзины.
* **[События](/ru/aftersell/cart/sdk-events)**: откуда приходит этот объект.
* **[Хуки](/ru/aftersell/cart/sdk-hooks)**: добавьте собственные данные к позиции с помощью обогатителя.
* **[Сценарии использования](/ru/aftersell/cart/sdk-use-cases)**: полные решения, читающие эти поля.
