Twenty에서 PDF를 자동으로 생성하거나 가져와 레코드에 첨부합니다. 이는 Company, Opportunity 또는 기타 객체에 연결된 견적서, 송장, 보고서를 생성할 때 흔히 사용됩니다.
이 워크플로우는 수동 트리거를 사용하므로 사용자가 선택한 레코드에 대해 필요할 때 PDF를 생성할 수 있습니다. 로직 함수가 다음을 처리합니다:
- URL에서 PDF를 다운로드(PDF 생성 서비스에서 제공)
- 파일을 Twenty에 업로드
- 레코드에 연결된 첨부 파일 생성
사전 준비
워크플로우를 설정하기 전에:
- API 키 생성: Settings → APIs로 이동하여 새 API 키를 만드세요. 이 토큰은 로직 함수에 필요합니다.
- PDF 생성 서비스 설정(선택 사항): PDF를 동적으로 생성하려면(예: 견적서) Carbone, PDFMonkey, DocuSeal 같은 서비스를 사용해 PDF를 만들고 다운로드 URL을 받으세요.
단계별 설정
1단계: 트리거 구성
- 워크플로우로 이동해 새 워크플로우를 생성합니다
- 수동 트리거를 선택합니다
- PDF를 첨부할 객체를 선택하세요(예: Company 또는 Opportunity).
수동 트리거를 사용하면 사용자가 레코드를 선택한 후 우측 상단에 표시되는 버튼으로 이 워크플로우를 실행해 PDF를 생성하고 첨부할 수 있습니다.
2단계: 로직 함수 추가
- Code 액션(로직 함수)을 추가합니다
- 아래 코드로 새 함수를 만드세요
- 입력 매개변수를 구성하세요
입력 매개변수
| 매개변수 | 값 |
|---|
companyId | {{trigger.object.id}} |
다른 객체(Person, Opportunity 등)에 첨부하는 경우 해당 매개변수 이름을 바꾸고(예: personId, opportunityId) 로직 함수를 업데이트하세요.
로직 함수 코드
export const main = async (
params: { companyId: string },
) => {
const { companyId } = params;
// Replace with your Twenty GraphQL endpoint
// Cloud: https://api.twenty.com/graphql
// Self-hosted: https://your-domain.com/graphql
const graphqlEndpoint = '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' });
// Step 2: Upload the file via GraphQL multipart upload
const uploadMutation = `
mutation UploadFile($file: Upload!, $fileFolder: FileFolder) {
uploadFile(file: $file, fileFolder: $fileFolder) {
path
}
}
`;
const uploadForm = new FormData();
uploadForm.append('operations', JSON.stringify({
query: uploadMutation,
variables: { file: null, fileFolder: 'Attachment' },
}));
uploadForm.append('map', JSON.stringify({ '0': ['variables.file'] }));
uploadForm.append('0', pdfFile);
const uploadResponse = await fetch(graphqlEndpoint, {
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 filePath = uploadResult.data?.uploadFile?.path;
if (!filePath) {
throw new Error('No file path returned from upload');
}
// Step 3: Create the attachment linked to the company
const attachmentMutation = `
mutation CreateAttachment($data: AttachmentCreateInput!) {
createAttachment(data: $data) {
id
name
}
}
`;
const attachmentResponse = await fetch(graphqlEndpoint, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: attachmentMutation,
variables: {
data: {
name: filename,
fullPath: filePath,
companyId,
},
},
}),
});
const attachmentResult = await attachmentResponse.json();
if (attachmentResult.errors?.length) {
throw new Error(`Attachment creation failed: ${attachmentResult.errors[0].message}`);
}
return attachmentResult.data?.createAttachment;
};
3단계: 사용 사례에 맞게 사용자 지정
다른 객체에 첨부하려면
companyId를 해당 필드로 바꾸세요:
| 개체 | 필드 이름 |
|---|
| 회사 | companyId |
| 사람 | personId |
| 기회 | opportunityId |
| 사용자 지정 개체 | yourCustomObjectId |
함수 매개변수와 첨부 생성 mutation의 variables.data 객체를 모두 업데이트하세요.
동적 PDF URL을 사용하려면
PDF 생성 서비스를 사용하는 경우 다음을 수행할 수 있습니다:
- 먼저 PDF를 생성하기 위해 HTTP 요청 작업을 만듭니다
- 반환된 PDF URL을 로직 함수의 매개변수로 전달합니다
export const main = async (
params: { companyId: string; pdfUrl: string; filename: string },
) => {
const { companyId, pdfUrl, filename } = params;
// ... rest of the function
};
4단계: 테스트 및 활성화
- 워크플로우를 저장합니다
- Company 레코드로 이동합니다
- ⋮ 메뉴를 클릭하고 워크플로우를 선택합니다
- 레코드의 Attachments 섹션에서 PDF가 첨부되었는지 확인합니다
- 워크플로우를 활성화합니다
PDF 생성 서비스와 결합하기
동적 견적서나 송장을 생성하려면:
예시: 견적서 생성 → PDF 첨부
| 단계 | 작업 | 목적 |
|---|
| 1 | 수동 트리거(Company) | 사용자가 레코드에서 시작 |
| 2 | 레코드 검색 | Opportunity 또는 라인 아이템 세부정보 가져오기 |
| 3 | HTTP 요청 | 레코드 데이터를 사용해 PDF 생성 API 호출 |
| 4 | 서버리스 함수 | 생성된 PDF를 다운로드해 첨부 |
널리 사용되는 PDF 생성 서비스
- Carbone - 템플릿 기반 문서 생성
- PDFMonkey - 템플릿 기반 동적 PDF 생성
- DocuSeal - 문서 자동화 플랫폼
- Documint - API 우선 문서 생성
각 서비스는 PDF URL을 반환하는 API를 제공하며, 이 URL을 로직 함수에 전달할 수 있습니다.
문제 해결
| 문제 | 해결책 |
|---|
| ”PDF 다운로드 실패” | PDF URL에 접근할 수 있으며 유효한 PDF를 반환하는지 확인하세요 |
| ”업로드 실패” | API 키가 유효하고 쓰기 권한이 있는지 확인하세요 |
| ”첨부 파일 생성 실패” | 객체 ID 필드 이름이 대상 객체와 일치하는지 확인하세요 |
관련 항목