> ## 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.

# Raggruppa le righe di bundle di un'altra app

> Usa setInternalProperties per dire all'Aftersell Cart quali righe appartengono allo stesso bundle, così vengono renderizzate come un unico articolo invece che come varie righe scollegate.

La maggior parte delle app di bundle costruisce un bundle aggiungendo **ogni componente come riga del carrello a sé**, collegandole poi con line item properties di propria concezione. L'Ajax API di Shopify consegna quelle righe al carrello senza alcuna indicazione che appartengano allo stesso insieme, quindi di default il drawer mostra un bundle di tre parti come tre articoli scollegati, ciascuno con il proprio prezzo e il proprio selettore di quantità.

`setInternalProperties` è il modo in cui dici al carrello che sono una cosa sola.

<div id="how-grouping-works">
  ## Come funziona il raggruppamento
</div>

Il carrello raggruppa le righe in base a due **proprietà canoniche**. Non conosce i nomi delle proprietà della tua app di bundle, quindi tocca a te tradurre: leggi ciò che l'app ha scritto e imprimi la coppia canonica su ogni riga con un [line transform](/it/aftersell/cart/sdk-hooks#registerlinetransform).

| Proprietà                     | Obbligatoria | Valore                                                                 |
| ----------------------------- | ------------ | ---------------------------------------------------------------------- |
| `_aftersell_cart_bundle_id`   | Sì           | Un ID condiviso. Ogni riga che porta lo stesso ID è un unico bundle.   |
| `_aftersell_cart_bundle_role` | No           | Imposta a `parent` sulla riga come cui il bundle deve essere mostrato. |

Queste passano per `setInternalProperties`, non per Shopify. Sono un **overlay solo di rendering**: non raggiungono mai `properties`, non vengono mai persistite su Shopify e non appaiono mai sull'ordine.

<div id="step-1-find-out-what-your-app-writes">
  ## Passo 1: scopri cosa scrive la tua app
</div>

Ogni app di bundle nomina le proprietà in modo diverso, quindi inizia guardando un carrello reale. Aggiungi un bundle sul tuo storefront, poi esegui questo nella console del browser:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.actions.getCart().items.forEach((line) => {
  console.log(line.title, line.properties);
});
```

Stai cercando una proprietà condivisa tra le righe del bundle. Di solito è una proprietà nascosta (il nome inizia con `_`) che contiene un ID, un riferimento o il nome del bundle. Qualcosa come `_bundle_id`, `_bundle_ref` o `_parent_id` è tipico. Annota la chiave esatta, e se una riga è marcata come prodotto principale.

<div id="step-2-map-it-onto-the-canonical-properties">
  ## Passo 2: mappala sulle proprietà canoniche
</div>

Incolla in **Cart settings → Custom script → Initialization**, sostituendo i nomi delle proprietà con quelli che hai trovato:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerLineTransform((line) => {
  const props = line.properties;
  if (!props) return;

  const bundleId = props._bundle_id;
  if (!bundleId) return;

  line.setInternalProperties({
    _aftersell_cart_bundle_id: bundleId,
    // Mark the main product so the bundle renders under it.
    _aftersell_cart_bundle_role: props._bundle_role === 'main' ? 'parent' : 'child',
  });
});
```

Questa è l'intera integrazione. Quando due o più righe condividono un ID, il carrello le raggruppa in un unico bundle.

<Note>
  Se la tua app non marca un prodotto principale, ometti del tutto `_aftersell_cart_bundle_role`. Il carrello sceglie un anchor per te.
</Note>

<div id="what-you-get">
  ## Cosa ottieni
</div>

