# Variazioni dei prezzi

> Cambiamenti dei prezzi di listino e anteprima di uno, incluso ciò che un cliente pagherà prima e dopo.

Le modifiche di massa, la pianificazione e le e-mail per i cambi di prezzo dei clienti richiedono il piano Pro. Il piano Free può pubblicare immediatamente gli import di fogli di calcolo a prezzo Standard senza e-mail. I prezzi concordati esistenti e i cambi pianificati continuano a valere quando finisce il piano Pro.

I prezzi di listino non cambiano mai in modo silenzioso in TradeCatalog. I nuovi prezzi vanno in un **cambiamento prezzo** per una sola lista di prezzi: un bozzetto che il personale recensisce, data e pubblica. I clienti vengono e-mailati solo quando i loro prezzi cambiano. Standard è la lista quando non ne viene indicata un'altra. Un bozzetto non mescola mai liste.

## Come vengono effettuati i cambiamenti dei prezzi

- **Dall'API:** [`PUT /products`](/docs/api/products#create-or-update-products) con un nuovo `listPrice` per un prodotto esistente lo aggiunge a un bozzetto e restituisce il `priceChangeId` del bozzetto.
- **Dall'app:** importazioni da fogli di calcolo, e modifiche di massa come "+4% sulla categoria Viti".

La pubblicazione, la pianificazione e l'annullamento avvengono nell'app, sotto **Cambiamenti prezzo**. Non esiste un'API per questi processi: una persona controlla sempre un cambiamento prezzo prima che i clienti lo vedano.

## Stati

| Stato       | Significato                                                       |
| ----------- | ----------------------------------------------------------------- |
| `draft`     | Non pubblicato. Nessun prezzo è cambiato.                         |
| `scheduled` | Pubblicato con una data futura. I prezzi cambiano in quella data. |
| `live`      | In vigore.                                                        |
| `cancelled` | Annullato prima che entrasse in vigore.                           |

## L'oggetto cambiamento prezzo

```json
{
  "id": "c4d5e6f7-1234-4abc-9def-0123456789ab",
  "source": "import",
  "title": "API import (Sage stock sync)",
  "supplierNote": null,
  "status": "draft",
  "effectiveAt": null,
  "notifyCustomers": true,
  "raiseFixedPrices": false,
  "priceListId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "priceListName": "Standard",
  "createdBy": "Fq3L0cZ7tN1pW9aYx2Rk",
  "publishedAt": null,
  "cancelledAt": null,
  "createdAt": "2026-09-27T02:00:14.000Z",
  "items": 38
}
```

