דלגו לתוכן

או התחילו מנקודה בטוחה: אינדקס הכלים המלא · מפת הטבלאות המרכזיות

מערכת חדשה — 14 יום חינם

דוחות

עודכן 30.08.2026

שני כלים, ומנוע אחד: כל הדוחות והשאילתות השמורות במוצר חיים במחלקה _DynamicQueries.

אותו מנגנון בדיוק, בשני מקומות בממשק:

הצורה איפה מופיעה מה מבדיל
דוח דף הדוחות — apps/mybusiness/Reports PageName: "apps/mybusiness/reports"
שאילתה שמורה הרשימה הנפתחת “שאילתות” בדף רשימה של ישות PageId + PageName הם אותו דף; FormName הוא הטופס שלו (בסגנון dynamic-table-formP113); Default: true הופך אותה לתצוגה הפותחת. חובה ShowFields — שאילתת ברירת מחדל בלי ShowFields מסתירה את כל עמודות הטבלה

לכן אותו כלי בונה גם “דוח מכירות לפי אחראי” בדף הדוחות, וגם את התצוגה שנפתחת כברירת מחדל בדף המכירות.

הפרמטר טיפוס חובה המשמעות
objectId String דוח בודד לפי מזהה
pageId String כל הדוחות של דף מסוים

בלי אף פרמטר מוחזרים הדוחות של הדף apps/mybusiness/reports (סינון לפי PageName), כ‑{ "results": [ … ] }. objectId שלא קיים מחזיר { "results": [] }.

הפרמטר טיפוס חובה המשמעות
report Object אובייקט הדוח
reportId String מזהה דוח קיים. קיים ⇒ עדכון; נעדר ⇒ יצירה
הקבוצה השדה המשמעות
זהות Name שם הדוח בעברית. חובה ביצירה (Error: Name is required). הימנעו מגרשיים וסוגריים — ראו המגבלה על קידוד
ClassName הטבלה שעליה שואלים. חובה ביצירה, תמיד — גם בשאילתת ישות (Error: ClassName is required)
מיקום PageName / PageId / FormName / Default לאיזה דף הדוח נקשר. שלחו גם PageId וגם PageName
עמודות ShowFields מערך מסלולי תצוגה — בלי שם המחלקה: "AccountId.Name", "OwnerId.name"
OptionalFields הגדרת כל עמודה: { field ✔, summary ✔, text, type, aggrField, aggrFunc, dateFormat }
סינון QueryElems פקדי הסינון שהמשתמש רואה — מבנה תנאי B
צורה IsAggr false = רשימה שטוחה של רשומות · true = מקובץ ומסוכם
PivotInfo { row, col, value } — טבלה צולבת. דורש IsAggr: true
CalculatedFields עמודות מחושבות
תצוגה Sort שדה מיון. מקף לסדר יורד: -createdAt. (זו גם הדרך היחידה למיון ברירת מחדל בדף רשימה — דרך שאילתה עם Default: true)
ShowSum כותרת שורת הסיכום — הערך הוא הכותרת, והוא מה שמפעיל את השורה. בלי גרשיים (ראו המגבלה על קידוד)
GridDivider רוחב פקד סינון בגריד. ברירת מחדל 4
AllowCsv כפתור ייצוא CSV
Url2Link הצגת URL כקישור
תזמון ScheduleSendAt { interval ✔, hour ✔, occurrence }
ScheduleSendTo כתובות מייל, מופרדות בפסיקים
הרשאות permissions מי רשאי לראות ולהשתמש. הכלי לא אוכף את הנוכחות שלו — בלי permissions הדוח נוצר עם ACL של הבעלים בלבד, ואף אחד אחר לא רואה אותו
editPermissions objectId של המשתמש שרשאי לערוך. חובה ביצירה עם Master Key (Error: Edit Permissions is required when creating a report with master key)

המבנה שגורם לרוב הכשלים

Section titled “המבנה שגורם לרוב הכשלים”

בדוח מקובץ (IsAggr: true), כל עמודה ב‑OptionalFields היא אחד משניים — וההבדל היחיד ביניהן הוא נוכחות aggrFunc:

שדה בלי aggrFunc (או עם "") הוא הקיבוץ. שדה עם aggrFunc הוא הערך.

זה הכול. אין דגל groupBy ואין דגל measure — הנוכחות של הפונקציה היא ההצהרה.

