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

# Importer les données de produits dans Twenty

> Synchronisez les données du catalogue de produits depuis un entrepôt de données vers votre CRM selon une planification.

Utilisez ce modèle pour garder Twenty synchronisé avec les données produits de votre entrepôt de données (par ex. Snowflake, BigQuery, PostgreSQL).

## Structure du flux de travail

1. **Déclencheur** : Selon une planification
2. **Code** : Interroger votre entrepôt de données
3. **Code** (facultatif) : Formater les données en tableau
4. **Iterator** : Parcourir chaque produit
5. **Upsert Record** : Créer ou mettre à jour dans Twenty

<img src="https://mintcdn.com/twenty/ZVHVYG6uDKpO6cME/images/user-guide/workflows/create_users_workflow.png?fit=max&auto=format&n=ZVHVYG6uDKpO6cME&q=85&s=8542bb62659bb0e7d1de08c6f36d83d5" style={{width:'100%'}} width="4550" height="7720" data-path="images/user-guide/workflows/create_users_workflow.png" />

## Étape 1 : Planifier le déclencheur

Définissez le flux de travail pour s'exécuter à une fréquence correspondant à vos besoins d'actualisation des données :

* Toutes les 5 minutes pour une synchronisation quasi en temps réel
* Toutes les heures pour des données moins critiques
* Quotidiennement pour des mises à jour par lots

## Étape 2 : Interroger votre entrepôt de données

Ajoutez une action **Code** pour récupérer les données récentes :

```javascript theme={null}
export const main = async () => {
  const intervalMinutes = 10; // Match your schedule frequency
  const cutoffTime = new Date(Date.now() - intervalMinutes * 60 * 1000).toISOString();

  // Replace with your actual data warehouse connection
  const response = await fetch("https://your-warehouse-api.com/query", {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      query: `
        SELECT id, name, sku, price, stock_quantity, updated_at
        FROM products
        WHERE updated_at >= '${cutoffTime}'
      `
    })
  });

  const data = await response.json();
  return { products: data.results };
};
```

<Tip>
  Filtrez par `updated_at >= last X minutes` pour ne récupérer que les enregistrements récemment modifiés. Cela rend la synchronisation plus efficace.
</Tip>

## Étape 3 : Formater les données (facultatif)

Si votre entrepôt renvoie des données dans un format nécessitant une transformation, ajoutez une autre action **Code**. Les transformations courantes incluent les conversions de type, le renommage de champs et le nettoyage des données.

### Exemple : données utilisateur avec champs booléens et de statut

```javascript theme={null}
export const main = async (params: {
  users: any;
}): Promise<object> => {
  const { users } = params;
  const usersFormatted = typeof users === "string" ? JSON.parse(users) : users;

  // Convert string "true"/"false" to actual booleans
  const toBool = (v: any) => v === true || v === "true";

  return {
    users: usersFormatted.map((user) => ({
      ...user,
      activityStatus: String(user.activityStatus).toUpperCase(),
      isActiveLast30d: toBool(user.isActiveLast30d),
      isActiveLast7d: toBool(user.isActiveLast7d),
      isActiveLast24h: toBool(user.isActiveLast24h),
      isTwenty: toBool(user.isTwenty),
    })),
  };
};
```

### Exemple : données produit avec conversions de type

```javascript theme={null}
export const main = async (params: { products: any }) => {
  const products = typeof params.products === "string"
    ? JSON.parse(params.products)
    : params.products;

  return {
    products: products.map(product => ({
      externalId: product.id,
      name: product.name,
      sku: product.sku,
      price: parseFloat(product.price),        // String → Number
      stockQuantity: parseInt(product.stock_quantity),
      isActive: product.status === "active"    // String → Boolean
    }))
  };
};
```

### Exemple : formatage des dates et des devises

```javascript theme={null}
export const main = async (params: { deals: any }) => {
  const deals = typeof params.deals === "string"
    ? JSON.parse(params.deals)
    : params.deals;

  return {
    deals: deals.map(deal => ({
      ...deal,
      // Convert Unix timestamp to ISO date
      closedAt: deal.closed_timestamp
        ? new Date(deal.closed_timestamp * 1000).toISOString()
        : null,
      // Ensure amount is a number (remove currency symbols)
      amount: parseFloat(String(deal.amount).replace(/[^0-9.-]/g, "")),
      // Normalize stage names
      stage: deal.stage?.toLowerCase().replace(/_/g, " ")
    }))
  };
};
```

### Transformations courantes

| Format source        | Format cible     | Code                                     |
| -------------------- | ---------------- | ---------------------------------------- |
| `"true"` / `"false"` | `true` / `false` | `v === true \|\| v === "true"`           |
| `"123.45"`           | `123.45`         | `parseFloat(value)`                      |
| `"active"`           | `"ACTIVE"`       | `value.toUpperCase()`                    |
| `1704067200` (Unix)  | Date ISO         | `new Date(v * 1000).toISOString()`       |
| `"$1,234.56"`        | `1234.56`        | `parseFloat(v.replace(/[^0-9.-]/g, ""))` |
| `null` / `undefined` | `""`             | `value \|\| ""`                          |

## Étape 4 : Itérer sur les produits

Ajoutez une action **Itérateur** :

* Entrée : `{{code.products}}`

Cela parcourt chaque produit du tableau.

## Étape 5 : Effectuer un upsert pour chaque enregistrement

À l'intérieur de l'itérateur, ajoutez une action **Upsert Record** :

| Paramètre              | Valeur                                 |
| ---------------------- | -------------------------------------- |
| **Objet**              | Votre objet Produit personnalisé       |
| **Correspondance par** | ID externe ou SKU (identifiant unique) |
| **Nom**                | `{{iterator.item.name}}`               |
| **SKU**                | `{{iterator.item.sku}}`                |
| **Prix**               | `{{iterator.item.price}}`              |

<Tip>
  Utilisez **Upsert** (mettre à jour ou créer) au lieu de construire des branches distinctes pour la création et la mise à jour. C'est plus rapide à construire et plus facile à déboguer.
</Tip>

## Exemples de cas d'utilisation

| Source                            | Données                                          |
| --------------------------------- | ------------------------------------------------ |
| **Système ERP**                   | Catalogue de produits, tarification, stocks      |
| **Plateforme e-commerce**         | Commandes, clients, mises à jour des produits    |
| **Entrepôt de données**           | Indicateurs agrégés, données enrichies           |
| **Système de gestion des stocks** | Niveaux de stock, alertes de réapprovisionnement |

## Articles connexes

* [Déclencheurs de workflows](/l/fr/user-guide/workflows/capabilities/workflow-triggers)
* [Actions de workflows](/l/fr/user-guide/workflows/capabilities/workflow-actions)
* [Gérer les tableaux dans les actions Code](/l/fr/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)
