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 2s

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,82 @@
---
title: Gestionarea tablourilor în acțiunile de cod
description: Aflați cum să gestionați corect intrările de tip tablou în acțiunile de cod din fluxurile de lucru.
---
Când lucrați cu tablouri în acțiunile de cod, este posibil să întâmpinați două provocări frecvente:
1. **Tablouri transmise ca șiruri** — datele din sisteme externe sau din pașii anteriori sosesc ca un șir în loc de un tablou propriu-zis
2. **Nu puteți selecta elemente individuale** — puteți selecta doar întregul tablou, nu câmpuri specifice din interiorul lui
Ambele pot fi rezolvate cu un nod de cod.
## Analizarea tablourilor din șiruri
Tablourile sunt adesea transmise între pașii unui flux de lucru ca șiruri sau JSON, mai degrabă decât ca tablouri native. Acest lucru se întâmplă când:
* Primirea de date de la API-uri externe prin HTTP Request
* Procesarea payload-urilor de webhook
* Transmiterea datelor între pașii fluxului de lucru
**Soluție**: Adăugați acest tipar la începutul acțiunii dvs. de cod:
```javascript
export const main = async (params: {
users: any;
}): Promise<object> => {
const { users } = params;
// Handle input that may come as a string or an array
const usersFormatted = typeof users === "string" ? JSON.parse(users) : users;
// Now you can safely work with usersFormatted as an array
return {
users: usersFormatted.map((user) => ({
...user,
activityStatus: String(user.activityStatus).toUpperCase(),
})),
};
};
```
Linia esențială `typeof users === "string" ? JSON.parse(users) : users` verifică dacă intrarea este un șir, o parsează dacă este necesar sau o folosește direct dacă este deja un tablou.
## Extragerea câmpurilor individuale din tablouri
Un webhook poate returna un tablou de forma `answers: [...]`, dar în pașii următori ai fluxului de lucru puteți selecta doar **întregul tablou** — nu și elemente individuale din interiorul lui.
**Soluție**: Adăugați un nod de cod pentru a extrage câmpuri specifice și a le returna ca obiect structurat:
```javascript
export const main = async (params: {
answers: any;
}): Promise<object> => {
const { answers } = params;
// Handle input that may come as a string or an array
const answersFormatted = typeof answers === "string"
? JSON.parse(answers)
: answers;
// Extract specific fields from the array
const firstname = answersFormatted[0]?.text || "";
const name = answersFormatted[1]?.text || "";
return {
answer: {
firstname,
name
}
};
};
```
Nodul de cod returnează un obiect structurat în locul unui tablou. În pașii următori, acum puteți selecta câmpuri individuale precum `answer.firstname` și `answer.name` din selectorul de variabile.
<Tip>
**Vrei să iterezi peste array în loc să extragi câmpuri?** Când un pas Code sau Logic Function returnează un array de nivel superior, îl poți trimite direct într-un [Iterator](/l/ro/user-guide/workflows/capabilities/use-iterator): selectează opțiunea pasului **Whole list** ca intrare pentru Iterator, apoi fă referire la fiecare element cu `{{iterator.currentItem}}` în interiorul buclei. În acest caz nu este nevoie să restructurezi array-ul într-un obiect.
</Tip>
<Tip>
Faceți clic pe pictograma pătrată din dreapta sus a editorului de cod pentru a-l afișa pe tot ecranul — util, deoarece lățimea implicită a editorului este limitată.
</Tip>

View File

@@ -0,0 +1,182 @@
---
title: Importați datele despre produse în Twenty
description: Sincronizați datele catalogului de produse dintr-un depozit de date în CRM-ul dvs., conform unui program.
---
Folosiți acest model pentru a menține Twenty sincronizat cu datele despre produse din depozitul dvs. de date (de ex., Snowflake, BigQuery, PostgreSQL).
## Structura fluxului de lucru
1. **Declanșator**: Conform unui program
2. **Code**: Interogați depozitul de date
3. **Code** (opțional): Formatați datele ca tablou
4. **Iterator**: Parcurgeți fiecare produs
5. **Upsert Record**: Creați sau actualizați în Twenty
<img src="/images/user-guide/workflows/create_users_workflow.png" style={{width:'100%'}} />
## Pasul 1: Programați declanșatorul
Configurați fluxul de lucru să ruleze la o frecvență care corespunde nevoilor dvs. privind actualitatea datelor:
* La fiecare 5 minute pentru sincronizare aproape în timp real
* La fiecare oră pentru date mai puțin critice
* Zilnic pentru actualizări în lot
## Pasul 2: Interogați depozitul dvs. de date
Adăugați o acțiune **Code** pentru a prelua datele recente:
```javascript
export const main = async () => {
const intervalMinutes = 10; // Match your schedule frequency
const cutoffTime = new Date(Date.now() - intervalMinutes * 60 * 1000).toISOString();
// Replace with your actual data warehouse connection
const response = await fetch("https://your-warehouse-api.com/query", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
query: `
SELECT id, name, sku, price, stock_quantity, updated_at
FROM products
WHERE updated_at >= '${cutoffTime}'
`
})
});
const data = await response.json();
return { products: data.results };
};
```
<Tip>
Filtrați după `updated_at >= last X minutes` pentru a prelua doar înregistrările modificate recent. Acest lucru menține sincronizarea eficientă.
</Tip>
## Pasul 3: Formatați datele (opțional)
Dacă depozitul dvs. de date returnează date într-un format care necesită transformare, adăugați o altă acțiune **Code**. Transformările uzuale includ conversii de tip, redenumirea câmpurilor și curățarea datelor.
### Exemplu: Date despre utilizatori cu câmpuri booleene și de stare
```javascript
export const main = async (params: {
users: any;
}): Promise<object> => {
const { users } = params;
const usersFormatted = typeof users === "string" ? JSON.parse(users) : users;
// Convert string "true"/"false" to actual booleans
const toBool = (v: any) => v === true || v === "true";
return {
users: usersFormatted.map((user) => ({
...user,
activityStatus: String(user.activityStatus).toUpperCase(),
isActiveLast30d: toBool(user.isActiveLast30d),
isActiveLast7d: toBool(user.isActiveLast7d),
isActiveLast24h: toBool(user.isActiveLast24h),
isTwenty: toBool(user.isTwenty),
})),
};
};
```
### Exemplu: Date de produs cu conversii de tip
```javascript
export const main = async (params: { products: any }) => {
const products = typeof params.products === "string"
? JSON.parse(params.products)
: params.products;
return {
products: products.map(product => ({
externalId: product.id,
name: product.name,
sku: product.sku,
price: parseFloat(product.price), // String → Number
stockQuantity: parseInt(product.stock_quantity),
isActive: product.status === "active" // String → Boolean
}))
};
};
```
### Exemplu: Formatarea datelor calendaristice și a valorilor monetare
```javascript
export const main = async (params: { deals: any }) => {
const deals = typeof params.deals === "string"
? JSON.parse(params.deals)
: params.deals;
return {
deals: deals.map(deal => ({
...deal,
// Convert Unix timestamp to ISO date
closedAt: deal.closed_timestamp
? new Date(deal.closed_timestamp * 1000).toISOString()
: null,
// Ensure amount is a number (remove currency symbols)
amount: parseFloat(String(deal.amount).replace(/[^0-9.-]/g, "")),
// Normalize stage names
stage: deal.stage?.toLowerCase().replace(/_/g, " ")
}))
};
};
```
### Transformări uzuale
| Format sursă | Format țintă | Cod |
| -------------------- | ---------------- | ---------------------------------------- |
| `"true"` / `"false"` | `true` / `false` | `v === true \|\| v === "true"` |
| `"123.45"` | `123.45` | `parseFloat(value)` |
| `"active"` | `"ACTIVE"` | `value.toUpperCase()` |
| `1704067200` (Unix) | Dată ISO | `new Date(v * 1000).toISOString()` |
| `"$1,234.56"` | `1234.56` | `parseFloat(v.replace(/[^0-9.-]/g, ""))` |
| `null` / `undefined` | `""` | `value \|\| ""` |
## Pasul 4: Parcurgeți produsele
Adăugați o acțiune **Iterator**:
* Intrare: `{{code.products}}`
Aceasta parcurge fiecare produs din array.
## Pasul 5: Efectuați upsert pentru fiecare înregistrare
În interiorul iteratorului, adăugați o acțiune **Upsert Record**:
| Setare | Valoare |
| ------------------ | -------------------------------------- |
| **Obiect** | Obiectul dvs. Product personalizat |
| **Potrivire după** | ID extern sau SKU (identificator unic) |
| **Nume** | `{{iterator.item.name}}` |
| **SKU** | `{{iterator.item.sku}}` |
| **Preț** | `{{iterator.item.price}}` |
<Tip>
Utilizați **Upsert** (actualizare sau creare) în loc să construiți ramuri separate pentru creare vs. actualizare. Se construiește mai rapid și este mai ușor de depanat.
</Tip>
## Exemple de cazuri de utilizare
| Sursa | Date |
| --------------------------- | ------------------------------------------- |
| **Sistem ERP** | Catalog de produse, prețuri, stocuri |
| **Platformă de e-commerce** | Comenzi, clienți, actualizări de produse |
| **Depozit de date** | Metrici agregate, date îmbogățite |
| **Sistem de inventar** | Niveluri de stoc, alerte de reaprovizionare |
## Conexe
* [Declanșatoare ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-triggers)
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)
* [Gestionați array-urile în acțiunile Code](/l/ro/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)