aggrFunc המשמעות
"" או מושמט קבץ לפי השדה הזה
dow · q · q/yy · mm · mm/yy · yy · dd/mm/yy · mm/dd/yy קבץ שדה תאריך לפי חלון הזמן הזה. mm/yy הוא סוס העבודה
count · sum · avg · min · max מדוד — זו עמודת הערך
JSON
{ "report": {
"Name": "מכירות לפי אחראי וחודש",
"ClassName": "Sales",
"PageName": "apps/mybusiness/reports",
"IsAggr": true,
"AllowCsv": true,
"PageId": "<ה-_id של דף Reports מ-Get-Site-Pages>",
"ShowFields": ["OwnerId.name", "createdAt", "Total"],
"OptionalFields": [
{ "field": "OwnerId.name", "aggrField": "OwnerId._User.name",
"text": "אחראי", "summary": "" },
{ "field": "createdAt", "aggrField": "createdAt",
"text": "חודש", "aggrFunc": "mm/yy", "summary": "" },
{ "field": "Total", "aggrField": "Total",
"text": "סכום", "aggrFunc": "sum", "summary": "sum" }
],
"QueryElems": [
{ "F": "SaleStatusId", "C": "exists", "T": "Pointer",
"P": { "targetClass": "SaleStatuses" }, "FText": "שלב קיים" }
],
"Sort": "-Total",
"ShowSum": "סיכום",
"GridDivider": 4,
"permissions": ["role:Admin", "role:Sales"],
"editPermissions": "2b0QVKoigE"
} }

summary הוא פונקציית שורת הסיכום של העמודה: sum/avg/min/max רק על עמודה מספרית. summary: "sum" על עמודת count של שדה מחרוזת (או על כל שדה שאינו Number) מפיל את שורת הסיכום ב‑400 — the type of the group aggregate field (Name) must be "Number"; השתמשו שם ב‑"" או count.

שלושת השדות שחייבים להתיישר

Section titled “שלושת השדות שחייבים להתיישר”

לכל עמודה בדוח מקובץ, שלושה ערכים חייבים להסכים:

המאפיין הפורמט הדוגמה
ShowFields[i] מסלול נקודה, בלי שם מחלקה "SaleStatusId.Name"
OptionalFields[i].field זהה ל‑ShowFields[i] "SaleStatusId.Name"
OptionalFields[i].aggrField מסלול מלא, עם שם המחלקה באמצע "SaleStatusId.SaleStatuses.Name"

IsAggr: false — רשימת רשומות כמו שהן. OptionalFields מצטמצם ל‑{ field, summary, text }, בלי aggrFunc ובלי aggrField, ו‑summary משמש רק לשורת הסיכום התחתונה.

JSON
{ "report": {
"Name": "דוח מכירות מפורט",
"ClassName": "Sales",
"PageName": "apps/mybusiness/reports",
"IsAggr": false,
"AllowCsv": true,
"PageId": "<ה-_id של דף Reports>",
"ShowFields": ["AccountId.Name", "Name", "SaleStatusId.Name", "OwnerId.name", "Total", "ClosingDate"],
"OptionalFields": [
{ "field": "AccountId.Name", "summary": "", "text": "לקוח" },
{ "field": "Name", "summary": "", "text": "שם מכירה" },
{ "field": "SaleStatusId.Name", "summary": "", "text": "סטטוס" },
{ "field": "OwnerId.name", "summary": "", "text": "אחראי" },
{ "field": "Total", "summary": "sum", "text": "סכום" },
{ "field": "ClosingDate", "summary": "", "text": "תאריך סגירה", "dateFormat": "Date" }
],
"Sort": "-createdAt",
"ShowSum": "סיכום",
"GridDivider": 4,
"permissions": ["role:Admin", "role:Sales"],
"editPermissions": "2b0QVKoigE"
} }

ערכי summary: "" · count (לכל טיפוס) · sum · avg · min · max (ל‑Number; min/max גם ל‑Date). ערכי dateFormat להצגה: DateTime · Date · Time · Year · Q/YY · MM/YY · Month · Quarter.

JSON
"PivotInfo": { "row": "OwnerId.name", "col": "createdAt", "value": "Total" }
  • row — שדה קיבוץ (בלי aggrFunc).
  • col — בדרך כלל תאריך עם aggrFunc של זמן.
  • value — מדד עם sum או count.
  • כל שלושתם חייבים להופיע גם ב‑ShowFields וגם ב‑OptionalFields, ודורש IsAggr: true.
  • תא שסכומו 0 מוצג כ‑NaN — פגם תצוגה בלבד.

מבנה תנאי B, בדיוק כמו בטבלאות תצוגה ובטריגרים:

JSON
"QueryElems": [
{ "F": "Name", "C": "contains", "T": "String", "V": "", "FText": "חיפוש שם" },
{ "F": "SaleStatusId", "C": "containedIn", "T": "Pointer", "V": [],
"P": { "targetClass": "SaleStatuses", "multiple": true }, "FText": "סטטוס" },
{ "F": "OwnerId", "C": "equalTo", "T": "Pointer", "V": "currentUser",
"P": { "targetClass": "_User" }, "FText": "אחראי" },
{ "F": "createdAt", "C": "greaterThanOrEqualTo", "T": "Date", "FText": "מתאריך" },
{ "F": "createdAt", "C": "lessThanOrEqualTo", "T": "Date", "FText": "עד תאריך" },
{ "F": "IsAccount", "C": "equalTo", "T": "Boolean", "V": false, "FText": "לידים בלבד" }
]
  • containedIn + P.multiple: true = בחירה מרובה. equalTo בלי multiple = בחירה יחידה.
  • "currentUser" = “הרשומות שלי”.
  • סינון לפי שדה בטבלה מקושרת נכתב עם שם המחלקה: "AccountId.Accounts.Name" — שימו לב שזה הפוך מ‑ShowFields, שם המחלקה לא מופיעה.

