> ## 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 для чтения и изменения корзины: открытие, закрытие, добавление, удаление, обновление количества, замена варианта, чтение состояния и форматирование денег.

Действия **читают и изменяют корзину**. Они находятся в `window.aftersell.cart.actions`.

<Note>
  Действия выполняются **после готовности корзины**, внутри `ready()` или обработчика [события](/ru/aftersell/cart/sdk-events).
</Note>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.ready().then(() => {
  const state = window.aftersell.cart.actions.getCart();
  console.log(state.itemCount, 'items');
});
```

<Note>
  **До загрузки корзины действия являются заглушками.** Каждое из них выводит в консоль предупреждение с именем действия, например `cart.actions.addItem() called before the cart loaded`, и ничего не делает. Асинхронные действия всё равно разрешают Promise, поэтому цепочка `.then()` выполняется нормально, а не выбрасывает исключение; `getCart()` возвращает `null`, а `formatMoney()` возвращает пустую строку.

  Ничего не ломается, если вызвать действие слишком рано, но и ничего не происходит. Следите за этим предупреждением в консоли, когда действие как будто ничего не делает.
</Note>

<div id="every-action">
  ## Все действия
</div>

| Действие                                                 | Сигнатура                            | Возвращает              | Что делает                              |
| -------------------------------------------------------- | ------------------------------------ | ----------------------- | --------------------------------------- |
| [`open`](#open-and-close)                                | `open()`                             | Нет                     | Открывает drawer.                       |
| [`close`](#open-and-close)                               | `close()`                            | Нет                     | Закрывает drawer.                       |
| [`getCart`](#getcart)                                    | `getCart()`                          | `AftersellCart \| null` | Читает текущую корзину.                 |
| [`formatMoney`](#formatmoneycents)                       | `formatMoney(cents)`                 | `string`                | Форматирует сумму для отображения.      |
| [`addItem`](#additemvariantid-quantity)                  | `addItem(variantId, quantity?)`      | `Promise`               | Добавляет вариант.                      |
| [`removeItem`](#removeitemkey)                           | `removeItem(key)`                    | `Promise`               | Удаляет позицию.                        |
| [`updateItemQuantity`](#updateitemquantitykey-quantity)  | `updateItemQuantity(key, quantity)`  | `Promise`               | Устанавливает количество позиции.       |
| [`replaceLineVariant`](#replacelinevariantkey-variantid) | `replaceLineVariant(key, variantId)` | `Promise`               | Меняет вариант позиции.                 |
| [`refresh`](#refresh)                                    | `refresh()`                          | `Promise`               | Повторно запрашивает корзину у Shopify. |
| [`visualRefresh`](#visualrefresh)                        | `visualRefresh()`                    | Нет                     | Перерисовывает без повторного запроса.  |

<Warning>
  Вызов действия из обработчика `cart_updated` может зациклиться. Сначала прочитайте [два правила](/ru/aftersell/cart/sdk-events#the-two-rules).
</Warning>

***

<div id="drawer">
  ## Drawer
</div>

<div id="open-and-close">
  ### open и close
</div>

Открывают или закрывают drawer-корзину. Оба синхронны и не принимают аргументов.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Open the drawer from your own cart link.
document.querySelector('#my-cart-link').addEventListener('click', (event) => {
  event.preventDefault();
  window.aftersell.cart.actions.open();
});
```

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Close it after the shopper does something in a custom block.
window.aftersell.cart.actions.close();
```

***

<div id="reading">
  ## Чтение
</div>

<div id="getcart">
  ### getCart()
</div>

Возвращает текущий [объект корзины](/ru/aftersell/cart/sdk-cart-object) или `null` до его загрузки. Результат является **копией**, поэтому его изменение не повлияет на настоящую корзину.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.ready().then(() => {
  const state = window.aftersell.cart.actions.getCart();
  if (!state) return; // the initial load failed

  console.log(state.itemCount, 'items,', state.items.length, 'lines');
  console.log('Total:', window.aftersell.cart.actions.formatMoney(state.totalPrice));
});
```

Поскольку это снимок состояния, не храните результат; читайте его заново каждый раз, когда вам нужны актуальные данные. В обработчике события у вас уже есть свежая корзина в качестве payload, поэтому `getCart()` там избыточен.

<div id="formatmoneycents">
  ### formatMoney(cents)
</div>

Форматирует сумму в минимальных денежных единицах, используя денежный формат вашего магазина. Каждая цена в SDK указана в центах, поэтому именно так вы превращаете её в то, что можно отобразить.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.actions.formatMoney(5779);  // "$57.79"
window.aftersell.cart.actions.formatMoney(0);     // "$0.00"
```

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Show the cart total in your own header element.
window.aftersell.cart.events.on('cart_updated', (state) => {
  document.querySelector('#header-total').textContent =
    window.aftersell.cart.actions.formatMoney(state.totalPrice);
});
```

