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: Răspuns automat la e-mailurile primite
description: Creează un flux de lucru care folosește IA pentru a tria e-mailurile primite și pentru a trimite automat răspunsuri în același fir.
---
Răspunde la e-mailurile primite în câteva secunde — nu în ore. Acest flux de lucru folosește un AI Agent pentru a filtra zgomotul (buletine de știri, spam, răspunsuri automate) și pentru a crea un răspuns personalizat la mesajele reale. Apoi, AI îl trimite ca un răspuns filetat în conversația originală.
## Cum funcționează firele de e-mail
Fiecare e-mail are un antet ascuns `Message-ID` — o amprentă unică atribuită de serverul de e-mail al expeditorului. Când răspundeți la un e-mail, clientul dvs. de e-mail setează un antet `In-Reply-To` care face referire la acea amprentă. Astfel, Gmail, Outlook și orice alt client grupează mesajele în fire de discuție.
În Twenty, acea amprentă este stocată ca `headerMessageId` pe obiectul Message. Fluxul dvs. de lucru o preia și o transmite în câmpul In-Reply-To al acțiunii Send Email.
## Construirea fluxului de lucru
### Pasul 1: Creați un flux de lucru nou
Accesați **Settings -> Workflows** și faceți clic pe **+ New Workflow**.
### Pasul 2: Declanșare la mesajele primite
Alegeți **When a Record is Created** și selectați **Messages**.
De fiecare dată când un e-mail ajunge în Twenty, aceasta se declanșează.
<img src="/images/user-guide/workflows/auto-reply/workflow-overview.png" style={{width:'100%'}} />
### Pasul 3: Căutați cine l-a trimis
Adăugați o acțiune **Search Records**.
Adresa expeditorului nu este în mesajul propriu-zis — se găsește în înregistrarea asociată Message Participant.
| Câmp | Valoare |
| ---------- | --------------------------------- |
| **Obiect** | Participanți la mesaj |
| **Filtru** | Mesajul **este** `{{trigger.id}}` |
| **Filtru** | Rolul **este** From |
| **Limită** | 1 |
Aceasta vă oferă e-mailul expeditorului în `handle` și numele acestuia în `displayName`.
<img src="/images/user-guide/workflows/auto-reply/find-sender.png" style={{width:'100%'}} />
### Pasul 4: Trimiteti si redactati un raspuns cu AI
Adăugați o acțiune **AI Agent**. Acest singur pas face două lucruri: decide dacă e-mailul merită un răspuns și, dacă da, redactează unul.
Folosiți un prompt de tipul:
```
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 răspunsul în câmpul `response`, la care pot face referire pașii următori.
<img src="/images/user-guide/workflows/auto-reply/ai-triage.png" style={{width:'100%'}} />
### Pasul 5: Ramificați în funcție de decizia AI
Adăugați o acțiune **If/Else** pentru a verifica dacă AI a decis să răspundă sau să o omită.
| Câmp | Valoare |
| ---------------------- | -------------------------------------------- |
| **Condiție** | AI Agent `response` **nu conține** `SKIP` |
| **Dacă este adevărat** | Continuați la Send Email |
| **Altfel** | Nu faceți nimic (fluxul de lucru se încheie) |
Spam-ul, buletinele informative și mesajele generate automat sunt ignorate. Tot restul trece la pasul următor.
<img src="/images/user-guide/workflows/auto-reply/should-reply.png" style={{width:'100%'}} />
### Pasul 6: Trimiteți un răspuns în același fir
Adăugați o acțiune **Send Email** pe ramura "if true". Faceți clic pe **Advanced options**, apoi pe **Add In-Reply-To**.
| Câmp | Valoare |
| --------------- | -------------------------------------- |
| **Către** | `{{Find Sender.first.handle}}` |
| **Subiect** | `Re: {{trigger.subject}}` |
| **Body** | `{{AI Triage & Draft Reply.response}}` |
| **In-Reply-To** | `{{trigger.headerMessageId}}` |
Câmpul In-Reply-To este cel care face ca acesta să fie un răspuns, nu o conversație nouă. Destinatarul îl vede afișat în fir sub e-mailul original în Gmail, Outlook sau orice alt client.
<img src="/images/user-guide/workflows/auto-reply/send-email.png" style={{width:'100%'}} />
<Tip>
**In-Reply-To** necesită un `message.headerMessageId` din declanșator — este amprenta unică a e-mailului, nu o adresă a destinatarului. Dacă îl lăsați necompletat, e-mailul se trimite în continuare, doar ca un mesaj independent.
</Tip>
<Warning>
Gmail folosește subiectul pentru a grupa mesajele în fire de discuție. Subiectul **trebuie** să înceapă cu `Re:` (inclusiv două puncte și spațiu) pentru ca Gmail să afișeze răspunsul în cadrul firului original. Fără acesta, răspunsul va apărea ca o conversație separată — chiar dacă antetul In-Reply-To este setat corect.
</Warning>
### Pasul 7: Testați și activați
Apăsați **Test**, apoi verificați clientul de e-mail. Răspunsul ar trebui să apară sub mesajul original.
Activați când sunteți mulțumit(ă) de rezultat.
## Idei pe care să le dezvoltați
* **Răspundeți doar VIP-urilor** — adăugați o ramură care verifică domeniul expeditorului sau dacă acesta există ca Contact în Twenty
* **Dirijați în funcție de intenție** — folosiți prompturi AI Agent separate pentru a trata diferit solicitările de vânzări față de cererile de asistență
* **Îmbogățiți înainte de a răspunde** — adăugați un pas Search Records pentru a include compania expeditorului sau istoricul tranzacțiilor în promptul AI, pentru răspunsuri mai personalizate

View File

@@ -0,0 +1,179 @@
---
title: Automatizări pentru Closed Won
description: Automatizați activitățile de după câștig atunci când oportunitățile se închid.
---
Când o tranzacție se închide, trebuie să se întâmple mai multe lucruri: actualizați starea companiei, notificați membrii echipei, creați sarcini de onboarding. Automatizați totul cu un singur flux de lucru.
## Problema
Atunci când o oportunitate trece la "Closed Won":
* Tipul companiei trebuie să se schimbe din "Prospect" în "Customer"
* Trebuie create sarcini de onboarding
* Echipa de Customer Success trebuie notificată
* Reprezentantul de vânzări are nevoie de confirmare
Efectuarea manuală a acestor pași consumă timp și este predispusă la erori.
## Soluția
Creați un flux de lucru care gestionează automat toate activitățile de după câștig.
## Configurare completă a fluxului de lucru
### Pasul 1: Creați fluxul de lucru
1. Accesați **Setări → Fluxuri de lucru**
2. Faceți clic pe **+ Flux de lucru nou**
3. Denumiți-l "Deal Won - Post-Win Automation"
### Pasul 2: Configurați declanșatorul
1. Selectați **Record is Updated**
2. Alegeți **Oportunități**
3. La "Fields to monitor", selectați **Stage**
### Pasul 3: Adăugați filtrul de stadiu
1. Adăugați acțiunea **Filter**
2. Condiție: `{{trigger.object.stage}}` este egal cu "Closed Won"
### Pasul 4: Actualizați tipul companiei
1. Adăugați acțiunea **Update Record**
2. Configurați:
| Câmp | Valoare |
| -------------------------- | ------------------------------- |
| **Obiect** | Companii |
| **Înregistrare** | `{{trigger.object.company.id}}` |
| **Tip** | Client |
| **Data primei tranzacții** | `{{trigger.object.closedAt}}` |
| **Proprietarul contului** | `{{trigger.object.owner.id}}` |
### Pasul 5: Creați o sarcină de onboarding
1. Adăugați acțiunea **Create Record**
2. Configurați:
| Câmp | Valoare |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Obiect** | Sarcini |
| **Titlu** | `Onboarding: {{trigger.object.name}}` |
| **Responsabil** | Membru al echipei de Customer Success |
| **Data scadenței** | Peste 3 zile |
| **Prioritate** | Ridicată |
| **Companie asociată** | `{{trigger.object.company.id}}` |
| **Oportunitate asociată** | `{{trigger.object.id}}` |
| **Descriere** | `Onboarding pentru noul client {{trigger.object.company.name}}. Valoarea tranzacției: {{trigger.object.amount}}` |
### Pasul 6: Notificați echipa de Customer Success
1. Adăugați acțiunea **Send Email**
2. Configurați:
| Câmp | Valoare |
| ----------- | ------------------------------------------------ |
| **Către** | customer-success@yourcompany.com |
| **Subiect** | `🎉 Client nou: {{trigger.object.company.name}}` |
| **Corp** | Consultați exemplul de mai jos |
**Exemplu de corp al e-mailului**:
```
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!
```
### Pasul 7: Confirmare către reprezentantul de vânzări
1. Adăugați încă o acțiune **Send Email**
2. Configurați:
| Câmp | Valoare |
| ----------- | ----------------------------------------------------------------------------------------------------------------- |
| **Către** | `{{trigger.object.owner.email}}` |
| **Subiect** | `✅ Tranzacție închisă: {{trigger.object.name}}` |
| **Corp** | Felicitări! Tranzacția a fost procesată. Echipa de Customer Success a fost notificată și onboarding-ul a început. |
### Pasul 8: Testați și activați
1. Testați mutând o oportunitate de test la "Closed Won"
2. Verifică:
* Tipul companiei schimbat la "Customer"
* Sarcină de onboarding creată
* Echipa de Customer Success a primit e-mailul
* Reprezentantul de vânzări a primit confirmarea
3. Activați când sunteți gata
## Gestionarea Closed Lost
Creați un flux de lucru similar pentru tranzacțiile pierdute:
### Declanșator
* Record is Updated (Oportunități, Stage = "Closed Lost")
### Acțiuni
1. **Create Record**: Sarcină pentru "Lost Deal Analysis"
2. **Update Record**: Adăugați motivul pierderii în înregistrarea companiei
3. **Send Email**: Notificați managerul privind tranzacția pierdută
## Avansat: Onboarding în mai mulți pași
Pentru onboarding complex, creați mai multe sarcini:
```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 };
};
```
Utilizați **Iterator** pentru a crea fiecare sarcină din array.
## Idei de personalizare
### Mențineți celelalte instrumente actualizate
* Creați un client în sistemul de facturare cu un **HTTP Request**
### Acţiuni condiţionate
Utilizați acțiunile **Filter** pentru:
* Onboarding diferit pentru enterprise vs IMM
* Responsabili diferiți în funcție de regiune
* Omiteți notificările pentru tranzacții mici
### Include detaliile tranzacției
Utilizați acțiunea **Code** pentru a formata:
* Documente cu rezumatul tranzacției
* Note de predare pentru echipa de Customer Success
* Liste de verificare personalizate pentru onboarding
## Conexe
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)
* [Trimiteți e-mailuri din fluxuri de lucru](/l/ro/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,136 @@
---
title: Detectați oportunitățile stagnante
description: Notificați automat managerii când oportunitățile nu au fost actualizate.
---
Mențineți pipeline-ul sănătos alertând managerii când oportunitățile devin stagnante. Acest flux de lucru verifică oportunitățile care nu au fost actualizate într-un număr specificat de zile.
## Problema
Oportunitățile lăsate fără actualizări duc la:
* Tranzacții care se răcesc
* Previziuni nesigure
* Venituri pierdute
## Soluția
Creați un flux de lucru programat care găsește oportunități stagnante și le trimite prin e-mail managerilor lor.
## Configurare pas cu pas
### Pasul 1: Creați fluxul de lucru
1. Accesați **Setări → Fluxuri de lucru**
2. Faceți clic pe **+ Flux de lucru nou**
3. Denumiți-l "Alertă pentru oportunități stagnante"
### Pasul 2: Configurați declanșatorul
1. Selectați **On a Schedule**
2. Setați să ruleze zilnic (de exemplu, în fiecare zi la 8 AM)
### Pasul 3: Căutați oportunități stagnante
1. Adăugați acțiunea **Search Records**
2. Configurați:
| Câmp | Valoare |
| ---------- | --------------------------------------------------- |
| **Obiect** | Oportunități |
| **Filtru** | Updated At este înainte de (astăzi - 7 zile) |
| **Filtru** | Stage nu este "Closed Won" ȘI nu este "Closed Lost" |
| **Limită** | 100 |
### Pasul 4: Verificați dacă s-au găsit rezultate
1. Adăugați acțiunea **Filter**
2. Condiție: `{{searchRecords.length}}` este mai mare decât 0
3. Dacă nu există oportunități stagnante, fluxul de lucru se oprește aici
### Pasul 5: Formatați alerta (acțiune Code)
Adăugați o acțiune **Code** pentru a formata e-mailul:
```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
};
};
```
### Pasul 6: Trimiteți e-mailul de alertă
Adăugați acțiunea **Send Email**:
| Câmp | Valoare |
| ----------- | ---------------------------------------------------------------- |
| **Către** | sales-manager@yourcompany.com |
| **Subiect** | `🚨 {{code.totalCount}} oportunități stagnante necesită atenție` |
| **Corp** | `{{code.summary}}` |
### Pasul 7: Testați și activați
1. Faceți clic pe **Test** pentru a rula fluxul de lucru
2. Verificați că e-mailul conține datele corecte
3. Activați când sunteți gata
## Opțiuni de personalizare
### Modificați pragul de stagnare
Modificați filtrul Search Records pentru a schimba de la 7 zile la perioada preferată:
* 3 zile pentru vânzări cu ritm ridicat
* 14 zile pentru tranzacții enterprise
* 30 de zile pentru cicluri de vânzări lungi
### Alerte pentru reprezentanți individuali
În loc de un singur e-mail către manager, folosiți **Iterator** pentru a trimite e-mailuri personalizate fiecărui reprezentant despre tranzacțiile lor stagnante.
### Adăugați escaladare
Creați mai multe fluxuri de lucru cu severitate în creștere:
1. Ziua 7: E-mail către reprezentant
2. Ziua 14: E-mail către reprezentant + manager
3. Ziua 21: Creați o sarcină pentru ca managerul să intervină
### Includeți în Slack
Utilizați **HTTP Request** pentru a posta către un webhook Slack în locul sau pe lângă e-mail.
## Conexe
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)
* [Trimiteți e-mailuri din fluxuri de lucru](/l/ro/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,69 @@
---
title: Afişare număr de e-mailuri primite
description: Creați un flux de lucru pentru a număra automat și afișa numărul de e-mailuri primite de la fiecare contact.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/workflow-number-of-emails-received.png" style={{width:'100%'}} />
## Prezentare generală
Acest flux de lucru declanșează de fiecare dată când se primește un nou e-mail și actualizează un câmp personalizat în Înregistrarea Persoanei cu numărul total de e-mailuri de la acel expeditor.
## Cerințe
Înainte de a configura acest flux de lucru, creaţi un câmp personalizat pe obiectul **Persoane**:
1. Mergeți la \*\*Setări → Model de date → Oameni \*\*
2. Adauga un nou camp **Numărul**
3. Numește-l ceva ca "Numărul de e-mailuri primite de la această persoană"
## Configurare pas cu pas
<VimeoEmbed videoId="1148700336" title="Demonstrație video" />
### Pasul 1: Configurați Declanșatorul
1. Mergeți la **Fluxuri de lucru** și creați un nou flux de lucru
2. Selectați **Înregistrarea este creată** ca declanșator
3. Alege **Participanţii la mesaje** (disponibil sub obiecte avansate)
<Note>
Un participant la mesaj este o combinație între un ID de mesaj și un ID de persoană, creând o înregistrare unică per mesaj. Acest lucru este mai uşor de urmărit decât mesajele direct, deoarece putem accesa câmpul "handle", care conţine adresa de e-mail a expeditorului (sau a destinatarului).
</Note>
### Pasul 2: Filtrare pe rol
1. Adaugă o acțiune **filtru**
2. Setaţi condiţia: **Rol** este egal cu **FROM**
Acest lucru vă asigură că numărați doar mesajele trimise de această persoană, nu le sunt trimise.
### Pasul 3: Caută toţi participanţii la mesaje cu acelaşi manual
1. Adăugați o **acțiune de căutare Records**
2. Selectați **Participanții la mesaje** ca obiect
3. Adaugă filtre: **Handle** este egal cu procesorul de la declanșatorul (adresa de e-mail a expeditorului) și **Rol** egal cu **FROM**
4. Crește **Limita** de la 1 la **200** (maxim)
Aceasta găsește toate mesajele de la această adresă de e-mail pentru a obține numărul total.
<Note>
Acțiunea de căutare Înregistrări este limitată la maxim 200 de înregistrări. Cu toate acestea, deoarece utilizaţi doar valoarea `totalCount` (nu înregistrările individuale), acest pas va returna numărul total de e-mailuri trimise de această persoană.
</Note>
### Pasul 4: Actualizați înregistrarea persoanei cu o acțiune de creare sau actualizare a înregistrării
1. Adăugați o acțiune **Creare sau Actualizare Înregistrare**
2. Selectează **persoane** ca obiect
3. Găsiți persoana potrivindu-și adresa de e-mail cu `handle` de la Participantul la Mesaj
4. Setaţi câmpul personalizat "Număr de e-mailuri primite" la `{{searchRecords.totalCount}}`
Valoarea `totalCount` din acțiunea de căutare Înregistrări reprezintă numărul total de e-mailuri primite de la această persoană.
## Conexe
* [Acțiuni flux de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)
* [Creare câmpuri personalizate](/l/ro/user-guide/data-model/how-tos/customize-your-data-model)
* [Search Records Action](/l/ro/user-guide/workflows/capabilities/workflow-actions#search-records)

View File

@@ -0,0 +1,170 @@
---
title: Afișarea datelor din înregistrări asociate
description: Afișați date din înregistrări asociate (de ex., informații despre Companie pe Oportunități) folosind fluxuri de lucru.
---
Afișați date din înregistrări asociate direct pe înregistrările dvs. — de exemplu, afișați numărul de angajați al unei Companii pe Oportunitățile sale. Această soluție de ocolire prin fluxuri de lucru este utilă până când câmpurile imbricate vor fi disponibile nativ.
## Cazuri de Utilizare Comune
| Sursa | Destinație | Câmpuri de copiat |
| ------------ | ------------ | ---------------------------------------------------------- |
| Companie | Oportunitate | Industrie, Dimensiunea Companiei, ARR |
| Persoană | Oportunitate | Email, Telefon, Funcție |
| Oportunitate | Companie | Suma ultimei tranzacții, Data ultimei tranzacții câștigate |
## Copiere de câmpuri de bază
### Exemplu: Copiați Emailul Contactului în Oportunitate
**Obiectiv**: Atunci când setați un Punct de Contact pe o oportunitate, copiați emailul persoanei în oportunitate pentru acces facil.
### Condiție prealabilă
Creați câmpurile destinație în **Settings → Data Model → Opportunities** înainte de a construi fluxul de lucru:
* Email Contact (tip: Email)
* Telefon Contact (tip: Phone)
### Configurare
1. **Declanșator**: Înregistrarea este actualizată (Oportunități, câmp Punct de Contact)
2. **Filtru**: Verificați că Punctul de Contact nu este gol
3. **Căutare înregistrări**: Găsiți persoana asociată
* Obiect: Persoane
* Filtru: ID egal cu `{{trigger.object.pointOfContact.id}}`
4. **Actualizați Înregistrarea**:
* Obiect: Oportunități
* Înregistrare: `{{trigger.object.id}}`
* Email Contact: `{{searchRecords[0].email}}`
* Telefon Contact: `{{searchRecords[0].phone}}`
## Copierea mai multor câmpuri
### Exemplu: Sincronizați informațiile Companiei cu toate Oportunitățile asociate
**Obiectiv**: Când se schimbă detaliile companiei, actualizați toate oportunitățile asociate.
### Configurare
1. **Declanșator**: Înregistrarea este actualizată (Companii)
* Câmpuri: Industrie, Dimensiunea Companiei, Venit Anual
2. **Căutare înregistrări**: Găsiți toate oportunitățile pentru această companie
* Obiect: Oportunități
* Filtru: ID Companie egal cu `{{trigger.object.id}}`
3. **Iterator**: Parcurgeți fiecare oportunitate
4. **Actualizați Înregistrarea** (în interiorul iteratorului):
* Obiect: Oportunități
* Înregistrare: `{{iterator.currentItem.id}}`
* Industria Companiei: `{{trigger.object.industry}}`
* Dimensiunea Companiei: `{{trigger.object.companySize}}`
* ARR al Companiei: `{{trigger.object.annualRevenue}}`
## Copiere la crearea înregistrării
### Exemplu: Precompletați Oportunitatea cu datele Companiei
**Obiectiv**: La crearea unei oportunități legate de o companie, copiați automat informațiile esențiale ale companiei.
### Condiție prealabilă
Creați câmpurile destinație în **Settings → Data Model → Opportunities**:
* Industria Companiei (tip: Text)
* Dimensiunea Companiei (tip: Number)
### Configurare
1. **Declanșator**: Înregistrarea este creată (Oportunități)
* Filtru: Compania nu este goală
2. **Căutare înregistrări**: Obțineți detaliile companiei asociate
* Obiect: Companii
* Filtru: ID egal cu `{{trigger.object.company.id}}`
3. **Actualizați Înregistrarea**:
* Obiect: Oportunități
* Înregistrare: `{{trigger.object.id}}`
* Industria Companiei: `{{searchRecords[0].industry}}`
* Dimensiunea Companiei: `{{searchRecords[0].employees}}`
<Note>
**Limitare Tasks and Notes**: Relațiile pentru Tasks și Notes sunt codificate ca many-to-many și nu sunt încă disponibile în declanșatoare sau acțiuni de flux de lucru. Pentru a accesa aceste relații, utilizați [API-ul](/l/ro/developers/extend/api) în schimb.
</Note>
## Sincronizare bidirecțională
### Exemplu: Mențineți contactul principal sincronizat
**Obiectiv**: Când se schimbă contactul principal al unei companii, actualizați contactul. Când o persoană devine principală, actualizați compania.
### Flux de lucru 1: Companie → Persoană
1. **Declanșator**: Înregistrarea este actualizată (Companii, câmp Contact principal)
2. **Actualizați Înregistrarea**: Setați "Is Primary Contact" al persoanei la true
3. **Căutare înregistrări**: Găsiți contactul principal anterior
4. **Actualizați Înregistrarea**: Setați "Is Primary Contact" al contactului anterior la false
### Flux de lucru 2: Persoană → Companie
1. **Declanșator**: Înregistrarea este actualizată (Persoane, Is Primary Contact = true)
2. **Actualizați Înregistrarea**: Setați Contactul principal al companiei la această persoană
<Note>
Aveți grijă cu sincronizările bidirecționale pentru a evita buclele infinite. Folosiți filtre pentru a verifica dacă valoarea chiar s-a schimbat înainte de a actualiza.
</Note>
## Utilizarea codului pentru mapare complexă
### Exemplu: Transformați datele în timpul copierii
**Obiectiv**: Copiați și formatați numărul de telefon de la persoană în oportunitate.
```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 };
};
```
## Cele mai bune practici
### Evitați buclele
* Nu creați fluxuri de lucru care se declanșează reciproc la nesfârșit
* Folosiți condiții specifice pe câmpuri
* Adăugați verificări pentru a vedea dacă valoarea chiar s-a schimbat
### Gestionați datele lipsă
* Verificați întotdeauna dacă înregistrarea sursă există înainte de copiere
* Furnizați valori implicite pentru câmpurile opționale
* Folosiți filtre pentru a omite atunci când câmpul sursă este gol
### Performanță
* Grupați actualizările când copiați către multe înregistrări
* Utilizați fluxuri de lucru programate pentru operațiuni de sincronizare în masă
* Luați în considerare utilizarea Iterator pentru actualizări multiple ale înregistrărilor
## Conexe
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)
* [Declanșatoare ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-triggers)

View File

@@ -0,0 +1,202 @@
---
title: Câmpuri de formulă
description: Creează câmpuri de formulă folosind fluxuri de lucru până când va fi disponibil suportul nativ.
---
Douăzeci de domenii nu acceptă încă formulă nativă (vin în 2026), dar puteți obține același rezultat folosind fluxuri de lucru. Această soluție temporară îți permite să calculezi și să completezi automat valorile câmpurilor — de la concatenări simple la logică de business complexă.
## Cazuri de Utilizare Comune
| Caz de utilizare | Exemplu de formulă |
| ------------------------- | ---------------------------------- |
| **Nume complet** | Prenume + " " + Nume |
| **Sumă estimată** | Sumă × Probabilitate |
| **Zile până la scadență** | Data scadenței - Astăzi |
| **Zile în stadiu** | Astăzi - Data intrării în stadiu |
| **Scor lead** | Puncte bazate pe criterii multiple |
<Tip>
Pentru un exemplu complet de urmărire a timpului în stadiile din pipeline, vezi [Urmărește cât timp rămân oportunitățile în fiecare stadiu](/l/ro/user-guide/views-pipelines/how-tos/track-time-in-stage).
</Tip>
## Formulă de bază: Concatenare
### Exemplu: Autocompletare nume complet
**Obiectiv**: Combină automat prenumele și numele într-un câmp de nume complet.
### Configurare
1. **Declanșator**: Înregistrarea este actualizată sau creată (Persoane)
2. **Filtru**: Verifică dacă prenumele sau numele s-a schimbat
3. **Acțiune de cod**:
```javascript
export const main = async (params) => {
const { firstName, lastName } = params;
const fullName = [firstName, lastName]
.filter(Boolean)
.join(' ');
return { fullName };
};
```
4. **Actualizează înregistrarea**: Setează Nume complet la `{{code.fullName}}`
## Formulă numerică: Sumă estimată
### Exemplu: Calculează venitul estimat
**Obiectiv**: Înmulțește suma oportunității cu probabilitatea pentru a obține suma estimată.
Vezi [Cum să afișezi suma estimată în pipeline](/l/ro/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline) pentru fluxul de lucru complet.
### Configurare
1. **Declanșator**: Înregistrarea este actualizată (Oportunități, câmpul Sumă SAU Probabilitate)
2. **Acțiune de cod**:
```javascript
export const main = async (params) => {
const { amount, probability } = params;
const expectedAmount = (amount || 0) * (probability || 0) / 100;
return { expectedAmount };
};
```
3. **Actualizează înregistrarea**: Setează Suma estimată la `{{code.expectedAmount}}`
## Formulă de dată: Calculul zilelor
### Exemplu: Zile până la scadența sarcinii
**Obiectiv**: Calculează câte zile rămân până la data scadenței unei sarcini.
### Configurare
1. **Declanșator**: Înregistrarea este actualizată sau creată (Sarcini, câmp Data scadenței)
2. **Acțiune de cod**:
```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. **Actualizează înregistrarea**: Setează Zile până la scadență la `{{code.daysUntilDue}}`
<Note>
Valorile negative indică sarcini întârziate. Poți folosi acest câmp pentru a filtra sau sorta sarcinile după urgență.
</Note>
## Formulă condițională: Scor lead
### Exemplu: Calculează scorul lead pe baza criteriilor
**Obiectiv**: Punctează lead-urile pe baza dimensiunii companiei, industriei și nivelului de implicare.
### Configurare
1. **Declanșator**: Înregistrarea este actualizată (Persoane sau Companii)
2. **Acțiune de cod**:
```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. **Actualizează înregistrarea**: Setează Scor lead la `{{code.leadScore}}`
## Formulă de text: Extracția domeniului
### Exemplu: Extrage domeniul din e-mail
**Obiectiv**: Extrage și stochează automat domeniul e-mailului.
### Configurare
1. **Declanșator**: Înregistrarea este actualizată (Persoane, câmp E-mail)
2. **Acțiune de cod**:
```javascript
export const main = async (params) => {
const { email } = params;
if (!email) return { domain: null };
const domain = email.split('@')[1]?.toLowerCase();
return { domain };
};
```
3. **Actualizează înregistrarea**: Setează câmpul Domeniu la `{{code.domain}}`
## Cele mai bune practici
### Performanță
* Declanșează doar la modificări relevante ale câmpurilor
* Folosește filtre pentru a omite înregistrările care nu necesită calcul
* Evită calcule complexe în fluxurile de lucru cu volum mare
### Gestionarea erorilor
* Verifică valorile null/undefined înainte de calcule
* Folosește valori implicite când lipsesc datele
* Returnează mesaje de eroare clare când calculele eșuează
### Testare
* Testează cu cazuri-limită (câmpuri goale, valori zero)
* Verifică manual calculele înainte de activare
* Monitorizează rulările fluxurilor de lucru pentru rezultate neașteptate
## Conexe
* [Cum să afișezi suma estimată în pipeline](/l/ro/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline)
* [Cum să urmărești timpul în stadiu](/l/ro/user-guide/views-pipelines/how-tos/track-time-in-stage)
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)

View File

@@ -0,0 +1,127 @@
---
title: Notificați colegii despre o notă de revizuit
description: Trimiteți notificări automate prin e-mail când atribuiți unui coleg revizuirea unei note.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<Note>
**Etichetarea colegilor direct în note nu este încă suportată.** Această funcție este planificată pentru a doua jumătate a anului 2026. Între timp, acest flux de lucru oferă o soluție practică de ocolire.
</Note>
## Provocarea
Doriți să etichetați un coleg într-o notă, astfel încât să primească o notificare pentru a o revizui. În prezent, Twenty nu suportă mențiuni cu @ în note sau sarcini.
## Soluția de ocolire
În loc să etichetați în textul notei, puteți:
1. Creați un câmp de relație **Reviewer** pe obiectul Note
2. Atribuiți recenzentul atunci când creați sau editați nota
3. Faceți un flux de lucru automat trimiteți un e-mail către examinator cu un link către notă
<Warning>
**Limitare**: Această abordare permite atribuirea unui singur recenzent per câmp. Dacă trebuie să notificați mai multe persoane, creați câmpuri de relație suplimentare (de ex., Reviewer 1, Reviewer 2). Aceasta nu scalează bine dacă trebuie să etichetați mulți colaboratori deodată.
</Warning>
## Configurare pas cu pas
### Pasul 1: Creați câmpul Reviewer
<img src="/images/user-guide/workflows/reviewer-field-for-note.png" style={{width:'100%'}} />
1. Accesați **Setări → Model de date → Note**
2. Faceți clic pe **Adaugă câmp**
3. Configurați:
| Setare | Valoare |
| ------------------ | -------------------------------------------- |
| **Name** | Reviewer |
| **Tip** | Relație |
| **Obiect asociat** | Membru al Spațiului de Lucru |
| **Tipul relației** | Multe note → Un membru al spațiului de lucru |
4. Salvați câmpul
### Pasul 2: Creați fluxul de lucru
<VimeoEmbed videoId="1151897168" title="Demonstrație video" />
#### Creați declanșatorul fluxului de lucru
1. Accesați vizualizarea principală și creați un nou flux de lucru
2. Selectați **Record Updated** ca declanșator
3. Alegeți **Note** ca obiect și specificați câmpul Reviewer.
4. Acesta se va declanșa ori de câte ori recenzentul unei note este actualizat.
#### Adăugați un filtru pentru a verifica dacă recenzentul tocmai a fost atribuit
Adăugați o acțiune **Filter** pentru a vă asigura că fluxul de lucru continuă doar atunci când este atribuit un recenzent:
| Condiție | Valoare |
| ------------ | ----------- |
| **Reviewer** | nu este gol |
#### Căutați membrul spațiului de lucru
1. Adăugați o acțiune **Search Records**
2. Selectați **Workspace Member** (sub obiecte avansate)
3. Adăugați un filtru:
| Condiție | Valoare |
| -------- | ----------------------------- |
| **ID** | egal cu `{{note.reviewerId}}` |
Aceasta preia înregistrarea completă a membrului spațiului de lucru, inclusiv adresa de e-mail și numele.
#### Trimiteți e-mailul de notificare
1. Adăugați o acțiune **Send Email**
2. Configurați:
| Câmp | Valoare |
| ----------- | --------------------------------------------------- |
| **Către** | Search Record → First Workspace Member → User Email |
| **Subiect** | O notă are nevoie de revizuirea dvs. |
| **Corp** | Consultați exemplul de mai jos |
**Exemplu de corp al e-mailului:**
```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>
Înlocuiți `yourSubDomain` cu subdomeniul real al spațiului dvs. de lucru Twenty.
</Note>
#### Testați și activați
1. Faceți clic pe **Test** pentru a rula manual fluxul de lucru
2. Creați sau editați o notă și atribuiți un recenzent
3. Verificați căsuța de e-mail a recenzentului pentru e-mailul de notificare
4. Activați fluxul de lucru
## Utilizare
După configurare, echipa dvs. poate utiliza acest flux de lucru astfel:
1. Creând o notă nouă (sau editând una existentă)
2. Selectând un coleg în câmpul **Reviewer**
3. Colegul primește automat un e-mail cu un link direct către notă
## Conexe
* [Declanșatoare ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-triggers)
* [Trimiteți e-mailuri din fluxuri de lucru](/l/ro/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Creați câmpuri personalizate](/l/ro/user-guide/data-model/how-tos/create-custom-fields)
* [Creați câmpuri de relație](/l/ro/user-guide/data-model/how-tos/create-relation-fields)