הממשק מסדר את הפקדים מימין לשמאל, מלמעלה למטה, לפי הסדר במערך.

  • GridDivider: 3 (ארבעה פקדים בשורה — האידיאלי) או 4 (שלושה בשורה) כשיש מספיק פקדים למלא שורה. 6 ו‑12 מותחים פקד על חצי מסך או על כולו, וזה נראה שבור, אלא אם באמת יש רק פקד או שניים. זה בדיוק מה שסכימת הכלי ממליצה: “for one field the number should be 12. for 2 fields the value is 6”.
  • סדר המערך: חיפושי טקסט ← בחירות מרובות של Pointer ← זוגות טווח תאריכים ← תיבות סימון אחרונות. תיבת סימון בסוף המערך נוחתת בפינה השמאלית‑תחתונה, שזה המקום הטבעי שלה ב‑RTL.

CalculatedFields — עמודות מחושבות

Section titled “CalculatedFields — עמודות מחושבות”
JSON
"CalculatedFields": [
{ "name": "מחיר לפני הנחה", "fieldA": "PricePerUnit", "fieldB": "Quantity", "action": "Times" },
{ "name": "שיעור הנחה", "fieldA": "מחיר לפני הנחה", "fieldB": "Total", "action": "Divide (%)" }
]
action הפעולה
Plus fieldA + fieldB
Minus fieldA - fieldB
Times fieldA * fieldB
Divide fieldA / fieldB
Divide (%) (fieldA / fieldB) * 100

אפשר לשרשר: ה‑name של שדה מחושב קודם משמש כ‑fieldA או fieldB בשדה הבא — כמו בדוגמה.

JSON
"ScheduleSendAt": { "interval": "daily", "hour": 8, "occurrence": [] },
"ScheduleSendTo": "manager@company.com,team@company.com"
interval occurrence
daily []
weekly ימי השבוע, 0 = ראשון — למשל [0, 3]
monthly ימים בחודש — למשל [1, 15]

occurrence נחוץ ל‑weekly ול‑monthly — אבל הכלי לא אוכף אותו (שבועי בלי occurrence נשמר כמות שהוא). ספקו אותו תמיד.

JSON
"permissions": ["role:Admin", "role:Sales", "2b0QVKoigE"],
"editPermissions": "2b0QVKoigE"
  • permissions — מי רואה ומשתמש. תפקיד נכתב בקידומת role: ואחריה שם התפקיד המדויק (רגיש לרישיות ולרווחים: role:Report Admin). את שמות התפקידים מוציאים ב‑Get-Roles.
  • editPermissionsobjectId של משתמש אחד. חובה כשיוצרים עם Master Key, כי אז אין משתמש מחובר שיירש את הבעלות.

ה‑permissions נכתבים כמות שהם כמפתחות קריאה ב‑ACL של הרשומה, ו‑editPermissions מקבל קריאה+כתיבה. לכן משתמש נכתב כ‑objectId חשוף (כפי שהסכימה אומרת); הצורה "userId:<id>" יוצרת מפתח ACL חסר משמעות ואינה מעניקה דבר. ובכל מקרה: העדיפו תפקידים על משתמשים בודדים.

1. Get-Schema(class) מאמתים שמות שדות
2. Get-Optional-Fields(class) ← מכאן מעתיקים field / aggrField / type / text
3. Get-Roles → שמות התפקידים ל-permissions
Get-all-Users → objectId ל-editPermissions
4. שאילתת ישות? Get-Reports(pageId) → מעתיקים FormName משאילתה קיימת
5. Create-or-Update-Report
6. Get-Reports(objectId) קריאה חוזרת לאימות
7. דוח מתוזמן? יוצרים בלי תזמון, ומוסרים למשתמש את צעד ההוספה/השמירה מהממשק
  • אין מחיקת דוח. אין כלי. מחיקה נעשית בממשק או ב‑REST על _DynamicQueries עם Master Key.
  • דוח מורכב אינו נתמך בכלי. דוח שמאגד כמה דוחות (SubqueriesInfo) — הכלי מתעלם מהשדה ויוצר דוח רגיל. זהו פער ידוע בכלי; אל תעקפו אותו בכתיבה ישירה מסביבת סוכן.
  • פלט Get-Reports כבד — סננו לפי objectId או pageId.
  • Aggregate-Data הוא הדוד של המשפחה, לא בן שלה. הוא אגרגציה חד‑פעמית שלא נשמרת בשום מקום, והדקדוק שלו קרוב אבל לא זהה — הפרמטר groupby שלו הוא מחרוזת. ראו כלי נתונים.
  • GridDivider ברירת מחדל 4 — ואם לא תעברו עליו במודע תקבלו לפעמים פריסה שנראית שבורה.