snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 3s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
---
title: Risposta automatica alle email in arrivo
description: Crea un flusso di lavoro che utilizza l'IA per smistare le email in arrivo e inviare automaticamente risposte in thread.
---
Rispondi alle email in arrivo in pochi secondi — non ore. Questo flusso di lavoro utilizza un agente IA per filtrare il rumore (newsletter, spam, auto-replies) e redigere una risposta personalizzata ai messaggi reali. Poi, AI lo invia come risposta filettata all'interno della conversazione originale.
## Come funziona il threading delle email
Ogni email include un'intestazione nascosta `Message-ID` — un'impronta univoca assegnata dal server di posta del mittente. Quando rispondi a un'email, il tuo client di posta imposta un'intestazione `In-Reply-To` che fa riferimento a quell'impronta. È così che Gmail, Outlook e tutti gli altri client raggruppano i messaggi nei thread.
In Twenty, quell'impronta è memorizzata come `headerMessageId` sull'oggetto Message. Il tuo flusso di lavoro la recupera e la passa al campo In-Reply-To dell'azione Send Email.
## Creazione del flusso di lavoro
### Passaggio 1: Crea un nuovo flusso di lavoro
Vai a **Impostazioni -> Flussi di lavoro** e fai clic su **+ New Workflow**.
### Passaggio 2: Imposta il trigger sui messaggi in arrivo
Scegli **When a Record is Created** e seleziona **Messages**.
Ogni volta che un'email arriva in Twenty, questo si attiva.
<img src="/images/user-guide/workflows/auto-reply/workflow-overview.png" style={{width:'100%'}} />
### Passaggio 3: Cerca chi l'ha inviato
Aggiungi un'azione **Search Records**.
L'indirizzo del mittente non è presente sul messaggio stesso — si trova nel record Message Participant correlato.
| Campo | Valore |
| ----------- | ------------------------------- |
| **Oggetto** | Partecipanti al messaggio |
| **Filtro** | Message **is** `{{trigger.id}}` |
| **Filtro** | Role **is** From |
| **Limite** | 1 |
Questo ti fornisce l'email del mittente in `handle` e il suo nome in `displayName`.
<img src="/images/user-guide/workflows/auto-reply/find-sender.png" style={{width:'100%'}} />
### Passo 4: Triage e bozza una risposta con AI
Aggiungi un'azione **AI Agent**. Questo singolo passaggio fa due cose: decide se l'email merita una risposta e, in tal caso, ne scrive una.
Usa un prompt come:
```
You are an email triage assistant for a sales team. Read the following
inbound email and decide if it deserves a reply.
Subject: {{trigger.subject}}
Body: {{trigger.text}}
From: {{Find Sender.first.displayName}} ({{Find Sender.first.handle}})
If this email is spam, a newsletter, an automated notification, or
otherwise does not need a human reply, respond with exactly: SKIP
Otherwise, write a short, professional reply (3-4 sentences max) that:
- Acknowledges their specific message
- Lets them know someone from the team will follow up shortly
- Is warm but not overly casual
Respond with only the reply text, no subject line or greeting prefix.
```
AI Agent produce la sua risposta in un campo `response` a cui i passaggi successivi possono fare riferimento.
<img src="/images/user-guide/workflows/auto-reply/ai-triage.png" style={{width:'100%'}} />
### Passaggio 5: Ramifica in base alla decisione dell'AI
Aggiungi un'azione **If/Else** per verificare se l'AI ha deciso di rispondere o saltare.
| Campo | Valore |
| -------------- | ----------------------------------------------- |
| **Condizione** | AI Agent `response` **does not contain** `SKIP` |
| **Se vero** | Continua con Send Email |
| **Altrimenti** | Non fare nulla (il flusso di lavoro termina) |
Spam, newsletter e messaggi generati automaticamente vengono scartati. Tutto il resto passa al passaggio successivo.
<img src="/images/user-guide/workflows/auto-reply/should-reply.png" style={{width:'100%'}} />
### Passaggio 6: Invia una risposta nello stesso thread
Aggiungi un'azione **Send Email** nel ramo "if true". Fai clic su **Advanced options**, quindi su **Add In-Reply-To**.
| Campo | Valore |
| --------------- | -------------------------------------- |
| **A** | `{{Find Sender.first.handle}}` |
| **Oggetto** | `Re: {{trigger.subject}}` |
| **Corpo** | `{{AI Triage & Draft Reply.response}}` |
| **In-Reply-To** | `{{trigger.headerMessageId}}` |
Il campo In-Reply-To è ciò che rende questo un messaggio di risposta invece di una nuova conversazione. Il destinatario lo vede nel thread sotto l'email originale in Gmail, Outlook o qualsiasi altro client.
<img src="/images/user-guide/workflows/auto-reply/send-email.png" style={{width:'100%'}} />
<Tip>
**In-Reply-To** si aspetta un `message.headerMessageId` dal trigger — è l'impronta univoca dell'email, non un indirizzo del destinatario. Se lo lasci vuoto, l'email viene comunque inviata, solo come messaggio autonomo.
</Tip>
<Warning>
Gmail usa l'oggetto per raggruppare i messaggi nei thread. L'oggetto **deve** iniziare con `Re:` (inclusi i due punti e lo spazio) affinché Gmail visualizzi la risposta all'interno del thread originale. Senza di esso, la risposta apparirà come una conversazione separata — anche se l'intestazione In-Reply-To è impostata correttamente.
</Warning>
### Passaggio 7: Testa e attiva
Fai clic su **Test**, quindi controlla il tuo client di posta. La risposta dovrebbe comparire annidata sotto il messaggio originale.
Attivalo quando sei soddisfatto.
## Idee per sviluppare ulteriormente
* **Rispondi solo ai VIP** — aggiungi un ramo che controlli il dominio del mittente o se esiste come Contatto in Twenty
* **Instrada in base all'intento** — usa prompt distinti di AI Agent per gestire le richieste commerciali in modo diverso rispetto a quelle di supporto
* **Arricchisci prima di rispondere** — aggiungi un passaggio Search Records per inserire nel prompt dell'AI l'azienda del mittente o la cronologia delle trattative per risposte più personalizzate

