{
  "name": "Generation et envoi des convocations de formation",
  "nodes": [
    {
      "id": "e61760d1-be66-4ef2-a886-4b98cf3da5c1",
      "name": "Note inscriptions",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -460,
        -320
      ],
      "parameters": {
        "color": 4,
        "width": 520,
        "height": 260,
        "content": "## 1. Onglet Inscriptions (Google Sheets)\n\n`id_inscription` | `nom_apprenant` | `email_apprenant` | `titre_formation` | `date_debut` | `date_fin` | `horaires` | `lieu` | `modalite` | `formateur` | `duree_heures` | `email_financeur` | `convocation_envoyee_le`\n\nRemplacez `REMPLACER_PAR_ID_DU_GOOGLE_SHEET` dans les nodes Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "cee7a427-efb3-4dc6-a8da-bc8ecbbf2e45",
      "name": "Note delai",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        180,
        -320
      ],
      "parameters": {
        "color": 3,
        "width": 460,
        "height": 260,
        "content": "## 2. Declenchement J-10\n\nLe node Code selectionne les inscriptions dont la formation demarre dans `JOURS_AVANT` jours et dont la convocation n'a pas encore ete envoyee.\n\nLa convocation reprend les mentions attendues par Qualiopi (indicateur 4) : objectifs, dates, horaires, lieu, modalites d'acces, contact handicap."
      },
      "typeVersion": 1
    },
    {
      "id": "219ba54d-107a-4ae4-ac10-4513a34efb23",
      "name": "Note renvoi",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -460,
        300
      ],
      "parameters": {
        "color": 5,
        "width": 460,
        "height": 200,
        "content": "## 3. Renvoi manuel\n\n`POST /convocation-renvoi` avec le corps :\n`{ nom_apprenant, email_apprenant, titre_formation, date_debut, date_fin, horaires, lieu, modalite, formateur, duree_heures }`"
      },
      "typeVersion": 1
    },
    {
      "id": "9d5af31d-06d2-421e-a5ab-62c249b5dfad",
      "name": "Chaque jour a 7h",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -420,
        -20
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 7 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "b4cd24ec-a4f0-4154-ad36-0e928922ea8e",
      "name": "Lire les inscriptions",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -200,
        -20
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Inscriptions"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "REMPLACER_PAR_ID_DU_GOOGLE_SHEET"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "d11fc643-983e-42db-a0ee-61cd20cc7e34",
      "name": "Selectionner les convocations a envoyer",
      "type": "n8n-nodes-base.code",
      "position": [
        20,
        -20
      ],
      "parameters": {
        "jsCode": "// Selectionne les inscriptions a convoquer (J-10 par defaut).\nconst JOURS_AVANT = 10;\n\nconst aujourdhui = new Date();\naujourdhui.setHours(0, 0, 0, 0);\nconst sortie = [];\n\nfor (const item of $input.all()) {\n  const l = item.json;\n\n  if (!l.email_apprenant) continue;\n  if (l.convocation_envoyee_le && String(l.convocation_envoyee_le).trim() !== '') continue;\n\n  const debut = new Date(l.date_debut);\n  if (isNaN(debut.getTime())) continue;\n  debut.setHours(0, 0, 0, 0);\n\n  const joursRestants = Math.round((debut - aujourdhui) / 86400000);\n  if (joursRestants < 0 || joursRestants > JOURS_AVANT) continue;\n\n  sortie.push({\n    json: {\n      ...l,\n      jours_restants: joursRestants,\n      copie_financeur: Boolean(l.email_financeur),\n      source: 'planification',\n    },\n  });\n}\n\nreturn sortie;"
      },
      "typeVersion": 2
    },
    {
      "id": "8487e88b-4e9f-4d26-a386-b0808386d387",
      "name": "Convocation a envoyer ?",
      "type": "n8n-nodes-base.if",
      "position": [
        240,
        -20
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "471171e9-6695-4753-a71b-182e4148b6b2",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.email_apprenant }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "0822cc9c-afe9-47fc-a6dc-bf9cb7a9b5a2",
      "name": "Aucune convocation aujourd'hui",
      "type": "n8n-nodes-base.noOp",
      "position": [
        460,
        160
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "ef90650d-81fe-43e0-a4e0-56a7cbd4179a",
      "name": "Generer la convocation",
      "type": "n8n-nodes-base.code",
      "position": [
        460,
        -140
      ],
      "parameters": {
        "jsCode": "// Construit le corps HTML de la convocation.\n// Personnalisez le bloc ORGANISME avec vos informations.\nconst ORGANISME = {\n  nom: 'Votre Organisme de Formation',\n  nda: 'Declaration d activite n. 00000000000',\n  contact: 'formation@votre-of.fr',\n  telephone: '01 23 45 67 89',\n  referentHandicap: 'handicap@votre-of.fr',\n};\n\nconst fr = (d) => {\n  const date = new Date(d);\n  return isNaN(date.getTime()) ? String(d) : date.toLocaleDateString('fr-FR', { day: '2-digit', month: 'long', year: 'numeric' });\n};\n\nreturn $input.all().map((item) => {\n  const l = item.json;\n  const lignes = [];\n\n  lignes.push('<h2>Convocation a une action de formation</h2>');\n  lignes.push('<p>Bonjour ' + (l.nom_apprenant || '') + ',</p>');\n  lignes.push('<p>Nous avons le plaisir de vous convoquer a la formation suivante :</p>');\n  lignes.push('<ul>');\n  lignes.push('<li><strong>Intitule :</strong> ' + (l.titre_formation || '') + '</li>');\n  lignes.push('<li><strong>Dates :</strong> du ' + fr(l.date_debut) + ' au ' + fr(l.date_fin) + '</li>');\n  lignes.push('<li><strong>Horaires :</strong> ' + (l.horaires || '09h00 - 17h00') + '</li>');\n  lignes.push('<li><strong>Duree :</strong> ' + (l.duree_heures || '') + ' heures</li>');\n  lignes.push('<li><strong>Modalite :</strong> ' + (l.modalite || 'presentiel') + '</li>');\n  lignes.push('<li><strong>Lieu / acces :</strong> ' + (l.lieu || '') + '</li>');\n  lignes.push('<li><strong>Formateur :</strong> ' + (l.formateur || '') + '</li>');\n  lignes.push('</ul>');\n  lignes.push('<p>Merci de vous presenter 10 minutes avant le debut de la session et de signer la feuille d emargement a chaque demi-journee.</p>');\n  lignes.push('<p>Situation de handicap ou besoin d adaptation : contactez notre referent a ' + ORGANISME.referentHandicap + '.</p>');\n  lignes.push('<p>' + ORGANISME.nom + ' - ' + ORGANISME.nda + '<br/>' + ORGANISME.contact + ' - ' + ORGANISME.telephone + '</p>');\n\n  return {\n    json: {\n      ...l,\n      objet_convocation: 'Convocation - ' + (l.titre_formation || 'votre formation'),\n      convocation_html: lignes.join(''),\n      envoyee_le: new Date().toISOString(),\n    },\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "fbac0ba9-b745-45aa-a691-c3493a09bb9a",
      "name": "Envoyer la convocation a l'apprenant",
      "type": "n8n-nodes-base.gmail",
      "position": [
        680,
        -140
      ],
      "parameters": {
        "sendTo": "={{ $json.email_apprenant }}",
        "subject": "={{ $json.objet_convocation }}",
        "message": "={{ $json.convocation_html }}",
        "options": {
          "appendAttribution": false
        },
        "emailType": "html",
        "resource": "message",
        "operation": "send"
      },
      "typeVersion": 2.1,
      "webhookId": "70aa12fe-78e8-42c0-a46e-a0ece2769c9d"
    },
    {
      "id": "0f95b071-6167-4cef-a78a-02b855ea015b",
      "name": "Copie au financeur ?",
      "type": "n8n-nodes-base.if",
      "position": [
        900,
        -140
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f0d2df7d-ab16-4251-a61d-8c148fc315c2",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.email_financeur }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "45af4d5c-be46-4afd-a008-dead812c7470",
      "name": "Envoyer la copie au financeur",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1120,
        -260
      ],
      "parameters": {
        "sendTo": "={{ $json.email_financeur }}",
        "subject": "=Copie convocation - {{ $json.nom_apprenant }} - {{ $json.titre_formation }}",
        "message": "={{ $json.convocation_html }}",
        "options": {
          "appendAttribution": false
        },
        "emailType": "html",
        "resource": "message",
        "operation": "send"
      },
      "typeVersion": 2.1,
      "webhookId": "f6d5d884-638e-4b25-af69-26e32f93f391"
    },
    {
      "id": "588e4f5a-e9e1-4a78-a1a2-46a64266961f",
      "name": "Fusionner les envois",
      "type": "n8n-nodes-base.merge",
      "position": [
        1340,
        -140
      ],
      "parameters": {
        "numberInputs": 2
      },
      "typeVersion": 3
    },
    {
      "id": "a3232d10-b16c-4e02-a661-b15be736d0ef",
      "name": "Marquer la convocation envoyee",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1560,
        -140
      ],
      "parameters": {
        "columns": {
          "value": {
            "id_inscription": "={{ $json.id_inscription }}",
            "convocation_envoyee_le": "={{ $json.envoyee_le }}",
            "statut_convocation": "envoyee"
          },
          "schema": [
            {
              "id": "id_inscription",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id_inscription",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "convocation_envoyee_le",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "convocation_envoyee_le",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "statut_convocation",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "statut_convocation",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id_inscription"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Inscriptions"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "REMPLACER_PAR_ID_DU_GOOGLE_SHEET"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "2d5f4aad-e0d2-4f34-afc5-b8f3b78411e5",
      "name": "Renvoi manuel",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -420,
        400
      ],
      "parameters": {
        "path": "convocation-renvoi",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2,
      "webhookId": "ed53afff-16a4-4b79-aa3f-42da6bb83132",
      "onError": "continueRegularOutput"
    },
    {
      "id": "63bcc2f2-263c-4b4b-a61c-c0c1b54e48a6",
      "name": "Normaliser la demande de renvoi",
      "type": "n8n-nodes-base.set",
      "position": [
        -200,
        400
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f5c92fb2-9459-4dae-a9a8-20dd3c82aa9d",
              "name": "id_inscription",
              "type": "string",
              "value": "={{ $json.body.id_inscription || 'manuel-' + $now.toMillis() }}"
            },
            {
              "id": "a8f828aa-f807-4e27-a863-393067071c6c",
              "name": "nom_apprenant",
              "type": "string",
              "value": "={{ $json.body.nom_apprenant }}"
            },
            {
              "id": "e17e1acf-7f59-4604-abcd-b2ed11c3bfad",
              "name": "email_apprenant",
              "type": "string",
              "value": "={{ $json.body.email_apprenant }}"
            },
            {
              "id": "bbd50d3e-609b-4e3e-a43b-cd1dbfcc7330",
              "name": "titre_formation",
              "type": "string",
              "value": "={{ $json.body.titre_formation }}"
            },
            {
              "id": "92ab5849-016e-4aaa-a278-d5254334116e",
              "name": "date_debut",
              "type": "string",
              "value": "={{ $json.body.date_debut }}"
            },
            {
              "id": "55202d73-e87c-4c4c-a544-640ec65f4b91",
              "name": "date_fin",
              "type": "string",
              "value": "={{ $json.body.date_fin }}"
            },
            {
              "id": "94b821f7-80d8-4082-a462-5d30bfc70acd",
              "name": "horaires",
              "type": "string",
              "value": "={{ $json.body.horaires }}"
            },
            {
              "id": "3ae3e0bf-9e4e-440b-a555-d30cf6cdf596",
              "name": "lieu",
              "type": "string",
              "value": "={{ $json.body.lieu }}"
            },
            {
              "id": "2da75ba2-3b11-42fa-a532-b8d0098dc9ef",
              "name": "modalite",
              "type": "string",
              "value": "={{ $json.body.modalite }}"
            },
            {
              "id": "60f16ca7-7ab1-463b-af85-bbe1236a47b6",
              "name": "formateur",
              "type": "string",
              "value": "={{ $json.body.formateur }}"
            },
            {
              "id": "be856d07-6073-40c6-a4d9-7ca4c69d6453",
              "name": "duree_heures",
              "type": "string",
              "value": "={{ $json.body.duree_heures }}"
            },
            {
              "id": "f17c6f05-b71a-4343-aea2-6b694dadbba3",
              "name": "email_financeur",
              "type": "string",
              "value": "={{ $json.body.email_financeur || '' }}"
            },
            {
              "id": "caf8ed5a-014d-41c3-ae74-78adab84f5a8",
              "name": "source",
              "type": "string",
              "value": "renvoi-manuel"
            }
          ]
        },
        "includeOtherFields": false
      },
      "typeVersion": 3.4
    }
  ],
  "pinData": {},
  "connections": {
    "Chaque jour a 7h": {
      "main": [
        [
          {
            "node": "Lire les inscriptions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lire les inscriptions": {
      "main": [
        [
          {
            "node": "Selectionner les convocations a envoyer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Selectionner les convocations a envoyer": {
      "main": [
        [
          {
            "node": "Convocation a envoyer ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convocation a envoyer ?": {
      "main": [
        [
          {
            "node": "Generer la convocation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Aucune convocation aujourd'hui",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generer la convocation": {
      "main": [
        [
          {
            "node": "Envoyer la convocation a l'apprenant",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Envoyer la convocation a l'apprenant": {
      "main": [
        [
          {
            "node": "Copie au financeur ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Copie au financeur ?": {
      "main": [
        [
          {
            "node": "Envoyer la copie au financeur",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fusionner les envois",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Envoyer la copie au financeur": {
      "main": [
        [
          {
            "node": "Fusionner les envois",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fusionner les envois": {
      "main": [
        [
          {
            "node": "Marquer la convocation envoyee",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Renvoi manuel": {
      "main": [
        [
          {
            "node": "Normaliser la demande de renvoi",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normaliser la demande de renvoi": {
      "main": [
        [
          {
            "node": "Generer la convocation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e6a91dc0-feff-4ecd-a948-2ac18cf31701",
  "meta": {
    "instanceId": "5f7c1a2b9d3e4f60a8b7c6d5e4f3021998af77bc12de34ff56aa7788bb99ccdd",
    "templateCredsSetupCompleted": true
  },
  "tags": []
}
