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

# Uploader un PDF sur une commande de vente programmatiquement

> Ajoutez un PDF à une commande de vente depuis un script.

Cet exemple montre comment ajouter un PDF à une commande de vente dans Bonx
depuis un script Node.js. Le fichier apparaîtra dans l'onglet **Fichiers** de la
commande, comme s'il avait été ajouté depuis l'interface.

Vous avez besoin de :

* l'identifiant de la commande de vente dans Bonx ;
* un fichier PDF ;
* l'URL GraphQL et une clé API Bonx.

L'ajout du fichier se fait en trois appels :

<Steps>
  <Step title="Demander une URL d'upload">Bonx renvoie une URL temporaire sur laquelle envoyer le PDF.</Step>
  <Step title="Envoyer le PDF">Envoyez le contenu du fichier à cette URL avec une requête `PUT`.</Step>

  <Step title="Lier le PDF à la commande">
    Créez le fichier dans Bonx avec le type `salesOrders` et l'identifiant de la commande.
  </Step>
</Steps>

## Exemple complet

Cet exemple utilise `fetch`, disponible nativement à partir de Node.js 18.
Enregistrez le script dans un fichier `.mjs` pour pouvoir l'exécuter directement.

```js theme={null}
import { readFile } from 'node:fs/promises';

const GRAPHQL_URL = process.env.BONX_GRAPHQL_URL;
const API_KEY = process.env.BONX_API_KEY;
const PDF_CONTENT_TYPE = 'application/pdf';

async function graphql(query, variables) {
  const response = await fetch(GRAPHQL_URL, {
    method: 'POST',
    headers: {
      'x-api-key': API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ query, variables }),
  });

  if (!response.ok) {
    throw new Error(`Erreur HTTP GraphQL : ${response.status}`);
  }

  const result = await response.json();
  if (result.errors) {
    throw new Error(JSON.stringify(result.errors));
  }

  return result.data;
}

async function uploadPdfToSalesOrder({ salesOrderId, filePath, fileName }) {
  const pdf = await readFile(filePath);

  // 1. Demander une URL temporaire pour l'upload
  const { generatePresignedUrlUpload: upload } = await graphql(
    `
      mutation CreateUploadUrl($fileName: String!, $contentType: String) {
        generatePresignedUrlUpload(fileName: $fileName, contentType: $contentType) {
          uploadUrl
          fileName
        }
      }
    `,
    { fileName, contentType: PDF_CONTENT_TYPE },
  );

  // 2. Envoyer le PDF sur cette URL
  const uploadResponse = await fetch(upload.uploadUrl, {
    method: 'PUT',
    headers: { 'Content-Type': PDF_CONTENT_TYPE },
    body: pdf,
  });

  if (!uploadResponse.ok) {
    throw new Error(`L'upload du PDF a échoué : ${uploadResponse.status}`);
  }

  // 3. Lier le fichier à la commande de vente
  const { insertFilesOne: file } = await graphql(
    `
      mutation AttachFile($fileId: String!, $name: String!, $size: Int!, $recordId: Int!) {
        insertFilesOne(
          object: {
            fileId: $fileId
            name: $name
            contentType: "application/pdf"
            size: $size
            recordId: $recordId
            recordType: "salesOrders"
          }
        ) {
          id
        }
      }
    `,
    {
      fileId: upload.fileName,
      name: fileName,
      size: pdf.length,
      recordId: salesOrderId,
    },
  );

  return file;
}

const file = await uploadPdfToSalesOrder({
  salesOrderId: 42,
  filePath: './bon-de-commande.pdf',
  fileName: 'Bon de commande client.pdf',
});

console.log('PDF ajouté :', file.id);
```

## Points à vérifier

* `salesOrderId` est l'identifiant interne de la commande dans Bonx.
* L'URL d'upload expire après 10 minutes. Demandez-la juste avant d'envoyer le fichier.
* Utilisez `application/pdf` lors de la création de l'URL et lors du `PUT`.
* Pour `fileId`, utilisez le `fileName` renvoyé par `generatePresignedUrlUpload`.
* Relancer le script ajoute une nouvelle copie du fichier. Évitez donc de traiter deux fois la même opération.

<Tip>
  Pour rattacher le PDF à un autre type de fiche, remplacez `salesOrders` par le `recordType` correspondant. Consultez
  [Rattacher un document](/fr/graphql/files) pour voir les valeurs disponibles.
</Tip>