View File

@@ -0,0 +1,179 @@
---
title: Automazioni per trattative chiuse come vinte
description: Automatizza le attività post-vittoria quando le opportunità vengono chiuse.
---
Quando una trattativa si chiude, devono succedere più cose: aggiornare lo stato dell'azienda, notificare i membri del team, creare attività di onboarding. Automatizza tutto questo con un unico flusso di lavoro.
## Il problema
Quando un'opportunità passa a "Chiusa vinta":
* Il tipo di azienda deve passare da "Potenziale cliente" a "Cliente"
* Devono essere create le attività di onboarding
* Il team di Customer Success deve essere avvisato
* Il rappresentante commerciale ha bisogno di una conferma
Farlo manualmente richiede tempo ed è soggetto a errori.
## La soluzione
Crea un flusso di lavoro che gestisca automaticamente tutte le attività post-vittoria.
## Configurazione completa del flusso di lavoro
### Passaggio 1: Crea il flusso di lavoro
1. Vai a **Impostazioni → Flussi di lavoro**
2. Fai clic su **+ Nuovo flusso di lavoro**
3. Assegna il nome "Trattativa vinta - Automazione post-vittoria"
### Passaggio 2: Configura il trigger
1. Seleziona **Record is Updated**
2. Seleziona **Opportunità**
3. In "Fields to monitor", seleziona **Stage**
### Passaggio 3: Aggiungi un filtro sulla fase
1. Aggiungi l'azione **Filter**
2. Condizione: `{{trigger.object.stage}}` uguale a "Chiusa vinta"
### Passaggio 4: Aggiorna il tipo di azienda
1. Aggiungi l'azione **Update Record**
2. Configura:
| Campo | Valore |
| ------------------------------- | ------------------------------- |
| **Oggetto** | Aziende |
| **Record** | `{{trigger.object.company.id}}` |
| **Tipo** | Cliente |
| **Data della prima trattativa** | `{{trigger.object.closedAt}}` |
| **Proprietario dell'account** | `{{trigger.object.owner.id}}` |
### Passaggio 5: Crea un'attività di onboarding
1. Aggiungi l'azione **Create Record**
2. Configura:
| Campo | Valore |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Oggetto** | Attività |
| **Titolo** | `Onboarding: {{trigger.object.name}}` |
| **Assegnatario** | Membro del team di Customer Success |
| **Data di scadenza** | Tra 3 giorni |
| **Priorità** | Alta |
| **Azienda correlata** | `{{trigger.object.company.id}}` |
| **Opportunità correlata** | `{{trigger.object.id}}` |
| **Descrizione** | `Onboarding del nuovo cliente per {{trigger.object.company.name}}. Valore della trattativa: {{trigger.object.amount}}` |
### Passaggio 6: Notifica il team di Customer Success
1. Aggiungi l'azione **Send Email**
2. Configura:
| Campo | Valore |
| ----------- | --------------------------------------------------- |
| **A** | customer-success@yourcompany.com |
| **Oggetto** | `🎉 Nuovo cliente: {{trigger.object.company.name}}` |
| **Corpo** | Vedi l'esempio sotto |
**Esempio di corpo dell'email**:
```
Hi CS Team,
We have a new customer!
Company: {{trigger.object.company.name}}
Deal: {{trigger.object.name}}
Value: {{trigger.object.amount}}
Sales Rep: {{trigger.object.owner.name}}
Close Date: {{trigger.object.closedAt}}
An onboarding task has been created automatically.
Let's give them a great start!
```
### Passaggio 7: Conferma al rappresentante commerciale
1. Aggiungi un'altra azione **Send Email**
2. Configura:
| Campo | Valore |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **A** | `{{trigger.object.owner.email}}` |
| **Oggetto** | `✅ Trattativa chiusa: {{trigger.object.name}}` |
| **Corpo** | Congratulazioni! La tua trattativa è stata elaborata. Il team di Customer Success è stato avvisato e l'onboarding è iniziato. |
### Passaggio 8: Testa e attiva
1. Esegui un test spostando un'opportunità di prova su "Chiusa vinta"
2. Verifica:
* Il tipo di azienda è stato modificato in "Cliente"
* Attività di onboarding creata
* Il team di Customer Success ha ricevuto l'email
* Il rappresentante commerciale ha ricevuto la conferma
3. Attiva quando sei pronto
## Gestione di "Chiusa persa"
Crea un flusso di lavoro simile per le trattative perse:
### Scatenante
* Record is Updated (Opportunità, Fase = "Chiusa persa")
### Azioni
1. **Create Record**: Attività per "Analisi trattativa persa"
2. **Update Record**: Aggiungi il motivo della perdita al record dell'azienda
3. **Send Email**: Notifica il responsabile della trattativa persa
## Avanzato: Onboarding a più fasi
Per un onboarding complesso, crea più attività:
```javascript
export const main = async (params) => {
const tasks = [
{ title: "Welcome call", daysFromNow: 1, assignee: "CS" },
{ title: "Send onboarding materials", daysFromNow: 2, assignee: "CS" },
{ title: "Technical setup", daysFromNow: 5, assignee: "Support" },
{ title: "30-day check-in", daysFromNow: 30, assignee: "CS" }
];
return { tasks };
};
```
Usa **Iterator** per creare ogni attività a partire dall'array.
## Idee di personalizzazione
### Mantieni aggiornati gli altri strumenti
* Crea il cliente nel sistema di fatturazione con una **HTTP Request**
### Azioni condizionali
Usa le azioni **Filter** per:
* Onboarding diverso per Enterprise rispetto alle PMI
* Assegnatari diversi in base alla regione
* Salta le notifiche per le trattative di piccolo valore
### Includi dettagli offerta
Usa l'azione **Code** per formattare:
* Documenti riepilogativi della trattativa
* Note di passaggio per il team di Customer Success
* Checklist di onboarding personalizzate
## Correlati
* [Azioni dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-actions)
* [Inviare email dai flussi di lavoro](/l/it/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,136 @@
---
title: Rileva opportunità stagnanti
description: Notifica automaticamente i responsabili quando le opportunità non sono state aggiornate.
---
Mantieni in salute la tua pipeline avvisando i responsabili quando le opportunità diventano stagnanti. Questo flusso di lavoro verifica le opportunità che non sono state aggiornate in un numero di giorni specificato.
## Il problema
Le opportunità senza aggiornamenti comportano:
* Trattative che si raffreddano
* Previsioni inaffidabili
* Perdita di ricavi
## La soluzione
Crea un flusso di lavoro pianificato che individua le opportunità stagnanti e invia un'email ai loro responsabili.
## Configurazione passo-passo
### Passaggio 1: Crea il flusso di lavoro
1. Vai a **Impostazioni → Flussi di lavoro**
2. Fai clic su **+ Nuovo flusso di lavoro**
3. Assegna il nome "Avviso di opportunità stagnanti"
### Passaggio 2: Configura il trigger
1. Seleziona **On a Schedule**
2. Imposta l'esecuzione giornaliera (ad es., ogni giorno alle 8:00)
### Passaggio 3: Cerca le opportunità stagnanti
1. Aggiungi un'azione **Search Records**
2. Configura:
| Campo | Valore |
| ----------- | ---------------------------------------------- |
| **Oggetto** | Opportunità |
| **Filtro** | Updated At è precedente a (oggi - 7 giorni) |
| **Filtro** | Stage non è "Closed Won" AND non "Closed Lost" |
| **Limite** | 100 |
### Passaggio 4: Verifica se ne sono state trovate
1. Aggiungi l'azione **Filter**
2. Condizione: `{{searchRecords.length}}` è maggiore di 0
3. Se non ci sono opportunità stagnanti, il flusso di lavoro si ferma qui
### Passaggio 5: Formatta l'avviso (azione Code)
Aggiungi un'azione **Code** per formattare l'email:
```javascript
export const main = async (params) => {
const opportunities = params.opportunities;
// Group opportunities by owner
const byOwner = {};
opportunities.forEach(opp => {
const ownerEmail = opp.owner?.email || 'unassigned';
if (!byOwner[ownerEmail]) {
byOwner[ownerEmail] = [];
}
byOwner[ownerEmail].push({
name: opp.name,
amount: opp.amount,
lastUpdated: opp.updatedAt,
stage: opp.stage
});
});
// Format summary for manager
let summary = "Stale Opportunities Report\n\n";
Object.entries(byOwner).forEach(([owner, opps]) => {
summary += `${owner}: ${opps.length} stale opportunities\n`;
opps.forEach(opp => {
summary += ` - ${opp.name} (${opp.stage})\n`;
});
summary += "\n";
});
return {
summary,
totalCount: opportunities.length
};
};
```
### Passaggio 6: Invia l'email di avviso
Aggiungi l'azione **Send Email**:
| Campo | Valore |
| ----------- | -------------------------------------------------------------------- |
| **A** | sales-manager@yourcompany.com |
| **Oggetto** | `🚨 {{code.totalCount}} opportunità stagnanti richiedono attenzione` |
| **Corpo** | `{{code.summary}}` |
### Passaggio 7: Testa e attiva
1. Fai clic su **Test** per eseguire il flusso di lavoro
2. Verifica che l'email contenga i dati corretti
3. Attiva quando sei pronto
## Opzioni di personalizzazione
### Modifica la soglia di stagnazione
Modifica il filtro di **Search Records** per passare da 7 giorni al periodo preferito:
* 3 giorni per vendite ad alta velocità
* 14 giorni per trattative enterprise
* 30 giorni per cicli di vendita lunghi
### Avvisa i singoli rappresentanti
Invece di un'unica email al responsabile, usa **Iterator** per inviare email personalizzate a ciascun rappresentante sulle proprie trattative stagnanti.
### Aggiungi un'escalation
Crea più flussi di lavoro con gravità crescente:
1. Giorno 7: Email al rappresentante
2. Giorno 14: Email al rappresentante + al responsabile
3. Giorno 21: Crea un'attività per il responsabile affinché intervenga
### Includi in Slack
Usa **HTTP Request** per inviare a un webhook Slack invece o in aggiunta all'email.
## Correlati
* [Azioni dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-actions)
* [Inviare email dai flussi di lavoro](/l/it/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,69 @@
---
title: Visualizza il numero di email ricevute
description: Crea un flusso di lavoro per contare e visualizzare automaticamente il numero di email ricevute da ciascun contatto.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/workflow-number-of-emails-received.png" style={{width:'100%'}} />
## Panoramica
Questo flusso di lavoro si attiva ogni volta che viene ricevuta una nuova email e aggiorna un campo personalizzato sul record Persona con il conteggio totale delle email provenienti da quel mittente.
## Prerequisiti
Prima di configurare questo flusso di lavoro, crea un campo personalizzato sull'oggetto **People**:
1. Vai a **Impostazioni → Modello dati → People**
2. Aggiungi un nuovo campo **Number**
3. Assegnagli un nome come "Numero di email ricevute da questa persona"
## Configurazione passo-passo
<VimeoEmbed videoId="1148700336" title="Dimostrazione video" />
### Passaggio 1: Configura il trigger
1. Vai su **Flussi di lavoro** e crea un nuovo flusso di lavoro
2. Seleziona **Record is Created** come trigger
3. Scegli **Message Participants** (disponibile sotto Oggetti avanzati)
<Note>
Un Message Participant è una combinazione di un ID messaggio e di un ID persona, che crea un record univoco per ogni messaggio. Questo è più semplice da tracciare rispetto ai Messaggi direttamente perché possiamo accedere al campo `handle`, che contiene l'indirizzo email del mittente (o del destinatario).
</Note>
### Passaggio 2: Filtra per ruolo
1. Aggiungi l'azione **Filter**
2. Imposta la condizione: **Role** uguale a **FROM**
Questo garantisce che tu conteggi solo i messaggi inviati da questa persona, non quelli inviati a questa persona.
### Passaggio 3: Cerca tutti i Message Participants con lo stesso handle
1. Aggiungi un'azione **Search Records**
2. Seleziona **Message Participants** come oggetto
3. Aggiungi dei filtri: **Handle** uguale all'handle del trigger (l'indirizzo email del mittente) e **Role** uguale a **FROM**
4. Aumenta il **Limit** da 1 a **200** (il massimo)
In questo modo si trovano tutti i messaggi provenienti da questo indirizzo email per ottenere il conteggio totale.
<Note>
L'azione Search Records è limitata a restituire al massimo 200 record. Tuttavia, poiché stai usando solo il valore `totalCount` (non i singoli record), questo passaggio restituirà il numero totale di email inviate da questa persona.
</Note>
### Passaggio 4: Aggiorna il record Persona con un'azione Create or Update Record
1. Aggiungi un'azione **Create or Update Record**
2. Seleziona **People** come oggetto
3. Trova la persona facendo corrispondere la sua email all'`handle` del Message Participant
4. Imposta il tuo campo personalizzato "Numero di email ricevute" su `{{searchRecords.totalCount}}`
Il valore `totalCount` dell'azione Search Records rappresenta il numero totale di email ricevute da questa persona.
## Correlati
* [Azioni dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-actions)
* [Crea campi personalizzati](/l/it/user-guide/data-model/how-tos/customize-your-data-model)
* [Azione Search Records](/l/it/user-guide/workflows/capabilities/workflow-actions#search-records)

View File

@@ -0,0 +1,170 @@
---
title: Visualizza i dati dei record correlati
description: Mostra i dati dei record correlati (ad es., informazioni sull'Azienda nelle Opportunità) usando i flussi di lavoro.
---
Visualizza i dati dei record correlati direttamente sui tuoi record — ad esempio, mostra il numero di dipendenti di un'Azienda nelle sue Opportunità. Questa soluzione alternativa con i flussi di lavoro è utile finché i campi annidati non sono disponibili nativamente.
## Casi d'Uso Comuni
| Fonte | Destinazione | Campi da copiare |
| ----------- | ------------ | --------------------------------------------------------- |
| Azienda | Opportunità | Settore, Dimensione aziendale, ARR |
| Persona | Opportunità | Email, Telefono, Qualifica |
| Opportunità | Azienda | Importo dell'ultimo affare, Data dell'ultimo affare vinto |
## Copia di campi di base
### Esempio: copia l'Email del contatto nell'Opportunità
**Obiettivo**: Quando imposti un Punto di contatto su un'opportunità, copia la sua email nell'opportunità per un accesso rapido.
### Prerequisito
Crea i campi di destinazione in **Impostazioni → Modello dati → Opportunità** prima di creare il flusso di lavoro:
* Email del contatto (tipo: Email)
* Telefono del contatto (tipo: Telefono)
### Impostazione
1. **Trigger**: Il record è aggiornato (Opportunità, campo Punto di contatto)
2. **Filtro**: Verifica che il Punto di contatto non sia vuoto
3. **Cerca record**: Trova la persona collegata
* Oggetto: Persone
* Filtro: ID uguale a `{{trigger.object.pointOfContact.id}}`
4. **Aggiorna record**:
* Oggetto: Opportunità
* Record: `{{trigger.object.id}}`
* Email del contatto: `{{searchRecords[0].email}}`
* Telefono del contatto: `{{searchRecords[0].phone}}`
## Copia di più campi
### Esempio: sincronizza le informazioni dell'Azienda con tutte le Opportunità correlate
**Obiettivo**: Quando i dettagli dell'azienda cambiano, aggiorna tutte le opportunità correlate.
### Impostazione
1. **Trigger**: Il record è aggiornato (Aziende)
* Campi: Settore, Dimensione aziendale, Ricavi annuali
2. **Cerca record**: Trova tutte le opportunità per questa azienda
* Oggetto: Opportunità
* Filtro: ID Azienda uguale a `{{trigger.object.id}}`
3. **Iteratore**: Itera su ciascuna opportunità
4. **Aggiorna record** (all'interno dell'iteratore):
* Oggetto: Opportunità
* Record: `{{iterator.currentItem.id}}`
* Settore aziendale: `{{trigger.object.industry}}`
* Dimensione aziendale: `{{trigger.object.companySize}}`
* ARR dell'azienda: `{{trigger.object.annualRevenue}}`
## Copia alla creazione del record
### Esempio: precompila l'Opportunità con i dati dell'Azienda
**Obiettivo**: Quando crei un'opportunità collegata a un'azienda, copia automaticamente le informazioni principali dell'azienda.
### Prerequisito
Crea i campi di destinazione in **Impostazioni → Modello dati → Opportunità**:
* Settore aziendale (tipo: Testo)
* Dimensione aziendale (tipo: Numero)
### Impostazione
1. **Trigger**: Il record è creato (Opportunità)
* Filtro: l'Azienda non è vuota
2. **Cerca record**: Recupera i dettagli dell'azienda collegata
* Oggetto: Aziende
* Filtro: ID uguale a `{{trigger.object.company.id}}`
3. **Aggiorna record**:
* Oggetto: Opportunità
* Record: `{{trigger.object.id}}`
* Settore aziendale: `{{searchRecords[0].industry}}`
* Dimensione aziendale: `{{searchRecords[0].employees}}`
<Note>
**Limitazione di Attività e Note**: Le relazioni su Attività e Note sono codificate come molte-a-molte e non sono ancora disponibili nei trigger o nelle azioni dei flussi di lavoro. Per accedere a queste relazioni, usa invece le [API](/l/it/developers/extend/api).
</Note>
## Sincronizzazione bidirezionale
### Esempio: mantieni sincronizzato il Contatto principale
**Obiettivo**: Quando cambia il contatto principale di un'azienda, aggiorna il contatto. Quando una persona diventa principale, aggiorna l'azienda.
### Flusso di lavoro 1: Azienda → Persona
1. **Trigger**: Il record è aggiornato (Aziende, campo Contatto principale)
2. **Aggiorna record**: Imposta "È Contatto principale" della persona su true
3. **Cerca record**: Trova il precedente contatto principale
4. **Aggiorna record**: Imposta "È Contatto principale" del contatto precedente su false
### Flusso di lavoro 2: Persona → Azienda
1. **Trigger**: Il record è aggiornato (Persone, È Contatto principale = true)
2. **Aggiorna record**: Imposta il Contatto principale dell'azienda su questa persona
<Note>
Fai attenzione con le sincronizzazioni bidirezionali per evitare loop infiniti. Usa filtri per verificare che il valore sia effettivamente cambiato prima di aggiornare.
</Note>
## Uso del codice per mappature complesse
### Esempio: trasformare i dati durante la copia
**Obiettivo**: Copia e formatta il numero di telefono dalla persona all'opportunità.
```javascript
export const main = async (params) => {
const { phone } = params;
if (!phone) return { formattedPhone: null };
// Remove non-numeric characters
const digits = phone.replace(/\D/g, '');
// Format as (XXX) XXX-XXXX
const formatted = digits.length === 10
? `(${digits.slice(0,3)}) ${digits.slice(3,6)}-${digits.slice(6)}`
: phone;
return { formattedPhone: formatted };
};
```
## Migliori Pratiche
### Evita i loop
* Non creare flussi di lavoro che si attivano a vicenda all'infinito
* Usa condizioni specifiche sui campi
* Aggiungi controlli per verificare se il valore è effettivamente cambiato
### Gestisci i dati mancanti
* Verifica sempre che il record di origine esista prima di copiare
* Fornisci valori predefiniti per i campi facoltativi
* Usa filtri per saltare quando il campo di origine è vuoto
### Prestazioni
* Esegui aggiornamenti in batch quando copi su molti record
* Usa flussi di lavoro pianificati per operazioni di sincronizzazione in blocco
* Valuta l'uso dell'Iteratore per aggiornamenti di più record
## Correlati
* [Azioni dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-actions)
* [Trigger dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-triggers)

View File

@@ -0,0 +1,202 @@
---
title: Campi formula
description: Crea campi formula usando i flussi di lavoro finché il supporto nativo non sarà disponibile.
---
Venti non supportano ancora i campi di formula nativi (arrivando nel 2026), ma puoi ottenere lo stesso risultato usando i flussi di lavoro. Questa soluzione alternativa consente di calcolare e compilare automaticamente i valori dei campi — dalle semplici concatenazioni alla logica aziendale più complessa.
## Casi d'Uso Comuni
| Caso d'uso | Esempio di formula |
| ------------------------ | ---------------------------------- |
| **Nome completo** | Nome + " " + Cognome |
| **Importo previsto** | Importo × Probabilità |
| **Giorni alla scadenza** | Data di scadenza - Oggi |
| **Giorni nella fase** | Oggi - Data di ingresso nella fase |
| **Punteggio lead** | Punti in base a criteri multipli |
<Tip>
Per un esempio completo del monitoraggio del tempo nelle fasi della pipeline, vedi [Traccia quanto tempo le opportunità restano in ogni fase](/l/it/user-guide/views-pipelines/how-tos/track-time-in-stage).
</Tip>
## Formula di base: concatenazione
### Esempio: compilazione automatica del nome completo
**Obiettivo**: combinare automaticamente nome e cognome in un campo nome completo.
### Impostazione
1. **Trigger**: il record viene aggiornato o creato (Persone)
2. **Filtro**: verifica che il nome o il cognome siano cambiati
3. **Azione di codice**:
```javascript
export const main = async (params) => {
const { firstName, lastName } = params;
const fullName = [firstName, lastName]
.filter(Boolean)
.join(' ');
return { fullName };
};
```
4. **Aggiorna record**: imposta Nome completo su `{{code.fullName}}`
## Formula numerica: importo previsto
### Esempio: calcolare il ricavo previsto
**Obiettivo**: moltiplicare l'importo dell'opportunità per la probabilità per ottenere l'importo previsto.
Vedi [Come mostrare l'importo previsto nella pipeline](/l/it/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline) per il flusso di lavoro completo.
### Impostazione
1. **Trigger**: il record viene aggiornato (Opportunità, campo Importo oppure Probabilità)
2. **Azione di codice**:
```javascript
export const main = async (params) => {
const { amount, probability } = params;
const expectedAmount = (amount || 0) * (probability || 0) / 100;
return { expectedAmount };
};
```
3. **Aggiorna record**: imposta Importo previsto su `{{code.expectedAmount}}`
## Formula sulle date: calcolo dei giorni
### Esempio: giorni alla scadenza dell'attività
**Obiettivo**: calcolare quanti giorni mancano alla data di scadenza di un'attività.
### Impostazione
1. **Trigger**: il record viene aggiornato o creato (Attività, campo Data di scadenza)
2. **Azione di codice**:
```javascript
export const main = async (params) => {
const { dueDate } = params;
if (!dueDate) {
return { daysUntilDue: null };
}
const due = new Date(dueDate);
const today = new Date();
const diffTime = due - today;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return { daysUntilDue: diffDays };
};
```
3. **Aggiorna record**: imposta Giorni alla scadenza su `{{code.daysUntilDue}}`
<Note>
I valori negativi indicano attività scadute. Puoi usare questo campo per filtrare o ordinare le attività per urgenza.
</Note>
## Formula condizionale: punteggio lead
### Esempio: calcolare il punteggio lead in base a criteri
**Obiettivo**: assegnare un punteggio ai lead in base alla dimensione aziendale, al settore e al coinvolgimento.
### Impostazione
1. **Trigger**: il record viene aggiornato (Persone o Aziende)
2. **Azione di codice**:
```javascript
export const main = async (params) => {
const { companySize, industry, hasEmail, hasPhone, source } = params;
let score = 0;
// Company size scoring
if (companySize === 'Enterprise') score += 30;
else if (companySize === 'Mid-Market') score += 20;
else if (companySize === 'SMB') score += 10;
// Industry scoring
const targetIndustries = ['Technology', 'Finance', 'Healthcare'];
if (targetIndustries.includes(industry)) score += 25;
// Contact info scoring
if (hasEmail) score += 10;
if (hasPhone) score += 15;
// Source scoring
if (source === 'Referral') score += 20;
else if (source === 'Website') score += 10;
return { leadScore: score };
};
```
3. **Aggiorna record**: imposta Punteggio lead su `{{code.leadScore}}`
## Formula di testo: estrazione del dominio
### Esempio: estrarre il dominio dall'email
**Obiettivo**: estrarre e archiviare automaticamente il dominio dell'email.
### Impostazione
1. **Trigger**: il record viene aggiornato (Persone, campo Email)
2. **Azione di codice**:
```javascript
export const main = async (params) => {
const { email } = params;
if (!email) return { domain: null };
const domain = email.split('@')[1]?.toLowerCase();
return { domain };
};
```
3. **Aggiorna record**: imposta il campo Dominio su `{{code.domain}}`
## Migliori Pratiche
### Prestazioni
* Attiva solo in caso di modifiche ai campi rilevanti
* Usa filtri per ignorare i record che non richiedono calcolo
* Evita calcoli complessi in flussi di lavoro ad alto volume
### Gestione degli errori
* Verifica i valori null/undefined prima dei calcoli
* Usa valori predefiniti quando i dati mancano
* Restituisci messaggi di errore chiari quando i calcoli falliscono
### Testing
* Esegui test con casi limite (campi vuoti, valori zero)
* Verifica manualmente i calcoli prima dell'attivazione
* Monitora le esecuzioni dei flussi di lavoro per risultati imprevisti
## Correlati
* [Come mostrare l'importo previsto nella pipeline](/l/it/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline)
* [Come tracciare il tempo in fase](/l/it/user-guide/views-pipelines/how-tos/track-time-in-stage)
* [Azioni dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-actions)

View File

@@ -0,0 +1,127 @@
---
title: Notificare ai colleghi una nota da rivedere
description: Invia notifiche email automatiche quando assegni a un collega la revisione di una nota.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<Note>
**Menzionare direttamente i colleghi nelle note non è ancora supportato.** Questa funzionalità è prevista per la seconda metà del 2026. Nel frattempo, questo flusso di lavoro fornisce una soluzione alternativa pratica.
</Note>
## La sfida
Vuoi menzionare un collega in una nota affinché riceva una notifica per rivederla. Al momento, Twenty non supporta le @menzioni nelle note o nelle attività.
## La soluzione alternativa
Invece di menzionare nel testo della nota, puoi:
1. Crea un campo di relazione **Reviewer** sull'oggetto Note
2. Assegna il revisore quando crei o modifichi la nota
3. Avere un flusso di lavoro inviare automaticamente una e-mail al revisore con un link alla nota
<Warning>
**Limitazione**: Questo approccio consente di assegnare un solo revisore per campo. Se devi notificare più persone, crea campi di relazione aggiuntivi (ad es., Reviewer 1, Reviewer 2). Questo non scala bene se devi taggare molti collaboratori in una volta sola.
</Warning>
## Configurazione passo-passo
### Passaggio 1: Crea il campo Reviewer
<img src="/images/user-guide/workflows/reviewer-field-for-note.png" style={{width:'100%'}} />
1. Vai a **Impostazioni → Modello dati → Note**
2. Fai clic su **Aggiungi campo**
3. Configura:
| Impostazione | Valore |
| --------------------- | --------------------------------------------- |
| **Name** | Reviewer |
| **Tipo** | Relazione |
| **Oggetto correlato** | Membro dello spazio di lavoro |
| **Tipo di relazione** | Molte note → Un membro dello spazio di lavoro |
4. Salva il campo
### Passaggio 2: Crea il flusso di lavoro
<VimeoEmbed videoId="1151897168" title="Dimostrazione video" />
#### Crea il trigger del flusso di lavoro
1. Vai alla vista principale e crea un nuovo flusso di lavoro
2. Seleziona **Record Updated** come trigger
3. Scegli **Note** come oggetto e specifica il campo Reviewer.
4. Questo si attiverà ogni volta che il revisore di una nota viene aggiornato.
#### Aggiungi un filtro per verificare che il revisore sia stato appena assegnato
Aggiungi un'azione **Filtro** per garantire che il flusso di lavoro prosegua solo quando è stato assegnato un revisore:
| Condizione | Valore |
| ------------ | ----------- |
| **Reviewer** | non è vuoto |
#### Cerca il membro dello spazio di lavoro
1. Aggiungi un'azione **Search Records**
2. Seleziona **Workspace Member** (nella sezione Oggetti avanzati)
3. Aggiungi un filtro:
| Condizione | Valore |
| ---------- | ------------------------------ |
| **ID** | uguale a `{{note.reviewerId}}` |
Questo recupera il record completo del membro dello spazio di lavoro, inclusi l'indirizzo email e il nome.
#### Invia l'email di notifica
1. Aggiungi un'azione **Send Email**
2. Configura:
| Campo | Valore |
| ----------- | --------------------------------------------------- |
| **A** | Search Record → First Workspace Member → User Email |
| **Oggetto** | Una nota richiede la tua revisione |
| **Corpo** | Vedi l'esempio sotto |
**Esempio di corpo dell'email:**
```text
Hi {{searchRecord.firstWorkspaceMember.name.firstName}},
You've been assigned to review a note.
View the note here:
https://yourSubDomain.twenty.com/object/note/{{recordIsUpdated.id}}
Best,
Twenty
```
<Note>
Sostituisci `yourSubDomain` con il tuo effettivo sottodominio dello spazio di lavoro Twenty.
</Note>
#### Esegui il test e attiva
1. Fai clic su **Test** per eseguire manualmente il flusso di lavoro
2. Crea o modifica una nota e assegna un revisore
3. Controlla la casella di posta del revisore per l'email di notifica
4. Attiva il flusso di lavoro
## Utilizzo
Una volta configurato, il tuo team può utilizzare questo flusso di lavoro:
1. Creando una nuova nota (o modificandone una esistente)
2. Selezionando un collega nel campo **Reviewer**
3. Il collega riceve automaticamente un'email con un link diretto alla nota
## Correlati
* [Trigger dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-triggers)
* [Inviare email dai flussi di lavoro](/l/it/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Crea campi personalizzati](/l/it/user-guide/data-model/how-tos/create-custom-fields)
* [Crea campi di relazione](/l/it/user-guide/data-model/how-tos/create-relation-fields)

View File

@@ -0,0 +1,106 @@
---
title: Invia avvisi via email per le attività in scadenza
description: Notifica automaticamente ai membri del team le attività imminenti o in ritardo.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/email_tasks_due.png" style={{width:'100%'}} />
Invia promemoria email quotidiani a ciascun membro del team sulle attività in scadenza oggi.
## Panoramica
Questo flusso di lavoro viene eseguito secondo una pianificazione e:
1. Recupera tutti i membri dello spazio di lavoro
2. Scorre ciascun membro
3. Trova le loro attività in scadenza oggi
4. Formatta e invia un'email personalizzata
## Configurazione passo-passo
<VimeoEmbed videoId="1147463514" title="Dimostrazione video" />
### Passaggio 1: Configura il trigger
1. Vai su **Impostazioni → Flussi di lavoro** e crea un nuovo flusso di lavoro
2. Seleziona **On a Schedule** come trigger
3. Usa un'espressione cron per ogni giorno alle 8:00: `0 8 * * *`
### Passaggio 2: Cerca tutti i membri dello spazio di lavoro
1. Aggiungi un'azione **Search Records**
2. Seleziona **Workspace Members** (nella sezione Oggetti avanzati)
3. Non sono necessari filtri — questo restituisce tutti i membri
### Passaggio 3: Aggiungi un Iterator
1. Aggiungi un'azione **Iterator**
2. Imposta l'array di input con i membri dello spazio di lavoro del passaggio precedente
3. Tutte le azioni all'interno dell'Iterator verranno eseguite una volta per membro
### Passaggio 4: Cerca le attività in scadenza oggi (all'interno dell'Iterator)
1. All'interno dell'Iterator, aggiungi un'azione **Search Records**
2. Seleziona **Tasks** come oggetto
3. Aggiungi filtri:
* **Assignee** = membro corrente dello spazio di lavoro (dall'Iterator)
* **Due Date** = oggi
### Passaggio 5: Formatta le attività nel corpo dell'email (all'interno dell'Iterator)
Aggiungi un'azione **Code** per formattare le attività in un elenco leggibile con link:
```javascript
export const main = async (params: {
tasksDue?: Array<{ id: string; title: string }> | null | string;
}) => {
const tasksDue =
typeof params.tasksDue === "string"
? JSON.parse(params.tasksDue)
: params.tasksDue;
if (!Array.isArray(tasksDue) || tasksDue.length === 0) {
return {
formattedTasks: "No tasks due today."
};
}
const formattedTasks = tasksDue
.map(
t =>
`${t.title}\nhttps://yourSubDomain.twenty.com/object/task/${t.id}`
)
.join("\n\n");
return { formattedTasks };
};
```
<Note>
Sostituisci `yourSubDomain` con il tuo effettivo sottodominio dello spazio di lavoro Twenty.
</Note>
### Passaggio 6: Invia email (all'interno dell'Iterator)
1. Aggiungi un'azione **Send Email** (sempre all'interno dell'Iterator)
2. Configura:
| Campo | Valore |
| ----------- | ------------------------------------------------------------------------------ |
| **A** | `{{iterator.currentItem.userEmail}}` (email del membro dello spazio di lavoro) |
| **Oggetto** | Le tue attività in scadenza oggi |
| **Corpo** | `{{code.formattedTasks}}` |
### Passaggio 7: Testa e attiva
1. Fai clic su **Test** per eseguire manualmente il flusso di lavoro
2. Controlla le caselle di posta per le email
3. Attiva il flusso di lavoro
## Correlati
* [Azioni dei flussi di lavoro](/l/it/user-guide/workflows/capabilities/workflow-actions)
* [Inviare email dai flussi di lavoro](/l/it/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Gestire gli array nelle azioni Code](/l/it/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)