Una volta raggruppate le righe, la riga anchor porta un [oggetto `bundle`](/it/aftersell/cart/sdk-cart-object#bundles) e il drawer renderizza il bundle come un singolo articolo:

* **I figli si annidano sotto l'anchor** invece di apparire come righe separate.
* **La quantità è atomica.** Cambiare la quantità del bundle scala ogni membro insieme, usando il rapporto `perAnchorQty` di ciascun figlio, quindi un bundle con due unità di un componente mantiene quella relazione due a uno.
* **La rimozione è atomica.** Rimuovere il bundle rimuove ogni riga membro in una sola richiesta, invece di lasciare componenti orfani.
* **Una sola riga di prezzo.** Ciò che mostra segue l'impostazione **bundle price** sul blocco [Cart items](/it/aftersell/cart/cart-items-block): il totale di tutti i membri, o solo il prezzo del prodotto principale.

<div id="how-the-anchor-is-chosen">
  ## Come viene scelto l'anchor
</div>

L'anchor è la riga come cui il bundle viene mostrato. Il carrello lo sceglie in questo ordine:

1. La riga con `_aftersell_cart_bundle_role` impostato a `parent`.
2. Altrimenti, il membro **con il prezzo più alto**.
3. Altrimenti, il primo membro nel carrello.

Il fallback sul prezzo è di solito corretto, dato che le app di bundle tendono a mettere lo sconto sul prodotto principale. Imposta il ruolo esplicitamente quando non lo è, per esempio quando il prodotto principale è l'articolo più economico o è gratis.

<div id="rules-worth-knowing">
  ## Regole che vale la pena conoscere
</div>

* **Un bundle richiede almeno due righe.** Una singola riga che porta un bundle ID viene lasciata stare e renderizza normalmente.
* **I bundle nativi di Shopify sono già gestiti.** Le righe che Shopify stesso marca come componentizzate vengono saltate da questo raggruppamento e adattate automaticamente. Ti serve solo per le app che aggiungono righe separate.
* **Il transform viene eseguito a ogni render.** Mantienilo leggero e privo di effetti collaterali. Non chiamare azioni né fare fetch al suo interno.
* **Il merge è additivo.** Le tue proprietà si fondono con quelle impostate da un altro transform. In caso di conflitto reale sulla stessa chiave, vince l'ultimo transform registrato.
* **Il raggruppamento avviene dopo il nascondere e il rinominare**, e prima dell'ordinamento. Quindi una riga che nascondi con `setHidden` non diventa mai parte di un bundle, e un [comparator](/it/aftersell/cart/sdk-hooks#registerlinecomparator) vede l'anchor, non i figli.

<Warning>
  **I figli raggruppati escono da `state.items`.** Una volta raggruppate le righe in un bundle, solo l'anchor appare in `getCart().items` e nei payload degli eventi; i figli si spostano in `anchor.bundle.children`. Inoltre smettono di contare in `itemCount`.

  Il **totale del carrello non è influenzato**, perché i totali arrivano direttamente da Shopify. Il raggruppamento cambia la presentazione, mai quanto paga l'acquirente.
</Warning>

<div id="reading-a-bundle-back">
  ## Rileggere un bundle
</div>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    if (!line.bundle) return;
    console.log(line.title, 'is a bundle of', line.bundle.children.length, 'items:');
    line.bundle.children.forEach((child) => {
      console.log('  ', child.quantity, 'x', child.title);
    });
  });
});
```

Per agire sulle righe di un bundle, usa `bundle.memberKeys`, che contiene la `key` di ogni membro incluso l'anchor.

<div id="using-it-for-other-things">
  ## Usarlo per altre cose
</div>

Il raggruppamento dei bundle è ciò per cui `setInternalProperties` è stato costruito, ma l'overlay è un canale generale per **dati solo di rendering che derivi da una riga**. Qualsiasi cosa metti lì è leggibile in `line.internalProperties` e in un [blocco Custom code](/it/aftersell/cart/custom-code-blocks), senza toccare il carrello reale:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerLineTransform((line) => {
  if (line.properties?._preorder_ship_date) {
    line.setInternalProperties({ _badge: `Ships ${line.properties._preorder_ship_date}` });
  }
});
```

Usalo quando il valore è **derivato** e solo di visualizzazione. Se il dato deve sopravvivere fino all'ordine, appartiene a una vera line item property, impostata con un input `properties[...]` nascosto nel form del prodotto in modo che raggiunga Shopify indipendentemente da chi esegue l'aggiunta.

<div id="where-to-go-next">
  ## Dove andare adesso
</div>

* **[`registerLineTransform`](/it/aftersell/cart/sdk-hooks#registerlinetransform)**: l'hook attraverso cui questo viene eseguito.
* **[Cart object](/it/aftersell/cart/sdk-cart-object#bundles)**: la struttura di `bundle` e dei suoi figli.
* **[Cart items block](/it/aftersell/cart/cart-items-block)**: l'impostazione del prezzo del bundle.