| Campo              | Tipo           | Descrizione                                                                                                                                        |
| ------------------ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source`           | stringa        | `import` (foglio di calcolo o API) o `bulk` (una variazione percentuale effettuata nell'app).                                                      |
| `title`            | stringa        | Visualizzato dal personale. I bozzetti API hanno il titolo "Importazione API (nome chiave)".                                                       |
| `supplierNote`     | stringa o null | Messaggio ai clienti nella e-mail del cambiamento prezzo.                                                                                          |
| `status`           | stringa        | Vedi [stati](#statuses).                                                                                                                           |
| `effectiveAt`      | stringa o null | Quando i nuovi prezzi entrano in vigore.                                                                                                           |
| `notifyCustomers`  | booleano       | Se i clienti vengono e-mailati sui loro nuovi prezzi.                                                                                              |
| `raiseFixedPrices` | booleano       | Se i prezzi concordati aumentano nella stessa percentuale. Questa scelta è separata dalla lista.                                                   |
| `priceListId`      | stringa o null | La lista in cui viene scritto questo cambiamento. Null significa Standard, incluso i cambiamenti effettuati prima che le liste fossero denominate. |
| `priceListName`    | stringa        | Il nome di quella lista. `Standard` quando `priceListId` è null.                                                                                   |
| `createdBy`        | stringa o null | ID della persona che lo ha creato. Per i bozzetti API, la persona che ha creato la chiave.                                                         |
| `items`            | intero         | Quanti prodotti modifica. Solo nella lista.                                                                                                        |

## Cambiamenti dei prezzi di listino

**GET** `/api/v1/price-changes`

Più recenti per primi. Copre i **100 cambiamenti prezzo più recenti**.

| Nome     | Tipo   | Obbligatorio | Descrizione                             |
| -------- | ------ | ------------ | --------------------------------------- |
| `limit`  | intero | no           | 1 a 100. Valore predefinito 100.        |
| `offset` | intero | no           | Righe da saltare. Valore predefinito 0. |

```bash
curl https://tradecatalog.app/api/v1/price-changes \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"
```

```js
const res = await fetch('https://tradecatalog.app/api/v1/price-changes', {
  headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
})
const { data: changes } = await res.json()
const drafts = changes.filter((change) => change.status === 'draft')
```

## Anteprima di un cambiamento prezzo

**GET** `/api/v1/price-changes/{id}`

Tutto ciò che il personale vede prima della pubblicazione: quanti prezzi aumentano e diminuiscono, i movimenti più grandi, gli avvisi e quanti prezzi concordati tocca. Passa `customer` per vedere i prezzi propri del cliente prima e dopo.

| Nome       | Posizione | Tipo    | Obbligatorio | Descrizione                  |
| ---------- | --------- | ------- | ------------ | ---------------------------- |
| `id`       | percorso  | stringa | sì           | ID del cambiamento prezzo.   |
| `customer` | query     | stringa | no           | ID cliente o codice account. |

```bash
curl "https://tradecatalog.app/api/v1/price-changes/c4d5e6f7-1234-4abc-9def-0123456789ab?customer=OAK01" \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"
```

```js
const res = await fetch(
  `https://tradecatalog.app/api/v1/price-changes/${priceChangeId}?customer=OAK01`,
  { headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` } },
)
const { data: preview } = await res.json()
if (preview.warnings.length)
  console.warn('Check these before publishing', preview.warnings)
```

```json
{
  "data": {
    "change": {
      "id": "c4d5e6f7-1234-4abc-9def-0123456789ab",
      "source": "import",
      "title": "API import (Sage stock sync)",
      "supplierNote": null,
      "status": "draft",
      "effectiveAt": null,
      "notifyCustomers": true,
      "raiseFixedPrices": false,
      "priceListId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "priceListName": "Standard",
      "createdBy": "Fq3L0cZ7tN1pW9aYx2Rk",
      "publishedAt": null,
      "cancelledAt": null,
      "createdAt": "2026-09-27T02:00:14.000Z"
    },
    "counts": { "total": 38, "up": 36, "down": 2 },
    "biggest": [
      {
        "productId": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
        "oldPrice": 1850,
        "newPrice": 1950,
        "sku": "HX-8510",
        "name": "Hex bolt M10 x 50 zinc",
        "changeBp": 541
      }
    ],
    "warnings": [],
    "fixedAffected": 3,
    "customer": {
      "name": "Oakfield Joinery",
      "rows": [
        {
          "sku": "HX-8510",
          "name": "Hex bolt M10 x 50 zinc",
          "before": 1573,
          "after": 1658,
          "label": "Brand discount −15%"
        }
      ]
    }
  },
  "currency": "GBP"
}
```

| Campo           | Descrizione                                                                                                                                                                                              |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `counts`        | Prodotti nel cambiamento, e quanti aumentano e diminuiscono.                                                                                                                                             |
| `biggest`       | Fino a 20 articoli con il movimento percentuale più alto. `changeBp` è la variazione in punti base (541 = +5,41%).                                                                                       |
| `warnings`      | Articoli che si muovono più del 30% in entrambe le direzioni, o vanno a zero. Di solito errori di battitura.                                                                                             |
| `fixedAffected` | Prezzi concordati su questi prodotti che sono validi ora. Cambiano solo se il cambiamento aumenta i prezzi concordati.                                                                                   |
| `customer`      | Con `customer`: i prezzi unitari di quel cliente prima e dopo, dal loro elenco e poi dalla loro modifica, per i primi 50 articoli. Un cliente su un altro elenco non è modificato. `null` senza di esso. |

`404 not_found` se non esiste alcun cambiamento prezzo in questo ambiente.
