<!-- Device Inventory Manager — https://wiki.cyberguard.srl/dim/inventory/import-export/ -->

# Import & Export

Bulk import and export of Inventory assets, using the same preview-before-confirm workflow used elsewhere in the portal.

> **Required permission:** `Inventory Import` for import, `Inventory Export` for export — separate from the base `Inventory` permission.

---

## Import workflow

1. Navigate to **Import** → **Inventory** tab
2. Upload your CSV file
3. Click **Preview**
4. Review the preview, then **Confirm**

### Step 2 — Preview

Before anything is written, the portal shows:

- **New catalogue entries** — any category, sub-category, or vendor name in the file that doesn't exist yet is listed explicitly, so a typo ("Sim" vs "SIm") is caught before it becomes two near-duplicate categories, not months later while filtering the list. Names that only differ by case count as the *same* entry.
- **Row-by-row result** — each row marked **New**, **Update**, or **Error**, with the reason for any error spelled out (e.g. "Category is required.")

### Deduplication

A row matches an existing asset by:

1. **Serial Number**, if the row has one, or
2. **Category + Name + Assigned User UPN**, otherwise

A matching row updates the existing asset instead of creating a duplicate — this is also what makes the exported file safe to re-import unchanged (see below).

> Assignment fields (assigned user, device) on an existing asset are only changed if the CSV row actually provides a value for them — a re-import that doesn't mention the assigned user never clears an assignment set through the portal.

> **Empty cells clear the other fields.** When a row updates an existing asset, an empty cell empties the corresponding field (for example the expiry date or the cost), and an empty `Stato` sets the asset back to **Active**. To change only some fields, start from an [export](#export) so that the file contains the current values of all the others.

---

## CSV format

| Property | Value |
|----------|-------|
| **Format** | CSV, semicolon-separated (`;`) |
| **Encoding** | UTF-8 |
| **Header row** | Required (first row) |
| **Date format** | `yyyy-MM-dd` |
| **Decimal format** | Point as decimal separator (`12.50`, never `12,50`) |
| **Maximum rows** | 5,000 per file |

Download a ready-to-use template from the portal: **Import → Inventory → Download Template**.

### Columns

```csv
Categoria;SottoCategoria;Nome;Vendor;Seriale;OrdineAcquisto;Stato;Costo;PeriodicitaCosto;Scadenza;DataAssegnazione;UtenteUPN;Note
Software;Licenze;Microsoft 365 E3;Microsoft;;PO-2026-0001;Active;12.50;Monthly;2027-06-30;2026-01-15;mario.rossi@cliente.it;Rinnovo automatico
SIM;;SIM aziendale 3934;Vodafone;8939000000000000001;;Active;9.90;Monthly;;;;
```

| Column | Required | Type | Description |
|--------|----------|------|-------------|
| `Categoria` | **Yes** | Text | Category name — created in the catalogue if new |
| `SottoCategoria` | No | Text | Sub-category name — created in the catalogue if new |
| `Nome` | **Yes** | Text (max 200) | Asset display name |
| `Vendor` | No | Text (max 150) | Vendor/publisher name — created in the catalogue if new |
| `Seriale` | No | Text (max 150) | Serial number, licence key, or ICCID — used for deduplication when present |
| `OrdineAcquisto` | No | Text (max 150) | Purchase order reference |
| `Stato` | No | Fixed value | See **Status values** below. Defaults to `Active` if left empty |
| `Costo` | No | Decimal | Invariant culture, point as decimal separator |
| `PeriodicitaCosto` | No | Fixed value | See **Cost period values** below |
| `Scadenza` | No | Date (`yyyy-MM-dd`) | Expiry or renewal date |
| `DataAssegnazione` | No | Date (`yyyy-MM-dd`) | Assignment date |
| `UtenteUPN` | No | Text (max 255) | Assigned Entra user (UPN) |
| `Note` | No | Text | Free text |

### Status values — always accepted in English, Italian aliases also accepted on import

| English (used by export) | Italian alias (accepted on import) | Meaning |
|---------------------------|--------------------------------------|---------|
| `Active` | `Attivo` | In active use |
| `Parked` | `Parcheggiato` | Temporarily set aside |
| `Dismissed` | `Dismesso` | Retired / no longer in use |

### Cost period values — always accepted in English, Italian aliases also accepted on import

| English (used by export) | Italian alias (accepted on import) |
|---------------------------|--------------------------------------|
| `OneTime` | `Una tantum` / `UnaTantum` |
| `Monthly` | `Mensile` |
| `Yearly` | `Annuale` |

> **On export**, `Stato` and `PeriodicitaCosto` are always written using the English invariant names above, regardless of the portal's display language — this is what makes an exported file safe to re-import into any tenant, in any language, without editing it first.

---

## Export

1. Navigate to **Export** from the sidebar
2. Select **Inventory**
3. Click **Export Data**

The exported file uses **exactly the same columns, in the same order**, as the import format above — category, sub-category, and vendor are written as their catalogue names (never as internal IDs), dates as `yyyy-MM-dd`, cost with a point as decimal separator, and `Stato`/`PeriodicitaCosto` in English.

### Round-trip

Because the export format matches the import format column-for-column, and every asset already has a serial number or a category+name+user combination that the import can match, **an exported file can be re-imported without any changes** and every row is recognized as an update to the asset it came from — no duplicates, no new catalogue entries created.

---

## Tips to avoid errors

- **Use the template.** It guarantees the correct column names, order, and separator.
- **Watch for near-duplicate category names.** The preview lists every new catalogue entry the import would create — check that list before confirming, especially for typos like "Sim" vs "SIm" (these two collapse into one entry automatically, since matching is case-insensitive).
- **Use a point, not a comma, for `Costo`.** A value like `12,50` is rejected rather than silently read as `1250`.
- **Keep dates in `yyyy-MM-dd`.** Any other format is rejected for that row.
- **Review the preview.** Rows with errors are listed with the specific reason and are skipped — fix the CSV and re-upload to include them.