View File

@@ -0,0 +1,106 @@
---
title: Trimiteți alerte prin e-mail pentru sarcini scadente
description: Notificați automat membrii echipei despre sarcinile lor care urmează sau sunt restante.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/email_tasks_due.png" style={{width:'100%'}} />
Trimiteți mementouri zilnice prin e-mail fiecărui membru al echipei despre sarcinile sale scadente astăzi.
## Prezentare generală
Acest flux de lucru rulează conform unui program și:
1. Preia toți membrii spațiului de lucru
2. Parcurge fiecare membru
3. Găsește sarcinile lor scadente astăzi
4. Formatează și trimite un e-mail personalizat
## Configurare pas cu pas
<VimeoEmbed videoId="1147463514" title="Demonstrație video" />
### Pasul 1: Configurați declanșatorul
1. Accesați **Settings → Workflows** și creați un nou flux de lucru
2. Selectați **On a Schedule** ca declanșator
3. Utilizați o expresie cron pentru rulare zilnică la 8:00 AM: `0 8 * * *`
### Pasul 2: Căutați toți membrii spațiului de lucru
1. Adăugați acțiunea **Search Records**
2. Selectați **Workspace Members** (sub obiecte avansate)
3. Nu sunt necesare filtre — aceasta returnează toți membrii
### Pasul 3: Adăugați un Iterator
1. Adăugați o acțiune **Iterator**
2. Setați array-ul de intrare la membrii spațiului de lucru din pasul anterior
3. Toate acțiunile din interiorul iteratorului vor rula o dată pentru fiecare membru
### Pasul 4: Căutați sarcinile scadente astăzi (în interiorul Iterator)
1. În interiorul iteratorului, adăugați o acțiune **Search Records**
2. Selectați **Tasks** ca obiect
3. Adăugați filtre:
* **Assignee** = membrul curent al spațiului de lucru (din iterator)
* **Due Date** = astăzi
### Pasul 5: Formatați sarcinile în corpul e-mailului (în interiorul Iterator)
Adăugați o acțiune **Code** pentru a formata sarcinile într-o listă lizibilă cu linkuri:
```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>
Înlocuiți `yourSubDomain` cu subdomeniul real al spațiului dvs. de lucru Twenty.
</Note>
### Pasul 6: Trimiteți e-mail (în interiorul Iterator)
1. Adăugați o acțiune **Send Email** (tot în interiorul iteratorului)
2. Configurați:
| Câmp | Valoare |
| ----------- | ---------------------------------------------------------------------------- |
| **Către** | `{{iterator.currentItem.userEmail}}` (e-mailul membrului spațiului de lucru) |
| **Subiect** | Sarcinile dvs. scadente astăzi |
| **Corp** | `{{code.formattedTasks}}` |
### Pasul 7: Testați și activați
1. Faceți clic pe **Test** pentru a rula manual fluxul de lucru
2. Verificați căsuțele de intrare pentru e-mailuri
3. Activați fluxul de lucru
## Conexe
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)
* [Trimiteți e-mailuri din fluxuri de lucru](/l/ro/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Gestionați array-urile în acțiunile Code](/l/ro/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)