Переопределите формат с помощью [`configure({ money_format })`](/ru/aftersell/cart/sdk-configure#money_format).

***

<div id="changing-the-cart">
  ## Изменение корзины
</div>

<Note>
  Действия с позициями идентифицируют позицию по её Shopify **`key`**, а не по ID варианта, потому что корзина может содержать один и тот же вариант в нескольких позициях с разными свойствами. Читайте его из `getCart().items[n].key`.
</Note>

<div id="additemvariantid-quantity">
  ### addItem(variantId, quantity?)
</div>

Добавляет вариант в корзину. `quantity` по умолчанию равен `1`. Разрешается, когда корзина стабилизируется.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Add one, then show the shopper.
window.aftersell.cart.actions.addItem(41720671830082).then(() => {
  window.aftersell.cart.actions.open();
});
```

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Add a specific quantity.
window.aftersell.cart.actions.addItem(41720671830082, 3);
```

Добавление варианта, уже находящегося в корзине, увеличивает количество этой позиции, а не создаёт вторую, при условии что существующая позиция не имеет свойств line item. Позиция со свойствами является отдельной позицией, поэтому вы получите новую.

<div id="removeitemkey">
  ### removeItem(key)
</div>

Полностью удаляет позицию.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Remove any free line from the cart.
const gift = window.aftersell.cart.actions
  .getCart()
  .items.find((line) => line.finalLinePrice === 0);
if (gift) window.aftersell.cart.actions.removeItem(gift.key);
```

<div id="updateitemquantitykey-quantity">
  ### updateItemQuantity(key, quantity)
</div>

Устанавливает количество позиции. Передача `0` удаляет позицию.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const line = window.aftersell.cart.actions.getCart().items[0];
if (line) window.aftersell.cart.actions.updateItemQuantity(line.key, 3);
```

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Cap a line at one unit.
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    if (line.variantId === LIMITED_VARIANT_ID && line.quantity > 1) {
      window.aftersell.cart.actions.updateItemQuantity(line.key, 1);
    }
  });
});
```

Второй пример безопасно запускать из `cart_updated`, потому что проверка `> 1` даёт false при втором проходе. См. [два правила](/ru/aftersell/cart/sdk-events#the-two-rules).

<div id="replacelinevariantkey-variantid">
  ### replaceLineVariant(key, variantId)
</div>

Меняет вариант позиции, сохраняя её количество и свойства. Полезно для переключателя размера или вкуса внутри корзины.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const line = window.aftersell.cart.actions.getCart().items[0];
window.aftersell.cart.actions.replaceLineVariant(line.key, 41720671862850);
```

<Warning>
  При замене **план продаж позиции сбрасывается**. Позиция подписки становится разовой покупкой, если вы не примените план заново.
</Warning>

Замена — это добавление с последующим удалением, а не редактирование на месте, поэтому результатом является **новая позиция**: она получает новый `key` и оказывается в конце корзины. После этого заново прочитайте `getCart()` вместо повторного использования переданного вами ключа.

***

<div id="refreshing">
  ## Обновление
</div>

<div id="refresh">
  ### refresh()
</div>

Повторно запрашивает корзину у Shopify. Используйте его после того, как что-то вне SDK изменило корзину, а drawer этого не заметил.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// After a raw Ajax API call of your own.
fetch('/cart/add.js', { method: 'POST', /* … */ })
  .then(() => window.aftersell.cart.actions.refresh())
  .then(() => { window.aftersell.cart.actions.open(); });
```

В большинстве случаев это не нужно, поскольку Aftersell уже слушает стандартные события корзины Shopify и повторно запрашивает данные самостоятельно. Прибегайте к этому, когда пользовательская интеграция обходит их.

<div id="visualrefresh">
  ### visualRefresh()
</div>

Повторно выполняет трансформации отрисовки без повторного запроса корзины у Shopify. Он редко нужен: регистрация (или отмена регистрации) [трансформации позиций](/ru/aftersell/cart/sdk-hooks#registerlinetransform), [компаратора](/ru/aftersell/cart/sdk-hooks#registerlinecomparator), [обогатителя](/ru/aftersell/cart/sdk-hooks#registercartenricher) или любого из [хуков подписки](/ru/aftersell/cart/sdk-hooks#registersubscriptionoptionstransform) запускает его за вас. Только два хука добавления в корзину этого не делают, поскольку они не меняют ничего из уже отображённого на экране.

Прибегайте к нему, когда меняется то, *от чего зависит* трансформация, но сама корзина не изменилась:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// A currency switcher changed the format: repaint prices already on screen.
window.myTheme.onCurrencyChange((currency) => {
  window.aftersell.cart.configure({ money_format: FORMATS[currency] });
  window.aftersell.cart.actions.visualRefresh();
});
```

***

<div id="notes-and-edge-cases">
  ## Замечания и особые случаи
</div>

* **Асинхронные действия разрешаются, когда изменение стабилизируется.** Ожидание одного из них позволяет выстроить последовательность работы после фактического обновления корзины.
* **`getCart()` возвращает копию.** Её изменение никак не влияет на настоящую корзину.
* **Нет действия для промокодов.** Применённые коды доступны для чтения в корзине (`discountCodes`, `totalDiscount`) и по позициям (`discountAllocations`); покупатели применяют их через блок [Discount code](/ru/aftersell/cart/discount-code-block).
* **Нет действия для атрибутов корзины или примечаний.** Атрибуты доступны для чтения в объекте корзины; покупатели пишут примечания через блок [Notes](/ru/aftersell/cart/notes-block).
* **Чтобы скрыть позицию, а не удалить её**, используйте [`registerLineTransform`](/ru/aftersell/cart/sdk-hooks#registerlinetransform). Удаление меняет итоговую сумму покупателя; скрытие — нет.

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

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