חשבוניות מתקבלות מספקים שונים, בפורמטים שונים, בשעות שונות — וכמעט תמיד מישהו במשרד מבזבז זמן יקר על סידורן הידני בתיקיות. זהו המקרה הקלאסי לאוטומציה: משימה חוזרת, צפויה, עם כללים ברורים. במדריך הזה נראה איך לבנות ב-Zoho Flow אוטומציה שמקבלת כל מייל שמגיע לתיבת חשבוניות ייעודית, מזהה לאיזה חודש הוא שייך, יוצרת או מאתרת תיקיית WorkDrive בפורמט YYYY-MM, ומעלה את כל הקבצים המצורפים — בלי שאף אחד יצטרך לגעת בעכבר. המדריך כולל גם את הקוד המלא של ה-custom function שמבצע את ההעלאה בפועל.
מה האוטומציה הזו עושה בפועל?
כל מייל שמגיע לתיבת חשבוניות ייעודית עם קובץ מצורף נתפס על ידי Zoho Flow. ה-flow מחשב לאיזה חודש קלנדרי המייל שייך, מאתר (או יוצר) תיקיית חודש מתאימה ב-Zoho WorkDrive בפורמט YYYY-MM, ומעלה לתוכה את כל הקבצים המצורפים. התוצאה הסופית: עץ תיקיות מסודר ב-WorkDrive שבו כל חשבונית נוחתת בתיקיית החודש הנכון ברגע שהיא מגיעה, בלי מיון ידני, בלי שכפולים, בלי טעויות.
מבנה ה-flow — שרשרת אחת עם נקודת החלטה אחת
ה-flow מורכב משרשרת לינארית עם פיצול אחד באמצע. הסדר הוא:
- Email received — הטריגר (Zoho Mail, עם פילטר 'has attachment').
- formatDate — custom function שממיר את תאריך הקבלה לפורמט YYYY-MM.
- Fetch folder — חיפוש ב-WorkDrive של תיקייה בשם הזה.
- Decision — האם התיקייה נמצאה?
- ענף 1 (תיקייה לא קיימת) — Create folder ואז uploadInvoice.
- ענף 2 (תיקייה קיימת, ברירת המחדל) — uploadInvoice ישירות.
- uploadInvoice — custom function שמבצע את ההעלאה בפועל מ-Zoho Mail ל-WorkDrive.
למה צריך custom function ולא action מובנה?
ל-Zoho Flow אין action מוכן בקטלוג שמעלה קובץ מצורף מ-Zoho Mail ישירות ל-Zoho WorkDrive. זה הצוואר בקבוק שגורם לרוב אנשי המקצוע שמנסים לבנות את ה-flow הזה לוותר באמצע. הפתרון הוא לכתוב פונקציה קצרה ב-Deluge שקוראת ישירות ל-API של שני המוצרים: בקשת attachment מ-Mail, ואז העלאה ל-WorkDrive. כל שאר ה-flow אלה רכיבי no-code סטנדרטיים.
דרישות מקדימות (one-time setup)
לפני שמתחילים לבנות את ה-flow, צריך להכין ארבעה דברים. הכנה לקויה כאן היא הסיבה הנפוצה ביותר ל-flow שלא עובד גם כשהוא 'מורכב נכון'.
- מנוי Zoho Flow בתשלום — custom functions לא זמינות בחינם. מנוי Zoho One כולל את הרמה המתאימה. אם הפונקציה לא נשמרת גם עם קוד טריוויאלי, זו כמעט תמיד הסיבה.
- מבנה תיקיות ב-WorkDrive — צרו Team Folder (לא תיקייה אישית) ובתוכו עץ של שנה/חודש בפורמט YYYY-MM. למשל: Finance → Monthly Invoices → 2026 → 2026-06, 2026-07 וכו׳. העתיקו את ה-folder ID של תיקיית האב (המחרוזת אחרי /folder/ ב-URL של WorkDrive).
- תיבת מייל ייעודית לחשבוניות — נתבו את כל החשבוניות לתיבה אחת. בגלל שכל מייל שם הוא חשבונית, ה-flow לא צריך פילטרים מורכבים, מספיק 'has attachment'.
- שני connections בעורך ה-custom function — אחד ל-Zoho Mail (עם הרשאות ZohoMail.messages.READ ו-ZohoMail.accounts.READ) ואחד ל-Zoho WorkDrive (עם WorkDrive.files.CREATE או WorkDrive.files.ALL). רשמו את ה-link names המדויקים של שניהם — הקוד יפנה אליהם בשמם, וטעות בשם גורמת לכשל אימות שקט בלי הודעת שגיאה ברורה.
שלב 1 — Trigger: Email received
פתחו flow חדש, בחרו App trigger, בחרו Zoho Mail ואז את הטריגר 'Email received'. הגדירו את ה-account לתיבת החשבוניות ואת ה-folder ל-Inbox שלה. תחת Filter criteria הוסיפו תנאי אחד בלבד: 'Has attachment?' is true. זה מבטיח שה-flow ירוץ רק על מיילים שבאמת נושאים קובץ. אחרי ההגדרה, הריצו test fetch כדי ש-Flow ידגום מייל אמיתי — הדגימה חושפת את שמות השדות (account, folderId, messageIdString וכו׳) שתשתמשו בהם בהמשך.
שלב 2 — Custom function: formatDate
ה-function הזה הופך את תאריך המייל לשם תיקיית החודש. בגלל ש-received-time מהטריגר הוא timestamp נומרי שה-date formatter לא מקבל ישירות, הדרך הפשוטה והאמינה היא לפרמט את ה-current datetime (ה-flow רץ תוך שניות מהגעת המייל, אז ההפרש זניח).
- Output variable: monthFolder
- Input (myDate): System Variable → Current datetime
- Format string: yyyy-MM
- התוצאה: מחרוזת כמו '2026-06'.
- שימו לב לאותיות: yyyy באותיות קטנות = שנה, MM באותיות גדולות = חודש. mm באותיות קטנות זה דקות — טעות קלאסית שגורמת לפלט מוזר כמו '2026-37'.
שלב 3 — WorkDrive: Fetch folder
מחפשים תיקייה ששמה זהה למחרוזת החודש בתוך תיקיית האב שלכם.
- Variable name: monthFolderLookup
- Folder name: ${monthFolder}
- Parent folder ID: ה-folder ID של תיקיית האב שהעתקתם בשלב ההכנה.
- Organization / Team / Team folder: בחרו את שלכם.
- אם נמצאה תיקייה — הצעד מחזיר את הפרטים שלה כולל ה-id. אם לא — הוא מחזיר ריק, וזה מה שה-Decision הבא יבדוק.
שלב 4 — Decision: האם התיקייה קיימת?
מוסיפים Decision step עם תנאי אחד. בדוגמה המקורית הסניף מתויג 'Folder Does not Exist': התנאי הוא 'Fetch folder → Folder ID is empty'. זה יוצר שני נתיבים — סניף התנאי (תיקייה חסרה) וסניף ה-Default (תיקייה קיימת). חשוב: התנאי בודק את ה-ID, לא את שם התיקייה.
שלב 5 — WorkDrive: Create folder (סניף 'תיקייה חסרה' בלבד)
על הסניף של 'תיקייה חסרה', יוצרים את תיקיית החודש כדי שחודשים עתידיים יתאספקו אוטומטית.
- Variable name: createdMonthFolder
- Folder name: ${monthFolder}
- Parent folder: Use a Custom Value = ה-folder ID של תיקיית האב.
- Organization / Team / Team folder: זהה לשלב Fetch folder.
שלב 6 — Custom function: uploadInvoice (על שני הסניפים)
זה ה-function שמבצע את העברת הקובץ בפועל מהמייל ל-WorkDrive. צרו אותו פעם אחת, ואז גררו עותק על כל אחד משני הסניפים. ההבדל היחיד בין שני העותקים הוא לאן destFolderId מצביע — בסניף ה-Default (תיקייה קיימת) הוא יצביע ל-${monthFolderLookup.id}, ובסניף 'תיקייה חסרה' הוא יצביע ל-${createdMonthFolder.id}. שלושת הארגומנטים האחרים זהים בשני העותקים. הקוד המלא של ה-function בסעיף הבא.
הקוד המלא של uploadInvoice — Deluge
הגדרת ה-function: return type = string. ארבעה input parameters, כולם string: accountId, folderId, messageId, destFolderId. שימו לב — בעורך החדש של Zoho Flow צריך לכתוב את חתימת הפונקציה והסוגריים בעצמכם (returnType name(params) { ... }), הדבקת הגוף בלבד תיכשל לשמור. שני הערכים שצריך להחליף בקוד הם שמות ה-connections מהשלב המקדים: 'invoicemail_connection' (מופיע פעמיים — להחליף את שניהם בשם של Mail connection שלכם) ו-'flow_workdrive_actions' (להחליף בשם של WorkDrive connection שלכם). הנה הקוד המלא:
string uploadInvoice(string accountId, string folderId, string messageId, string destFolderId) { attUrl = "https://mail.zoho.com/api/accounts/" + accountId + "/folders/" + folderId + "/messages/" + messageId + "/attachmentinfo"; attInfo = invokeurl [ url: attUrl type: GET connection: "invoicemail_connection" ]; attList = attInfo.get("data").get("attachments"); result = Map(); for each att in attList { attId = att.get("attachmentId"); attName = att.get("attachmentName"); fileUrl = "https://mail.zoho.com/api/accounts/" + accountId + "/folders/" + folderId + "/messages/" + messageId + "/attachments/" + attId; fileObj = invokeurl [ url: fileUrl type: GET connection: "invoicemail_connection" ]; uploadResp = zoho.workdrive.uploadFile(fileObj, destFolderId, attName, true, "flow_workdrive_actions"); result.put(attName, uploadResp); } return result.toString(); }
מה הקוד עושה, בעברית פשוטה
הפונקציה מבקשת מ-Zoho Mail את רשימת הקבצים המצורפים למייל שהפעיל את ה-flow. אחר כך, על כל קובץ מצורף בנפרד, היא מורידה את התוכן שלו ומעלה אותו לתיקיית היעד ב-WorkDrive. הדגל 'true' בקריאה ל-uploadFile אומר שאם קיים קובץ באותו שם — להעלות כעותק חדש במקום לדרוס. הלולאה מבטיחה שמייל עם 3 PDFs ימוקם ב-3 קבצים נפרדים בתיקייה, ולא רק הראשון. הפונקציה מחזירה Map ששמות הקבצים הם המפתחות והערכים הם תגובות ה-API של WorkDrive — שימושי לדיבוג.
מיפוי הארגומנטים של uploadInvoice
אחרי שמירת הפונקציה, גוררים אותה על כל סניף וממפים את ארבעת הארגומנטים:
| ארגומנט | ממופה ל- | הערה |
|---|---|---|
| accountId | ${trigger.account} | ה-account ID של Zoho Mail. |
| folderId | ${trigger.folderId} | תיקיית המייל שבה ה-email נמצא (לא תיקיית WorkDrive). |
| messageId | ${trigger.messageIdString} | השתמשו בגרסת ה-STRING — הגרסה הנומרית עלולה לאבד דיוק. |
| destFolderId (סניף Default) | ${monthFolderLookup.id} | כאשר התיקייה כבר קיימת ונמצאה ב-Fetch folder. |
| destFolderId (סניף תיקייה חסרה) | ${createdMonthFolder.id} | כאשר התיקייה נוצרה זה עתה ב-Create folder. |
בדיקת ה-flow לפני הפעלה
סדר הבדיקה הנכון הוא כזה:
- שמרו את ה-flow אבל השאירו אותו כבוי (OFF).
- מחשבון מייל אחר, שלחו מייל בדיקה עם PDF מצורף לתיבת החשבוניות.
- פתחו Test & Debug והריצו. בגלל שהתיקייה של החודש הנוכחי קיימת, ה-flow יעבור בסניף ה-Default.
- בדקו את הפלט של uploadInvoice — בהצלחה מוחזרת Map של שמות קבצים לתגובות העלאה.
- פתחו את WorkDrive וודאו שהקובץ נחת בתיקיית YYYY-MM הנכונה.
- כדי לבדוק את סניף ה-Create folder, שנו זמנית את הפלט של formatDate לחודש שאין לו תיקייה (למשל חודש עתידי), שלחו עוד מייל בדיקה, וודאו שהתיקייה נוצרה והקובץ נחת בתוכה. אחרי הבדיקה — החזירו את ה-flow למצבו המקורי ומחקו את תיקיית הבדיקה.
- כשכל הנתיבים עוברים — הפעילו את ה-flow (ON).
דברים לעקוב אחריהם בייצור
אחרי שה-flow רץ בייצור, יש כמה תרחישים שכדאי להכיר מראש כדי לא להופתע:
- שגיאות אימות בהעלאה — אם רואים 'Unauthorized', חברו מחדש את ה-WorkDrive connection. הטוקנים האלה נופלים מדי פעם.
- חשבוניות שהועברו (forwarded) — הקבצים מתויקים לפי תאריך הקבלה, לא לפי תאריך החשבונית המקורית. חשבונית ישנה שהועברה היום תתויק תחת החודש הנוכחי.
- תזמון גבולות חודש — בגלל ש-formatDate משתמש ב-current datetime, מייל שמעובד מיד אחרי חצות של ה-1 בחודש עלול ליפול לחודש החדש. זניח לחשבוניות, אבל כדאי לדעת.
- מעבר שנה — מומלץ להכין מראש את עץ התיקיות לשנה הבאה, או להרחיב את ה-flow כך שיצור גם את תיקיית השנה.
- קבצים מצורפים שאינם PCFs — הפונקציה מעלה כל קובץ מצורף ללא הבחנה. אם ספקים שולחים לוגו בחתימת המייל, הוא יעלה גם הוא. כדי למנוע את זה, הוסיפו בדיקת file type לפני ההעלאה בתוך הלולאה.
כמה זה חוסך ולמה זה משתלם
ההערכה הסטנדרטית בהטמעות שאנחנו מבצעים: עובד שמסדר חשבוניות ידנית מבזבז 30–60 דקות ביום על תיוק, כפול 22 ימי עבודה בחודש, כפול עלות שעת עבודה. ברוב המשרדים זה מתורגם להחזר השקעה תוך פחות מ-3 חודשים על פרויקט אוטומציה בעלות קבועה. בנוסף, החיסכון הלא מדיד — אפס חשבוניות אבודות, אפס תיקיות חסרות, ושום עובד לא צריך לזכור לארגן שום דבר — שווה לפעמים יותר מהזמן שנחסך.
Conclusion
אוטומציה של ניתוב חשבוניות היא אחת מההשקעות המהירות ביותר להחזר — חוסכת זמן יומיומי, מבטלת טעויות אנוש, ומשחררת מישהו במשרד ממשימה מייגעת שאף אחד לא נהנה ממנה. צוות 1T Solutions בונה אוטומציות ב-Zoho Flow לעסקים בישראל במסגרת פרויקטים במחיר קבוע, כולל כתיבה ובדיקה של כל ה-custom functions הנדרשות, חיבור ה-APIs, והדרכת הצוות. אנחנו מספקים הצעת מחיר כתובה תוך 24 שעות משיחת האפיון הראשונית. צרו איתנו קשר לשיחת אפיון ללא עלות.