View File

@@ -0,0 +1,130 @@
---
title: Aduceți răspunsurile din Typeform în Twenty
description: Gestionați payload-ul webhook al Typeform pentru a crea potențiali clienți din răspunsurile la formular.
---
Pentru configurarea standard a unui webhook, consultați [Configurați un declanșator Webhook](/l/ro/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger). Acest articol acoperă gestionarea specifică necesară pentru structura payload-ului personalizat al Typeform.
### Pasul 1: Creați un flux de lucru Webhook
1. Accesați **Setări → Fluxuri de lucru**
2. Faceți clic pe **+ Flux de lucru nou**
3. Selectați **Webhook** ca declanșator
4. Copiați URL-ul webhook
### Pasul 2: Configurați Typeform
1. În Typeform, deschideți formularul dvs.
2. Accesați **Connect → Webhooks**
3. Lipiți URL-ul webhook al Twenty
4. Salvează
### Pasul 3: Înțelegeți payload-ul Typeform
Typeform trimite o structură JSON îmbricată. Iată un exemplu simplificat:
```json
{
"event_type": "form_response",
"form_response": {
"form_id": "abc123",
"submitted_at": "2025-01-15T10:30:00Z",
"answers": [
{
"text": "Jane",
"type": "text",
"field": { "id": "field1", "type": "short_text", "title": "First Name" }
},
{
"text": "Smith",
"type": "text",
"field": { "id": "field2", "type": "short_text", "title": "Last Name" }
},
{
"text": "Acme Corp",
"type": "text",
"field": { "id": "field3", "type": "short_text", "title": "Company" }
},
{
"email": "jane@acme.com",
"type": "email",
"field": { "id": "field4", "type": "email", "title": "Email" }
},
{
"type": "choice",
"field": { "id": "field5", "type": "dropdown", "title": "Team Size" },
"choice": { "label": "10-50" }
}
]
}
}
```
Lucruri importante de reținut:
* Datele formularului sunt îmbricate sub `form_response`
* **Răspunsurile sunt returnate ca un array**, nu ca câmpuri denumite
* Fiecare răspuns include tipul și titlul câmpului pentru referință
### Pasul 4: Extrageți câmpurile din array-ul răspunsurilor
Deoarece `answers` este un array, în pașii următori puteți selecta doar întregul array — nu câmpuri individuale. Adăugați o acțiune **Code** pentru a extrage câmpurile de care aveți nevoie:
```javascript
export const main = async (params: {
answers: any;
}): Promise<object> => {
const { answers } = params;
// Handle input that may come as a string or an array
const answersFormatted = typeof answers === "string"
? JSON.parse(answers)
: answers;
// Extract fields by position or by finding the field type
const firstName = answersFormatted[0]?.text || "";
const lastName = answersFormatted[1]?.text || "";
const company = answersFormatted[2]?.text || "";
const email = answersFormatted.find(a => a.type === "email")?.email || "";
const teamSize = answersFormatted.find(a => a.type === "choice")?.choice?.label || "";
return {
contact: {
firstName,
lastName,
company,
email,
teamSize
}
};
};
```
Acum, în pașii următori, puteți selecta `contact.firstName`, `contact.email` etc. din selectorul de variabile.
<Tip>
Pentru mai multe detalii despre gestionarea array-urilor în acțiunile Code, consultați [Gestionați array-urile în acțiunile Code](/l/ro/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions).
</Tip>
### Pasul 5: Creați înregistrarea
Adăugați o acțiune **Create Record**:
| Câmp | Valoare |
| ------------------- | ----------------------------------------------------- |
| **Obiect** | Persoane |
| **Prenume** | `{{code.contact.firstName}}` |
| **Nume de familie** | `{{code.contact.lastName}}` |
| **Email** | `{{code.contact.email}}` |
| **Companie** | Căutați sau creați pe baza `{{code.contact.company}}` |
### Pasul 6: Testați și activați
1. Trimiteți un răspuns de test în Typeform
2. Verificați rularea fluxului de lucru pentru a confirma că datele au fost capturate
3. Activați fluxul de lucru
## Conexe
* [Configurați un declanșator Webhook](/l/ro/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger)
* [Gestionați array-urile în acțiunile Code](/l/ro/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)

View File

@@ -0,0 +1,263 @@
---
title: Generați un PDF din Twenty
description: Creați un flux de lucru pentru a genera și atașa un PDF (de exemplu, o ofertă) la o înregistrare.
---
Generați sau preluați automat un PDF și atașați-l la o înregistrare în Twenty. Aceasta este utilizată frecvent pentru a crea oferte, facturi sau rapoarte care sunt asociate cu Companii, Oportunități sau alte obiecte.
## Prezentare generală
Acest flux de lucru folosește un **Manual Trigger** pentru ca utilizatorii să poată genera un PDF la cerere pentru orice înregistrare selectată. O **funcție logică** se ocupă de:
1. Descărcarea PDF-ului dintr-un URL (de la un serviciu de generare PDF)
2. Încărcarea fișierului în Twenty
3. Crearea unui atașament asociat înregistrării
## Cerințe
Înainte de a configura fluxul de lucru:
1. **Creați o cheie API**: Accesați **Settings → APIs** și creați o nouă cheie API. Vei avea nevoie de acest jeton pentru Funcția Logică.
2. **Configurați un serviciu de generare PDF** (opțional): Dacă doriți să generați dinamic fișiere PDF (de ex., oferte), utilizați un serviciu precum Carbone, PDFMonkey sau DocuSeal pentru a crea PDF-ul și a obține un URL de descărcare.
## Configurare pas cu pas
### Pasul 1: Configurați declanșatorul
1. Accesați **Workflows** și creați un nou flux de lucru
2. Selectați **Manual Trigger**
3. Alegeți obiectul la care doriți să atașați fișiere PDF (de ex., **Companie** sau **Oportunitate**)
<Tip>
Cu un declanșator manual, utilizatorii pot rula acest flux de lucru folosind un buton care apare în dreapta sus odată ce o înregistrare este selectată — aceasta rulează fluxul de lucru pentru a genera și atașează un PDF.
</Tip>
### Pasul 2: Adăugați o funcție logică
1. Adauga o actiune **Codul** (Functie Logica)
2. Creați o funcție nouă cu codul de mai jos
3. Configurați parametrii de intrare
#### Parametri de intrare
| Parametru | Valoare |
| ----------- | ----------------------- |
| `companyId` | `{{trigger.object.id}}` |
<Note>
Dacă atașați la un alt obiect (Persoană, Oportunitate etc.), redenumiți parametrul în mod corespunzător (de ex., `personId`, `opportunityId`) și actualizați funcția logică.
</Note>
#### Codul funcției logice
```typescript
export const main = async (
params: { companyId: string },
) => {
const { companyId } = params;
// Replace with your Twenty GraphQL endpoints (/metadata for metadata and files or /graphql for your records)
// Cloud: https://api.twenty.com/graphql
// Self-hosted: https://your-domain.com/graphql
const metadataGraphqlEndpoint = 'https://api.twenty.com/metadata';
const dataGraphqlEndpoint = 'https://api.twenty.com/graphql';
// Replace with your API key from Settings → APIs
const authToken = 'YOUR_API_KEY';
// Replace with your PDF URL
// This could be from a PDF generation service or a static URL
const pdfUrl = 'https://your-pdf-service.com/generated-quote.pdf';
const filename = 'quote.pdf';
// Step 1: Download the PDF file
const pdfResponse = await fetch(pdfUrl);
if (!pdfResponse.ok) {
throw new Error(`Failed to download PDF: ${pdfResponse.status}`);
}
const pdfBlob = await pdfResponse.blob();
const pdfFile = new File([pdfBlob], filename, { type: 'application/pdf' });
const fieldMetadataIdQuery = `
query FindUploadFileFieldMetadataId {
objects {
edges {
node {
nameSingular
fieldsList {
id
name
}
}
}
}
}
`;
// Step 2: Find a fieldMetadataId of "Attachment file" field in Attachments object with GraphQL API
const response = await fetch(metadataGraphqlEndpoint, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`
},
body: {
query: fieldMetadataIdQuery,
}
});
const result = await response.json();
const uploadFileFieldMetadataId = result.data.objects.edges.find(object => object.node.nameSingular === 'attachment').node.fieldsList.find(field => field.name === 'file').id;
// Step 3: Upload the file via GraphQL multipart upload
const uploadMutation = `
mutation UploadFilesFieldFile($file: Upload!, $fieldMetadataId: String!) {
uploadFilesFieldFile(file: $file, fieldMetadataId: $fieldMetadataId) {
id
}
}
`;
const uploadForm = new FormData();
uploadForm.append('operations', JSON.stringify({
query: uploadMutation,
variables: { file: null, fieldMetadataId: uploadFileFieldMetadataId },
}));
uploadForm.append('map', JSON.stringify({ '0': ['variables.file'] }));
uploadForm.append('0', pdfFile);
const uploadResponse = await fetch(metadataGraphqlEndpoint, {
method: 'POST',
headers: { Authorization: `Bearer ${authToken}` },
body: uploadForm,
});
const uploadResult = await uploadResponse.json();
if (uploadResult.errors?.length) {
throw new Error(`Upload failed: ${uploadResult.errors[0].message}`);
}
const fileId = uploadResult.data?.uploadFilesFieldFile?.id;
if (!fileId) {
throw new Error('No file id returned from upload');
}
// Step 4: Create the attachment linked to the company
const attachmentMutation = `
mutation CreateOneAttachment($data: AttachmentCreateInput!) {
createAttachment(data: $data) {
id
name
}
}
`;
const attachmentResponse = await fetch(dataGraphqlEndpoint, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: attachmentMutation,
variables: {
data: {
name: filename,
targetCompanyId: companyId,
file: [
{
fileId: fileId,
label: filename
}
]
},
},
}),
});
const attachmentResult = await attachmentResponse.json();
if (attachmentResult.errors?.length) {
throw new Error(`Attachment creation failed: ${attachmentResult.errors[0].message}`);
}
return attachmentResult.data?.createAttachment;
};
```
### Pasul 3: Personalizați pentru cazul dvs. de utilizare
#### Pentru a atașa la un alt obiect
Înlocuiți `targetCompanyId` cu câmpul corespunzător:
| Obiect | Nume câmp |
| ------------------- | -------------------------- |
| Companie | `targetCompanyId` |
| Persoană | `targetPersonId` |
| Oportunitate | `targetOpportunityId` |
| Obiect personalizat | `targetYourCustomObjectId` |
Actualizați atât parametrul funcției, cât și obiectul `variables.data` în mutația de atașare.
#### Pentru a utiliza un URL PDF dinamic
Dacă utilizați un serviciu de generare PDF, puteți:
1. Mai întâi creați o acțiune HTTP Request pentru a genera PDF-ul
2. Transmiteți URL-ul PDF returnat către funcția logică ca parametru
```typescript
export const main = async (
params: { companyId: string; pdfUrl: string; filename: string },
) => {
const { companyId, pdfUrl, filename } = params;
// ... rest of the function
};
```
### Pasul 4: Testați și activați
1. Salvați fluxul de lucru
2. Navigați la o înregistrare de tip Company
3. Faceți clic pe meniul **⋮** și selectați fluxul dvs. de lucru
4. Verificați secțiunea **Attachments** din înregistrare pentru a confirma că PDF-ul a fost atașat
5. Activați fluxul de lucru
## Combinare cu servicii de generare PDF
Pentru crearea de oferte sau facturi dinamice:
### Exemplu: Generați ofertă → Atașați PDF
| Pas | Acțiune | Scop |
| --- | ------------------------ | ------------------------------------------------------ |
| 1 | Manual Trigger (Company) | Utilizatorul inițiază dintr-o înregistrare |
| 2 | Căutare înregistrare | Obțineți detalii despre Opportunity sau despre poziții |
| 3 | Solicitare HTTP | Apelați API-ul de generare PDF cu datele înregistrării |
| 4 | Funcție logică | Descărcați și atașați PDF-ul generat |
### Servicii populare de generare PDF
* **Carbone** - Generare de documente pe bază de șabloane
* **PDFMonkey** - Creare dinamică de PDF-uri din șabloane
* **DocuSeal** - Platformă de automatizare a documentelor
* **Documint** - Generare de documente orientată pe API
Fiecare serviciu furnizează un API care returnează un URL PDF, pe care apoi îl puteți trece la Funcția Logică.
## Depanare
| Problemă | Soluție |
| ------------------------------------- | ---------------------------------------------------------------------------- |
| "Nu s-a reușit descărcarea PDF-ului" | Verificați că URL-ul PDF este accesibil și returnează un PDF valid |
| "Nu s-a reușit încărcarea" | Verificați că cheia API este validă și are permisiuni de scriere |
| "Nu s-a reușit crearea atașamentului" | Asigurați-vă că numele câmpului ID al obiectului corespunde obiectului țintă |
## Conexe
* [Declanșatoare ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-triggers)
* [Funcții logice](/l/ro/user-guide/workflows/capabilities/workflow-actions#code)
* [Generați o ofertă sau o factură din Twenty](/l/ro/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty)

View File

@@ -0,0 +1,144 @@
---
title: Generați o ofertă sau o factură din Twenty
description: Creați automat facturi în instrumente externe atunci când se închid oportunitățile.
---
Trimiteți automat datele oportunității către sistemul dvs. de facturare (Stripe, QuickBooks, Xero etc.) atunci când o oportunitate este câștigată.
## Structura fluxului de lucru
1. **Declanșator**: Înregistrarea este actualizată (Oportunitate)
2. **Filtru**: Etapă = Closed Won
3. **Căutare înregistrare**: Obțineți detaliile Companiei
4. **Cod** (opțional): Formatați payload-ul
5. **Cerere HTTP**: Trimiteți către sistemul de facturare
## Pasul 1: Configurați declanșatorul
1. Creați un nou flux de lucru
2. Selectați declanșatorul **Record is Updated**
3. Alegeți **Opportunity** ca obiect
## Pasul 2: Filtrați pentru Closed Won
Adăugați o acțiune **Filter** pentru a continua doar când oportunitatea este câștigată:
| Setare | Valoare |
| ------------ | ------------------------------------- |
| **Câmp** | Etapa |
| **Condiție** | Egal |
| **Valoare** | `CLOSED_WON` (sau numele etapei dvs.) |
<Tip>
Declanșatorul se activează la orice actualizare a unei Oportunități. Filtrul asigură că fluxul de lucru continuă doar când etapa se schimbă la Closed Won.
</Tip>
## Pasul 3: Obțineți detalii despre Companie
Înregistrarea Oportunității s-ar putea să nu includă toate câmpurile Companiei de care aveți nevoie pentru factură. Adăugați o acțiune **Search Record**:
| Setare | Valoare |
| ------------------ | ----------------------------------------- |
| **Obiect** | Companie |
| **Potrivire după** | ID egal cu `{{trigger.object.companyId}}` |
Aceasta preia înregistrarea completă a Companiei cu adresa de facturare, ID fiscal etc.
## Pasul 4: Formatați payload-ul (opțional)
Dacă sistemul dvs. de facturare așteaptă un format specific, adăugați o acțiune **Code**:
```javascript
export const main = async (params: {
opportunity: any;
company: any;
}): Promise<object> => {
const { opportunity, company } = params;
return {
invoice: {
// Customer info from Company
customer_name: company.name,
customer_email: company.email || "",
billing_address: {
line1: company.address?.street || "",
city: company.address?.city || "",
postal_code: company.address?.postalCode || "",
country: company.address?.country || ""
},
tax_id: company.taxId || null,
// Invoice details from Opportunity
amount: opportunity.amount,
currency: opportunity.currency || "USD",
description: `Invoice for ${opportunity.name}`,
due_days: 30,
// Reference back to Twenty
metadata: {
opportunity_id: opportunity.id,
company_id: company.id
}
}
};
};
```
## Pasul 5: Trimiteți către sistemul de facturare
Adăugați o acțiune **HTTP Request**:
| Setare | Valoare |
| ------------ | ------------------------------------------------------ |
| **Metodă** | POST |
| **URL** | Punctul final al API-ului sistemului dvs. de facturare |
| **Anteturi** | `Authorization: Bearer YOUR_API_KEY` |
| **Corp** | `{{code.invoice}}` sau mapați câmpurile direct |
### Exemplu: Factură Stripe
```
POST https://api.stripe.com/v1/invoices
Headers:
Authorization: Bearer sk_live_xxx
Content-Type: application/x-www-form-urlencoded
Body:
customer: {{company.stripeCustomerId}}
collection_method: send_invoice
days_until_due: 30
```
### Exemplu: Factură QuickBooks
```
POST https://quickbooks.api.intuit.com/v3/company/{realmId}/invoice
Headers:
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Body: {{code.invoice}}
```
## Rezumat complet al fluxului de lucru
| Pas | Acțiune | Scop |
| --- | ------------------------------------------- | ---------------------------------------------------------- |
| 1 | Declanșator: Înregistrarea este actualizată | Se activează la orice modificare a unei Oportunități |
| 2 | Filtru | Continuați doar dacă Etapa = Closed Won |
| 3 | Căutare înregistrare | Obțineți detaliile complete ale Companiei pentru facturare |
| 4 | Cod | Formatați datele pentru API-ul de facturare |
| 5 | Solicitare HTTP | Creați factura în sistemul extern |
## Sfaturi
* **Stocați ID-urile externe**: Salvați ID-ul facturii returnat de API înapoi în Oportunitate folosind o acțiune **Update Record**
* **Gestionarea erorilor**: Adăugați o ramură pentru a trimite o notificare dacă cererea HTTP eșuează
* **Testați mai întâi**: Utilizați modul sandbox/test al sistemului dvs. de facturare înainte de lansare
## Conexe
* [Generați un PDF din Twenty](/l/ro/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty) — atașați PDF-uri generate la înregistrări
* [Declanșatoare ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-triggers)
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)
* [Automatizări pentru Closed Won](/l/ro/user-guide/workflows/how-tos/crm-automations/closed-won-automations)

View File

@@ -0,0 +1,170 @@
---
title: Configurați un declanșator webhook
description: Primiți date de la servicii externe pentru a declanșa fluxuri de lucru.
---
Declanșatoarele webhook permit serviciilor externe să pornească fluxurile dvs. de lucru trimițând date către un URL unic. Folosiți-le pentru a conecta formulare, aplicații terțe și integrări personalizate.
## Când să folosiți webhook-uri
| Caz de utilizare | Exemplu |
| --------------------------- | ---------------------------------------------------------------- |
| **Formulare web** | Trimiterile din formularul de contact creează potențiali clienți |
| **Aplicații terțe** | Plată Stripe → creează o înregistrare de client |
| **Integrări personalizate** | Aplicația dvs. → automatizare în Twenty |
| **Instrumente no-code** | Conexiuni Zapier, Make, n8n |
## 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 (de ex., "Trimitere formular site")
### Pasul 2: Configurați declanșatorul webhook
1. Faceți clic pe blocul declanșator
2. Selectați **Webhook**
3. Veți primi un URL de webhook unic, de exemplu:
```
https://api.twenty.com/webhooks/workflow/abc123...
```
4. Copiați acest URL — veți avea nevoie de el pentru serviciul dvs. extern
### Pasul 3: Definiți structura de date așteptată
Pentru cererile **POST**, definiți structura așteptată a corpului:
1. Faceți clic pe **Define expected body**
2. Introduceți un exemplu JSON care corespunde cu ceea ce va trimite serviciul dvs.:
```json
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"company": "Acme Inc",
"message": "Interested in your product"
}
```
3. Faceți clic pe **Salvați** — aceasta creează variabile pe care le puteți utiliza în pașii următori
### Pasul 4: Adăugați acțiuni
Acum adăugați acțiuni care folosesc datele webhook-ului:
**Exemplu: Creați o înregistrare Person**
1. Adăugați acțiunea **Create Record**
2. Selectați obiectul **People**
3. Asociați câmpurile:
| Câmp | Valoare |
| --------------- | ----------------------------------------------------- |
| Prenume | `{{trigger.body.firstName}}` |
| Nume de familie | `{{trigger.body.lastName}}` |
| Email | `{{trigger.body.email}}` |
| Companie | Căutați sau creați pe baza `{{trigger.body.company}}` |
### Pasul 5: Testați webhook-ul
Înainte de activare, testați webhook-ul:
**Folosind cURL**:
```bash
curl -X POST https://api.twenty.com/webhooks/workflow/abc123... \
-H "Content-Type: application/json" \
-d '{"firstName":"Test","lastName":"User","email":"test@example.com"}'
```
**Folosind Postman sau similar**:
1. Creați o cerere POST către URL-ul webhook-ului
2. Setați antetul Content-Type la `application/json`
3. Adăugați corpul JSON de test
4. Trimiteți și verificați rulările fluxului de lucru
### Pasul 6: Activați
După testare, faceți clic pe **Activați** pentru a activa fluxul de lucru.
## Gestionarea diferitelor structuri de date
### Date îmbricate
Dacă webhook-ul trimite date îmbricate:
```json
{
"contact": {
"name": "John Doe",
"email": "john@example.com"
},
"source": "website"
}
```
Faceți referire astfel: `{{trigger.body.contact.email}}`
### Tablouri
Dacă datele includ tablouri:
```json
{
"items": [
{"name": "Product A", "qty": 2},
{"name": "Product B", "qty": 1}
]
}
```
Modul în care gestionați tablourile depinde de cazul dvs. de utilizare:
**Număr necunoscut de elemente → Folosiți Iterator**
Dacă trebuie să procesați fiecare element din tablou (de ex., să creați o înregistrare pentru fiecare), adăugați o acțiune **Code** pentru a analiza tabloul, apoi folosiți **Iterator**:
```javascript
export const main = async (params: { items: any }) => {
const items = typeof params.items === "string"
? JSON.parse(params.items)
: params.items;
return { items };
};
```
Apoi utilizați Iterator pentru a itera: `{{code.items}}`
**Câmpuri cunoscute/specifice → Extrageți în câmpuri denumite**
Dacă tabloul conține câmpuri specifice la care doriți să accesați individual (de ex., răspunsuri de formular în care poziția 0 este întotdeauna "prenume", poziția 1 este întotdeauna "nume"), adăugați o acțiune **Code** pentru a le extrage:
```javascript
export const main = async (params: { items: any }) => {
const items = typeof params.items === "string"
? JSON.parse(params.items)
: params.items;
return {
product: {
name: items[0]?.name || "",
qty: items[0]?.qty || 0
}
};
};
```
Acum puteți selecta `product.name` și `product.qty` individual în pașii următori.
<Tip>
Pentru mai multe detalii despre gestionarea tablourilor, consultați [Gestionarea tablourilor în acțiunile Code](/l/ro/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions).
</Tip>
## Conexe
* [Declanșatoare ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-triggers)
* [Acțiuni ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-actions)

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)

View File

@@ -0,0 +1,21 @@
---
title: Servicii Profesionale
description: Obține ajutor profesional în dezvoltarea fluxurilor de lucru complexe și a automatizărilor de la echipa Twenty și partenerii certificați.
---
## Când Aveți Nevoie de Ajutor Profesional?
Consultați servicii profesionale pentru:
* Integrări complexe multi-sistem
* Logică avansată de afaceri și reguli de automatizare
* Fluxuri de lucru pentru procesarea datelor la scară largă
* Dezvoltare API personalizată
* Instruirea echipei și optimizarea fluxurilor de lucru
* Când nu aveți resurse interne
## Opțiuni de Servicii
### Parteneri de implementare
Colaborați cu parteneri certificați pentru personalizări avansate. Contactați-ne la [contact@twenty.com](mailto:contact@twenty.com) pentru a ne conecta cu [partenerii noștri de implementare](https://twenty.com/partners).

View File

@@ -0,0 +1,170 @@
---
title: Depanarea fluxului de lucru
description: Probleme frecvente ale fluxurilor de lucru și cum să le rezolvați.
---
## Probleme comune și soluții
### Flux de lucru care nu se declanșează
**Simptome**: Fluxul de lucru nu rulează atunci când vă așteptați.
**Cauze posibile**:
1. **Flux de lucru neactivat**: Asigurați-vă că fluxul de lucru este setat pe "Active", nu pe "Draft"
2. **Condițiile declanșatorului nu sunt îndeplinite**: Verificați că declanșatorul corespunde evenimentului așteptat
3. **Câmp nemonitorizat**: Pentru declanșatoarele "Record is Updated", asigurați-vă că acel câmp specific este urmărit
4. **Permisiuni**: Verificați că aveți permisiunea de a rula fluxuri de lucru
**Soluții**:
* Verificați starea fluxului de lucru în lista fluxurilor de lucru
* Testați cu acțiunea specifică despre care considerați că îl declanșează
* Revizuiți configurarea declanșatorului
* Contactați administratorul dvs. despre permisiuni
### Declanșarea fluxului de lucru prea devreme (câmpuri goale)
**Simptome**: Când creați manual o înregistrare în UI, fluxul de lucru se declanșează înainte de a avea timp să completați toate câmpurile. Fluxul de lucru rulează cu valori ale câmpurilor în mare parte goale.
**De ce se întâmplă asta**: Twenty salvează totul în timp real — nu există moduri separate "edit" vs "read". Când creați o înregistrare, aceasta este salvată imediat, declanșând evenimentul "Record is created" înainte să puteți completa câmpuri suplimentare.
**Când "Record is created" funcționează bine**:
* Înregistrări create prin apeluri API (câmpurile sunt populate într-o singură cerere)
* Înregistrări create prin import
* Crearea automată de înregistrări din alte fluxuri de lucru
**Soluție**: Pentru înregistrările create manual în UI, folosiți **"Record is created or updated"** ca declanșator. Astfel:
* Fluxul de lucru se declanșează după ce utilizatorul a terminat de completat și salvat câmpurile
* Obțineți date complete în loc de valori goale
<Tip>
Dacă doriți ca fluxul de lucru să ruleze doar o singură dată per înregistrare, adăugați o acțiune Filter pentru a verifica un câmp precum `createdAt equals updatedAt` (prima salvare) sau folosiți un câmp checkbox personalizat pentru a urmări dacă fluxul de lucru a rulat deja.
</Tip>
### Acțiuni eșuate
**Simptome**: Fluxul de lucru rulează, dar unele acțiuni eșuează.
**Cauze posibile**:
1. **Date lipsă**: Câmpurile obligatorii sunt goale
2. **Referințe nevalide**: Variabilele din pașii anteriori nu există
3. **Erori API**: Serviciile externe returnează erori
4. **Probleme de permisiuni**: Acțiunea necesită permisiuni pe care nu le aveți
**Soluții**:
* Verificați detaliile rulării fluxului de lucru pentru mesaje de eroare
* Verificați că toate câmpurile obligatorii au valori
* Testați conexiunile API independent
* Revizuiți permisiunile rolurilor
### Erori ale cererilor HTTP
**Simptome**: Acțiunile HTTP Request eșuează sau returnează rezultate neașteptate.
**Coduri de eroare comune**:
* **400**: Cerere incorectă - verificați formatul corpului cererii
* **401**: Neautorizat - verificați cheia API
* **403**: Interzis - verificați permisiunile API
* **404**: Nu a fost găsit - verificați URL-ul punctului final
* **429**: Prea multe cereri - implementați limitarea ratei
* **500**: Eroare de server - problemă a serviciului extern
**Soluții**:
* Verificați URL-ul punctului final API
* Verificați antetele de autentificare
* Testați mai întâi apelul API în afara Twenty
* Adăugați tratare a erorilor în acțiunile Code
### Erori în acțiunile Code
**Simptome**: Codul JavaScript nu reușește să se execute.
**Probleme comune**:
1. **Erori de sintaxă**: Greșeli de tastare sau JavaScript invalid
2. **Variabile nedefinite**: Referire la variabile care nu există
3. **Erori de tip**: Operații pe tipuri de date greșite
4. **Depășiri de timp**: Codul durează prea mult să se execute
**Soluții**:
* Utilizați validarea integrată a editorului de cod
* Testați mai întâi logica codului într-o consolă JavaScript
* Adăugați instrucțiuni console.log pentru depanare
* Simplificați operațiunile complexe
### Emailul nu se trimite
**Simptome**: Acțiunea Send Email nu livrează emailuri.
**Cauze posibile**:
1. **Niciun cont de email conectat**: Verificați Settings → Accounts
2. **Adresă de email invalidă**: Emailul destinatarului are un format incorect
3. **Limite de trimitere**: S-au atins limitele de rată ale furnizorului de email
4. **Filtre de spam**: Emailurile sunt blocate
**Soluții**:
* Verificați conexiunea contului de email
* Validați adresele de email ale destinatarilor
* Verificați limitele furnizorului de email
* Revizuiți conținutul emailului pentru posibile declanșatoare de spam
## Depanarea fluxurilor de lucru
### Utilizarea rulărilor fluxurilor de lucru
1. Accesați editorul de fluxuri de lucru
2. Deschideți panoul **Runs**
3. Găsiți rularea eșuată
4. Faceți clic pentru a vedea detalii pas cu pas
5. Revizuiți mesajele de eroare și datele de ieșire
### Testarea pașilor individuali
1. Pentru acțiunile Code, folosiți butonul **Test**
2. Pentru cererile HTTP, testați endpoint-ul separat
3. Creați înregistrări de test pentru a declanșa fluxuri de lucru
4. Folosiți declanșatoare manuale pentru testare controlată
### Tipare comune de depanare
**Adăugați jurnalizare**:
Folosiți acțiuni Code pentru a înregistra valori intermediare pentru depanare.
**Izolați pașii**:
Testați fiecare pas independent pentru a identifica eșecurile.
**Verificați fluxul de date**:
Verificați că fiecare pas primește datele de intrare așteptate.
## Cele mai bune practici pentru a evita problemele
### Înainte de activare
* Testați temeinic în modul draft
* Validați toate conexiunile API
* Revizuiți cu atenție condițiile declanșatorului
* Documentați comportamentul așteptat
### În timpul dezvoltării
* Folosiți nume descriptive pentru pași
* Adăugați comentarii în acțiunile Code
* Testați cu date realiste
* Planificați pentru cazuri limită
### După activare
* Monitorizați îndeaproape rulările inițiale
* Configurați alerte pentru eșecuri
* Revizuiți în mod regulat istoricul rulărilor
* Mențineți fluxurile de lucru simple atunci când este posibil

View File

@@ -0,0 +1,236 @@
---
title: Întrebări frecvente despre fluxuri de lucru
description: Întrebări frecvente despre fluxurile de lucru din Twenty.
---
<AccordionGroup>
<Accordion title="De ce nu pot activa un flux de lucru?">
Este probabil o problemă de permisiuni. Aveți nevoie de acces la fluxuri de lucru pentru a le crea și activa.
**Soluție**: Contactați administratorul spațiului de lucru pentru a vă acorda acces la fluxuri de lucru în **Setări → Membri → Roluri**.
Dacă nu vedeți deloc secțiunea Fluxuri de lucru în bara laterală, acest lucru confirmă că este o problemă de permisiuni.
</Accordion>
<Accordion title="De ce nu văd butonul fluxului de lucru manual în bara de navigare de sus?">
Fluxurile de lucru manuale apar în bara de navigare doar dacă sunt configurate corect:
1. Fluxul de lucru trebuie să fie **activat** (nu în modul de schiță)
2. Poziționarea în bara de navigare trebuie setată la **Pinned**
3. Pentru declanșatoarele Single/Bulk, trebuie să vă aflați pe pagina obiectului corect
**Pentru a verifica**: Deschideți fluxul de lucru → faceți clic pe declanșator → verificați că "Navbar placement" este setat la "Pinned".
Puteți accesa oricând fluxurile de lucru manuale prin **Cmd + K** (sau **Ctrl + K**), indiferent de setările barei de navigare.
</Accordion>
<Accordion title="Care este diferența dintre declanșatoarele manuale Single, Global și Bulk?">
| Tip | Înregistrări necesare | Rulările fluxului de lucru |
| --- | --------------------- | -------------------------- |
\| **Global** | Niciuna | O dată, fără input de înregistrare |
\| **Single** | Una sau mai multe selectate | O dată pentru fiecare înregistrare selectată |
\| **Bulk** | Una sau mai multe selectate | O dată, cu toate înregistrările ca un array |
* **Global**: Utilizați când fluxul de lucru nu are nevoie de context de înregistrare (de ex., generarea unui raport)
* **Single**: Utilizați când doriți să procesați fiecare înregistrare selectată independent (de ex., trimiteți e-mailuri individuale)
* **Bulk**: Utilizați când aveți nevoie să procesați înregistrările împreună sau să optimizați utilizarea creditelor (necesită acțiunea Iterator)
Consultați [Declanșatoare ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-triggers) pentru detalii.
</Accordion>
<Accordion title="Nu văd un nod If/Else. Ce ar trebui să fac?">
Un nod If/Else explicit nu este încă disponibil, dar se află pe foaia noastră de parcurs.
**Soluție temporară**: Creați mai multe ramuri din pasul dvs., fiecare începând cu o acțiune **Filter**:
```
Step 1
│
├── Branch A: Filter (condition = true) → Actions...
│
└── Branch B: Filter (condition = false) → Actions...
```
Doar ramura în care condiția filtrului este îndeplinită își va executa acțiunile următoare.
Consultați [Cum să utilizați ramurile](/l/ro/user-guide/workflows/capabilities/workflow-branches) pentru un ghid pas cu pas.
</Accordion>
<Accordion title="Rulează ramurile fluxului de lucru în paralel?">
**Da**, ramurile rulează în paralel în mod implicit.
Dacă doriți ca doar o singură ramură să se execute:
* Adăugați o acțiune **Filter** la începutul fiecărei ramuri
* Setați condiții opuse (de ex., Ramura A: status = "Open", Ramura B: status ≠ "Open")
Ramurile care nu îndeplinesc condiția filtrului se opresc din execuție, în timp ce altele continuă.
</Accordion>
<Accordion title="Pot să îmbin din nou ramurile?">
**Da**. După ce ramurile paralele se finalizează, puteți adăuga un pas la care se conectează ambele ramuri.
În editorul de fluxuri de lucru:
1. Finalizați acțiunile din ramuri
2. Adăugați un pas nou după ramuri
3. Trageți conexiuni de la finalul fiecărei ramuri către acest pas nou
Pasul îmbinat se va executa după ce toate ramurile conectate se finalizează.
</Accordion>
<Accordion title="Care este limita rezultatelor pentru Search Records?">
**Search Records returnează maximum 200 de înregistrări.**
Dacă aveți nevoie să procesați mai multe:
* Adăugați filtre mai specifice pentru a reduce rezultatele
* Utilizați fluxuri de lucru programate pentru a procesa în loturi
* Luați în considerare utilizarea API-ului pentru operațiuni în masă
Pentru majoritatea fluxurilor de lucru, 200 de înregistrări sunt suficiente. Dacă atingeți frecvent această limită, luați în considerare restructurarea automatizării.
</Accordion>
<Accordion title="Pot adăuga persoane în CC în e-mailurile fluxurilor de lucru?">
**Încă nu.** Câmpurile CC și BCC pentru acțiunea Send Email se află pe foaia noastră de parcurs.
**Soluție temporară**: Adăugați mai multe acțiuni Send Email pentru a trimite către destinatari suplimentari sau utilizați un HTTP Request pentru a trimite printr-un serviciu extern de e-mail care acceptă CC.
</Accordion>
<Accordion title="Cum folosesc rezultatele din pașii anteriori?">
Fiecare acțiune produce date de ieșire care pot fi utilizate în pașii următori.
**Pentru a face referire la datele din pașii anteriori**:
* Utilizați selectorul de variabile când configurați un câmp
* Sau tastați direct `{{stepName.fieldName}}`
**Exemple**:
* Datele declanșatorului: `{{trigger.object.email}}`
* Rezultatele căutării: `{{searchRecords[0].name}}`
* Rezultatul codului: `{{code.calculatedValue}}`
Treceți cursorul peste orice câmp din configurația acțiunii pentru a vedea variabilele disponibile din pașii anteriori.
</Accordion>
<Accordion title="De ce eșuează Iteratorul?">
**Iterator necesită un input de tip array.** Probleme frecvente:
1. **Inputul nu este un array**: Asigurați-vă că transmiteți rezultate din Search Records sau dintr-o altă acțiune care returnează un array
2. **Array-ul este gol**: Adăugați un filtru înainte de Iterator pentru a verifica `{{searchRecords.length}} > 0`
3. **Variabilă selectată greșit**: Asigurați-vă că selectați array-ul în sine, nu o singură înregistrare
**Configurare corectă**:
1. Search Records (returnează un array)
2. Filter: length > 0
3. Iterator: selectați `{{searchRecords}}`
4. Acțiunile din interiorul iteratorului folosesc `{{iterator.currentItem.fieldName}}`
</Accordion>
<Accordion title="Care este timpul maxim de execuție pentru acțiunile Code?">
Acțiunile Code (funcții logice) au un **timeout implicit de 5 minute** (300 de secunde).
Timeoutul maxim configurabil este de **15 minute** (900 de secunde).
Dacă codul depășește această limită, acțiunea va eșua cu o eroare de timeout.
**Sfaturi pentru a evita timeout-urile**:
* Împărțiți operațiunile mari în bucăți mai mici folosind Iterator
* Evitați calculele grele; utilizați servicii externe prin HTTP Request pentru procesări intensive
* Optimizați codul pentru a reduce timpul de execuție
* Dacă aveți nevoie de procesare mai lungă, luați în considerare utilizarea fluxurilor de lucru programate care procesează datele în loturi
</Accordion>
<Accordion title="Cum citesc rulările fluxului de lucru?">
Rulările fluxului de lucru afișează istoricul execuției și vă ajută să depanați problemele.
**Accesarea rulărilor**:
* În editorul de fluxuri de lucru → panoul **Runs** din dreapta
* Sau accesați **Rulări ale fluxurilor de lucru** în bara laterală
**Înțelegerea unei rulări**:
* **Status**: Running, Completed, Failed, Waiting
* **Pași**: Vedeți ce pași au fost executați și rezultatul lor
* **Erori**: Faceți clic pe pașii eșuați pentru a vedea mesajele de eroare
* **Date**: Vizualizați datele de intrare/ieșire la fiecare pas
Consultați [Rulări ale fluxurilor de lucru](/l/ro/user-guide/workflows/capabilities/workflow-runs) pentru detalii.
</Accordion>
<Accordion title="De ce nu văd rulările fluxului meu de lucru?">
Rulările fluxului de lucru ar putea eșua imediat din cauza limitelor de rată. Douăzeci de ani implementează o limită dură de 5 000 de curse pe oră pe spațiu de lucru.
Dacă depășiți această limită, fluxurile de lucru sunt imediat marcate ca eșuate și nu vor apărea în lista de execuții.
**Scenarii comune care ating această limită**:
* Selectarea a mai mult de 5.000 de înregistrări cu un declanșator manual Single
* Mai multe fluxuri de lucru care rulează simultan în spațiul dvs. de lucru
* Declanșatoare automate cu frecvență ridicată (de ex., Record Updated pe un obiect aglomerat)
**Soluții**:
* Utilizați declanșatoare **Bulk** în loc de Single pentru a procesa multe înregistrări într-o singură rulare
* Eșalonați în timp operațiunile mari efectuate în loturi
* Folosiți filtre pentru a reduce frecvența declanșărilor
* Programați fluxurile de lucru intensive în afara orelor de vârf
</Accordion>
<Accordion title="Care sunt limitele de rată pentru fluxurile de lucru?">
Twenty are două limite de rată pentru a asigura stabilitatea sistemului:
| Limită | Valoare | Comportament |
| ------ | ------- | ------------ |
\| **Limită soft** | 100 rulări/minut | Rulările se pun în coadă cu statusul "Not Started", procesate treptat |
\| **Limită hard** | 5.000 rulări/oră | Rulările eșuează imediat |
**Limită soft (100/min)**: Fluxurile dvs. de lucru nu vor eșua — doar așteaptă în coadă și sunt procesate în timp. Puteți declanșa mai mult de 100 de înregistrări; execuția va fi mai lentă.
**Limită hard (5.000/oră)**: Se aplică întregului dvs. spațiu de lucru. Dacă toate fluxurile dvs. de lucru cumulate depășesc 5.000 de rulări într-o oră, rulările suplimentare vor eșua imediat.
**Sfaturi pentru a rămâne în limite**:
* Utilizați declanșatoare Bulk cu Iterator în locul declanșatoarelor Single pentru loturi mari
* Combinați automatizările înrudite în mai puține fluxuri de lucru
* Utilizați fluxuri de lucru programate pentru a distribui încărcarea în timp
</Accordion>
<Accordion title="Pot reîncerca o rulare de flux de lucru eșuată?">
**Nu, momentan nu există o funcționalitate de reîncercare automată.**
Dacă o rulare de flux de lucru eșuează, va trebui să:
1. Examinați eroarea în **Setări → Workflows → [Workflow-ul dvs.] → Runs**
2. Remediați problema (date, configurație sau serviciu extern)
3. Declanșați manual din nou fluxul de lucru pe înregistrarea/înregistrările afectate
**Sfaturi pentru a reduce eșecurile**:
* Adăugați noduri **Filter** pentru a valida datele înaintea acțiunilor
* Utilizați **Search Records** pentru a verifica dacă există înregistrări asociate
* Testați temeinic cu câteva înregistrări înainte de operațiuni în masă
Funcționalitatea de reîncercare automată este pe foaia noastră de parcurs pentru o versiune viitoare.
</Accordion>
<Accordion title="Ar trebui să dezactivez fluxurile de lucru înainte de importurile CSV?">
**Da, dacă fluxurile dvs. de lucru sunt declanșate de crearea sau actualizarea înregistrărilor.**
Când importați date prin CSV, fiecare înregistrare creată sau actualizată poate declanșa fluxuri de lucru. Un import mare (mii de înregistrări) ar putea:
* Atinge limita de 5.000 de rulări/oră
* Consumă un număr semnificativ de credite de flux de lucru
* Trimite e-mailuri sau notificări neașteptate
* Creează sarcini sau înregistrări duplicate
**Înaintea unui import în masă**:
1. Accesați **Setări → Fluxuri de lucru**
2. Identificați fluxurile de lucru declanșate de obiectul pe care îl importați
3. **Dezactivați**-le temporar
4. Rulați importul CSV
5. **Reactivați** fluxurile de lucru când ați terminat
**Alternativă**: Dacă aveți nevoie ca fluxurile de lucru să ruleze pe datele importate, importați în loturi mai mici pentru a rămâne în limitele de rată.
</Accordion>
<Accordion title="Cum îmi curăț aspectul fluxului de lucru?">
Dacă planșa fluxului de lucru arată dezordonată, cu noduri împrăștiate, o puteți organiza automat:
1. Faceți clic dreapta oriunde pe planșa fluxului de lucru
2. Faceți clic pe **Aranjează fluxul de lucru**
Acest lucru va rearanja automat toate nodurile într-un aspect curat și organizat.
</Accordion>
</AccordionGroup>