מה חדש ב-Shipnest
כל שינוי במערכת מתועד כאן — מתיקוני באג קטנים ועד פיצ'רים חדשים. עודכן אוטומטית מ-changelog.json.
01.256.004•677 רשומות סה"כאוגוסט 2026
v01.256.004תיקוןאפליקציית שליחים / ליקוט / תשתיתעצירת מעקב מיקום במכשיר מנותק, מגבלת ליקוט רחבה יותר, והכנת תשתית לעומס גבוה
שני תיקונים מחקירת התראת התעבורה של Vercel, ובהמשך היום — מקבץ ייעולי תשתית לקראת צירוף לקוחות גדולים.
פרטים נוספים ↓הסתר ↑
שני תיקונים מחקירת התראת התעבורה של Vercel, ובהמשך היום — מקבץ ייעולי תשתית לקראת צירוף לקוחות גדולים. באפליקציית השליחים: מכשיר שה-session שלו פג המשיך לשדר מיקום כל 2 דקות לנצח (מאות בקשות כושלות ביום), כי מנגנון העצירה עבר דרך ה-stores שריקים כשהמשימה רצה ברקע ללא האפליקציה. מעכשיו משימת הרקע עוצרת את עצמה ישירות ברגע שה-session נדחה סופית, ומוחקת מיקומים שהצטברו בתור — פרטיות, סוללה, ופחות רעש. בדף הליקוט: מגבלת הקצב על קריאות התצוגה הועלתה מ-30 ל-120 לדקה (המגבלה משותפת לכל הטאבים מאחורי IP משרדי אחד).
- דף היום של השליח נטען מהר משמעותית: אינדקס חדש הוריד את שאילתת הביקורים מ-317ms ל-19ms (נמדד על השליח העמוס ביותר), והשליפה הפסיקה לגרור את כל נתוני ה-JSON הכבדים
- רשימת הנוכחות (מי מחובר) עברה לשאילתה משותפת אחת לכל הטאבים במקום שאילתה לכל חיבור כל 5 שניות — הפחתה מסיבית בעומס על מאגר החיבורים המשותף
- סנכרון משלוחי שותפים שולף מהמסד רק את השדות הנחוצים במקום 300 רשומות JSON מלאות כל 10 דקות
- כל קריאות ה-Lionwheel שנצפו בפרודקשן על המפתח הגלובלי הוסבו למפתח הפר-לקוח — הכרחי כשכמה לקוחות גדולים יחלקו את המערכת
v01.256.003תיקוןבוט קבוצות / תרחישיםכשל שליחה חולף לשליח מציף מיד פנייה לצוות
כשל שליחה חולף כבר לא נבלע בשקט: כששאלת צפי/תיאום ללקוח נכשלת בדרך לקבוצת השליח (תקלת ספק רגעית), הלקוח לא קיבל דבר ואיש לא ידע.
פרטים נוספים ↓הסתר ↑
כשל שליחה חולף כבר לא נבלע בשקט: כששאלת צפי/תיאום ללקוח נכשלת בדרך לקבוצת השליח (תקלת ספק רגעית), הלקוח לא קיבל דבר ואיש לא ידע. מעכשיו נכתבת מיד הודעה פנימית לצוות בתיבת הלקוח כדי שנציג יטפל. בנוסף, לבקשת הבעלים, ביטוי-שידור מותאם שמסתיים בסימן שאלה דורש מעכשיו שורה עצמאית מדויקת — 'שלכם?' לבדו יפעיל שידור, אבל 'זה גם לקוח שלכם' בתוך משפט לא (הביטוי עודכן בהגדרות בהתאם).
v01.256.002תיקוןבוט קבוצות / תרחישיםמקבץ תיקוני בוט: קול-עוזר שדלף ללקוחות, שיוכי תשובות שגויים, והודעות מטעות
עשרה דיווחי כשל, שבעה שורשים.
פרטים נוספים ↓הסתר ↑
עשרה דיווחי כשל, שבעה שורשים. מנסח-התשובות שענה בקול עוזר-AI ('אני מוכן לעזור! אנא שתף...') במקום תוכן — הטקסט הזה הגיע ללקוחות כתשובת השליח; מעכשיו קול-עוזר מזוהה (תבניות + מבנה) ומסווג כתקלת מודל, וללקוח מגיעות רק מילות השליח. תשובת צפי נקייה ('היום') עוברת ישירות בלי מודל בכלל, ו'רגע/שניה' לא סוגרות בירור — התשובה האמיתית שאחריהן נקלטת. תשובה קצרה של לקוח לשאלת נציג סמוכה ('בראשון בע"ה יהיה' על 'יש איסוף היום?') לא נתפרת יותר לבירור ישן. הודעת 'כתובת לא מעודכנת' לא טוענת עוד 'המשלוח נמסר' לפני שנמסר בפועל. ותרחיש השידור הפסיק להרעיש: הודעות-הסבר ארוכות ומספרים שהגיעו רק מציטוט אנושי ישן לא מקבלים עוד תשובות שגיאה — בלי לגעת בליבת השידור שעובדת היטב.
v01.256.001שיפוראפליקציית שליחיםדיאלוג גילוי-נאות לשיתוף מיקום לפני תחילת משמרת
בהתאם לדרישת ה-prominent disclosure של Google Play להרשאת מיקום ברקע: לפני בקשת הרשאות המיקום בתחילת משמרת, אפליקציית השליחים מציגה כעת הסבר חד-פעמי — אילו נתוני מיקום נאספים, לאיזו מטרה, ושהאיסוף נמשך גם כשהאפליקציה סגו…
פרטים נוספים ↓הסתר ↑
בהתאם לדרישת ה-prominent disclosure של Google Play להרשאת מיקום ברקע: לפני בקשת הרשאות המיקום בתחילת משמרת, אפליקציית השליחים מציגה כעת הסבר חד-פעמי — אילו נתוני מיקום נאספים, לאיזו מטרה, ושהאיסוף נמשך גם כשהאפליקציה סגורה, עם אישור מפורש. דחיית ההסבר מבטלת את תחילת המשמרת בצורה נקייה. האישור נשמר ואינו מוצג שוב. נדרש לקראת קידום הגרסה ל-production track בחנות; הופץ כעדכון OTA להתקנות 1.3.0.
v01.256.000חדשבוט וואטסאפ / לקוחותminorניתוק לקוח מהבוט — הערה פנימית לצוות במקום כל הודעה אוטומטית
מתג חדש בהגדרות הלקוח (לקוחות ← לקוח ← הגדרות ← 'ניתוק מהבוט') ללקוחות שלא רוצים לתקשר עם הבוט.
פרטים נוספים ↓הסתר ↑
מתג חדש בהגדרות הלקוח (לקוחות ← לקוח ← הגדרות ← 'ניתוק מהבוט') ללקוחות שלא רוצים לתקשר עם הבוט. כשהמתג דולק, הבוט לא שולח ללקוח שום הודעה — לא בקבוצת הוואטסאפ המקושרת ולא בצ'אט האישי — ולא מבצע עבורו פעולות אוטונומיות. פנייה של הלקוח שהבוט מזהה (שאלת צפי, ערעור על מסירה וכו') נרשמת כהערה פנימית בשיחת ה-inbox של הלקוח עם סימון לא-נקרא, כך שנציג מטפל ידנית. דיווח שליח על משלוח של הלקוח (אין מענה, כתובת שגויה, כשל מסירה, נזק) — שהיה מגיע ללקוח כהודעת בוט — הופך גם הוא להערת צוות שמציינת במפורש שהלקוח מנותק מהבוט. האכיפה בנויה בשלוש שכבות: פתרון יעד הצ'אט מחזיר 'אין יעד' ללקוח מנותק (וכל המסלולים הקיימים כבר יודעים ליפול משם להערת צוות), מנוע התרחישים עוצר לפני כל פעולה וכותב את ההערה, ושער אחרון בשכבת השליחה חוסם כל הודעת בוט לצ'אט של לקוח מנותק — גם ממסלול עתידי שישכח לבדוק. שליחה ידנית של נציג מה-inbox איננה מושפעת, וכך גם הודעות סטטוס מתוזמנות ותיאום איסופים יומי (שנשלטים בהגדרות נפרדות).
- מתג 'ניתוק מהבוט' בהגדרות הלקוח — הבוט מפסיק לחלוטין להתכתב עם הלקוח
- כל פנייה או אירוע שהבוט מזהה נרשמים כהערה פנימית לצוות עם סימון לא-נקרא, לטיפול ידני
- אכיפה בשלוש שכבות כולל שער אחרון בשכבת השליחה — גם מסלול עתידי לא יוכל לשלוח ללקוח מנותק
- שליחות ידניות של נציגים, הודעות מתוזמנות ותיאום איסופים יומי אינם מושפעים
v01.255.003תיקוןיבוא משלוחים מאקסליבוא חוזר מההיסטוריה: תאריך איסוף מיושן שגרם לחיוב בחודש הלא נכון
כשמייבאים קובץ מחדש מתוך היסטוריית היבוא, המערכת שחזרה את תאריך האיסוף המקורי — מהפעם הראשונה שהקובץ הועלה.
פרטים נוספים ↓הסתר ↑
כשמייבאים קובץ מחדש מתוך היסטוריית היבוא, המערכת שחזרה את תאריך האיסוף המקורי — מהפעם הראשונה שהקובץ הועלה. אם המשתמש לא שינה אותו ידנית, תאריך ישן (לעיתים מחודש קודם) נשלח לליונוויל. ליונוויל מחייבים לפי תאריך האיסוף המתוכנן, ולכן המשלוחים נכנסו לחיוב של החודש הלא נכון. כעת יבוא חוזר מתייחס לעצמו כעבודה חדשה שקורית עכשיו: תאריך איסוף שכבר עבר נדחף אוטומטית להיום, ותאריך עתידי לגיטימי (הזמנה מוקדמת) נשמר. כשהתאריך נדחף, מוצגת אזהרה ברורה שמבקשת מהמשתמש לוודא את התאריך לפני יצירת המשלוחים. התיקון חל גם על פורטל הלקוחות (אותו רכיב יבוא משותף).
v01.255.002תיקוןהודעות מתוזמנותהודעות מתוזמנות: מספר טלפון שגוי כבר לא מבזבז 3 ניסיונות ולא מתריע למנהל
הודעה מתוזמנת עם מספר טלפון בפורמט שגוי נכשלת באותו אופן בדיוק בכל ניסיון — המספר לא משתנה בין ניסיונות.
פרטים נוספים ↓הסתר ↑
הודעה מתוזמנת עם מספר טלפון בפורמט שגוי נכשלת באותו אופן בדיוק בכל ניסיון — המספר לא משתנה בין ניסיונות. עד כה המערכת ניסתה אותה שלוש פעמים (שלושה מחזורי cron) ורשמה כל כישלון כשגיאה חמורה ששולחת התראת וואטסאפ למנהל, על תקלה שאיש לא יכול לתקן (הלקוח פשוט הקליד מספר שגוי). כעת כשל כזה מסומן כסופי כבר בניסיון הראשון — לא נוסה שוב — ונרשם כאזהרה בלבד, בלי התראה. אותה התנהגות חלה על תבנית Meta שבורה (שגיאה 132018), שגם היא כישלון קבוע פר-הודעה. כשלים חולפים (timeout, עומס אצל הספק, שגיאת שרת) ממשיכים לנסות שוב עד לתקרה ולהתריע — כי מטח שלהם בבת אחת הוא בדיוק האופן שבו נפילת ספק אמיתית מתגלה. (הלולאה האינסופית עצמה כבר נעצרה קודם בזכות מנגנון ה-claim האטומי; זה מסיר את הרעש שנותר.) בנוסף נסגר פער כפילות ותיק: הודעות 'משלוח ניזוק' ו'כשל מסירה' ללקוח נשלחו מחדש בכל פעם שהשליח הזכיר שוב את המשלוח (אותה הודעה שלוש פעמים בשלושה ימים) — נוסף חסם פר-משלוח: נזק פעם אחת בשבוע, כשל מסירה פעם ב-48 שעות, והחסם נרשם רק אחרי שליחה שהצליחה כדי לא להשתיק שליחה ראשונה לגיטימית.
- טלפון לא-תקין / תבנית שבורה = כישלון קבוע → מסומן סופי בניסיון הראשון, אזהרה במקום שגיאה, ללא התראת מנהל
- כשלים חולפים ממשיכים לנסות ולהתריע — כדי שנפילת ספק אמיתית עדיין תזוהה
v01.255.001תיקוןעוזר AI פנימיעוזר AI — טבלת פרטים מומצאת שחמקה משומר האמינות, וזמן מסירה של לקוח שהוחזר גלובלי
מניתוח שיחות אמת (26/07-03/08).
פרטים נוספים ↓הסתר ↑
מניתוח שיחות אמת (26/07-03/08). (1) שומר האמינות (שמונע דיווח על פעולה או הצגת נתונים בלי קריאת כלי) פספס מקרה: העוזר פתח 'משכתי את פרטי המשלוח [ברקוד]:' והציג טבלת פרטים שלמה ומומצאת (נמען, כתובת, לקוח שולח — כולם בדויים) בלי לקרוא לאף כלי. שני חורים תוקנו — הפועל 'משכתי' לא היה מזוהה, וקישור ברקוד בין 'המשלוח' לנקודתיים שיבש את הזיהוי. בנוסף נוסף זיהוי ישיר של **טבלת פרטי-משלוח** (שלוש שורות שדה או יותר) שהוצגה בלי קריאת כלי — היא נדחית אוטומטית, כי טבלה כזו יכולה להגיע רק מקריאה למערכת. הזיהוי צר בכוונה כדי לא לפגוע בהצעה לגיטימית ('רוצה שאביא את הפרטים?') או בטבלה שאינה משלוח. (2) 'מה ממוצע זמן המסירה של לקוח X' נענה עם סטטיסטיקה **גלובלית של כל הלקוחות** (getDeliveryTimeStats לא ידע לסנן לפי לקוח) — נצפה 0.1-0.7 ימים כשהממוצע האמיתי של אותו לקוח הוא 2.27. נוסף סינון לפי לקוח (customerName/customerId) ולפי שליח (driverName), והכלי מחזיר כעת גם overall — הממוצע/חציון הכולל לישות שנשאלה — לצד הפירוט לפי עיר. אומת מול נתוני הפרודקשן; כל 1,959 הטסטים עוברים. תרחיש תיאום-המסירה כבר לא מנחש משלוחים: המסווג היה רשאי להצמיד כל מספר שהופיע בחלון שיחה של 6 שעות — גם משורת צוות ישנה על משלוח אחר — ושיחת תיאום איסוף שניהלו נציגים סווגה כבקשת לקוח ונשלחה לשליח עם כל ה-burst הגולמי, כולל תגי צוות ותיוגים. מעכשיו התרחיש פועל רק כשהלקוח עצמו נקב במספר (או ציטט הודעת בוט שלנו), ההודעה לשליח מכילה רק את מילות הלקוח אחרי ניקוי שורות צוות, ואם לא נותר טקסט ממשי — הבוט לא יורה. (3) הובהרה לעוזר מטריצת יכולות-השליחה, בעקבות שיחה שבה סתר את עצמו — פעם 'שלחתי' ופעם 'אני לא יכול לשלוח'. האמת: הוא שולח טקסט חופשי לשליח (בקבוצה בלבד) וללקוח העסקי, ולנמען הקצה רק תבנית אישור קבועה — ואין כלי לטקסט חופשי ישיר לנמען. ההנחיות אוסרות עליו מעכשיו גם להכחיש יכולת בצורה גורפת וגם להמציא 'נשלח' על יעד שאינו נתמך; הסתייגות חייבת להיות ממוקדת ליעד ולסוג.
- טבלת פרטי-משלוח מומצאת בלי קריאת כלי נדחית אוטומטית (השומר הורחב, בזהירות מפני התרעות שווא)
- 'ממוצע זמן מסירה של לקוח X' מסונן כעת לפי לקוח — קודם הוחזר נתון גלובלי שגוי (0.1 מול 2.27 ימים)
- getDeliveryTimeStats תומך בסינון לפי לקוח/שליח ומחזיר overall כולל לצד פירוט הערים
- מטריצת יכולות-שליחה ברורה לעוזר: שולח לשליח (קבוצה) וללקוח העסקי, לנמען רק תבנית — בלי הכחשה גורפת ובלי 'נשלח' מומצא
v01.255.000תיקוןסנכרון / Lionwheelminorמשלוחים שנמחקו ב-Lionwheel נמחקים אצלנו אוטומטית — ותור הסנכרון הפסיק להיחנק על משלוחים 'מתים'
Lionwheel לא מודיעה לנו כשמשלוח נמחק אצלה, ולכן משלוח כזה נשאר אצלנו 'פתוח' לנצח ומחזיר 404 בכל סנכרון.
פרטים נוספים ↓הסתר ↑
Lionwheel לא מודיעה לנו כשמשלוח נמחק אצלה, ולכן משלוח כזה נשאר אצלנו 'פתוח' לנצח ומחזיר 404 בכל סנכרון. שתי תקלות שהתגלו בחקירה: (1) תור הסנכרון (רשת הביטחון שממשיכה למשוך משלוחים פתוחים) מוין לפי 'סנכרון מוצלח אחרון', אבל כשל 404/429 לא עדכן את החותמת הזו — כך שאותם משלוחים מתים נשארו בראש התור ונמשכו שוב בכל ריצה, בעוד אלפי משלוחים חיים שמאחוריהם לא נבדקו אף פעם (נמדד: 84 משלוחים מתים נמשכו ~50 פעם כל אחד בשבוע, בזמן ש-4,662 משלוחים חיים לא סונכרנו ולו פעם אחת). (2) מנגנון המחיקה האוטומטית שאמור לזהות משלוח תקוע כבר היה קיים, אבל סף הזיהוי היה 'לפחות 2 כשלים והכשל הראשון לפני 3+ ימים'. הוחלף בכלל שמבקש המשתמש: 404 ב-3 ימים קלנדריים שונים (שעון ישראל) לפני מחיקה — ניסיון יום אחרי יום, ובאישור השלישי המשלוח נמחק. נוספה עמודה חדשה (last_sync_attempt_at) שנחתמת בכל ניסיון סנכרון ומשמשת כ-cursor של התור, כך שמשלוח שנבדק — חי או מת — יורד לסוף התור והרשימה מתנקזת בסבב מלא.
- עמודה חדשה last_sync_attempt_at: נחתמת בכל ניסיון (כולל 404/429), ושני ה-crons ממיינים לפיה — משלוח מת כבר לא חוסם את התור
- מחיקה אוטומטית לפי כלל ברור: 404 ב-3 ימים שונים ⇒ מחיקה. שמרני יותר מהסף הקודם (58 מועמדים במקום 394) ותואם ל'ניסיון יום אחרי יום'
- תיקון רעב-התור: לפני התיקון רק ~6-211 משלוחים סונכרנו ביום מתוך תור של 5,048 פתוחים; כעת התור מתנקז בסבב במקום לחזור על אותם ראשי-תור
- התלות במשתנה הסביבה AUTO_RESOLVE_DRY_RUN נותרה — כל עוד הוא דלוק בפרודקשן, הקרון רק מדפיס 'היה מוחק' ולא מוחק בפועל
v01.254.003תיקוןאנליטיקה / נהגיםאנליטיקת נהגים: ביקורים סוף/תחילת יום שובצו ליום ולשעה שגויים
עמודת מועד הביקור (visitAt) נשמרת ב-UTC ללא אזור זמן, אבל הדוחות המירו אותה לשעון ישראל בכיוון ההפוך — כל דלי נחת שש שעות מוקדם מדי וחצה גבולות של יום ושעה.
פרטים נוספים ↓הסתר ↑
עמודת מועד הביקור (visitAt) נשמרת ב-UTC ללא אזור זמן, אבל הדוחות המירו אותה לשעון ישראל בכיוון ההפוך — כל דלי נחת שש שעות מוקדם מדי וחצה גבולות של יום ושעה. בפועל: ביקור ב-00:00 בישראל דווח כ-18:00 של היום הקודם, ו-8,459 מתוך 73,192 הביקורים ב-45 הימים האחרונים (כ-12%) שובצו ליום הלא-נכון. תוקן בדוח הנהגים הכולל (הסדרה היומית ומפת החום יום/שעה), בדוח הפרטני לנהג, ובסנכרון הלילי של תמונות עלות המשלוח. במקביל התגלה שגם קיבוץ נקודות ה-GPS לפי יום נעשה לפי יום-UTC בעוד ספירות הביקורים לפי יום-ישראל — כך שהמרחק והשעות של יום מסוים לא התיישרו עם מספר המשלוחים שלו בגבולות היום; שני הצירים אוחדו כעת ליום ישראל, וציר הזמן של הגרף מונה ימי ישראל.
- המרת אזור-זמן בשאילתות הגולמיות תוקנה: עמודת timestamp-without-tz דורשת הכרזת UTC לפני ההמרה לישראל — אחרת ההסטה 6 שעות
- ספירת המשלוחים, המרחק, השעות והימים הפעילים מקובצים כולם לפי יום ישראל ומיושרים זה לזה
- הסנכרון הלילי של עלויות (cost-snapshot-reconcile) חישב יום שגוי — כעת תואם למנוע החי, כך שביקורי גבול-יום מתקבעים במקום להיחשב 'תקועים' כל לילה
v01.254.002תיקוןאינטגרציות / אישופ / קונימבומצב 'שידור יזום' לחנויות אישופ/קונימבו נשמר עכשיו באמת, עם מתג מצב ישירות בכרטיס החנות
הגדרות מצב השידור-היזום (כיבוי המשיכה האוטומטית, וסטטוסי ההצלחה/כישלון שמתעדכנים בחזרה בחנות) נזרקו בשקט בכל שמירה — שדות אלה לא היו ברשימת השדות המותרים של ה-API, כך שהמתג 'כבה משיכה אוטומטית' נראה עובד בטופס אבל הערך מ…
פרטים נוספים ↓הסתר ↑
הגדרות מצב השידור-היזום (כיבוי המשיכה האוטומטית, וסטטוסי ההצלחה/כישלון שמתעדכנים בחזרה בחנות) נזרקו בשקט בכל שמירה — שדות אלה לא היו ברשימת השדות המותרים של ה-API, כך שהמתג 'כבה משיכה אוטומטית' נראה עובד בטופס אבל הערך מעולם לא נכתב למסד הנתונים, והחנות המשיכה להימשך אוטומטית במקביל לכפתור. השדות נוספו לרשימה המותרת (יצירה ועדכון כאחד) כך שהמצב נשמר. בנוסף נוסף מתג מצב ברור ישירות בכרטיס החנות בפורטל, ליד כתובת ה-Webhook של הכפתור: מעבר בין 'משיכה אוטומטית לפי סטטוס' ל'רק שידור יזום (כפתור)' בלחיצה אחת, בלי צורך להיכנס להגדרות מתקדמות ולטעון סטטוסים.
- באג: disablePolling וסטטוסי ה-write-back של אישופ/קונימבו הושמטו ב-Zod ולא נשמרו — תוקן בשתי הסכמות (POST+PUT)
- מתג מצב חדש בכרטיס החנות: 'רק שידור יזום (כפתור)' מול 'משיכה אוטומטית', עם שמירה מיידית ומיזוג על ההגדרות הקיימות
v01.254.001שיפוראפליקציית שליחיםדיווח קריסות (Sentry) הופעל באפליקציית השליחים
עד היום ה-SDK של Sentry היה מחווט באפליקציית השליחים אבל כבוי — שדה ה-DSN היה ריק, כך שקריסות אצל שליחים בשטח נעלמו בלי זכר.
פרטים נוספים ↓הסתר ↑
עד היום ה-SDK של Sentry היה מחווט באפליקציית השליחים אבל כבוי — שדה ה-DSN היה ריק, כך שקריסות אצל שליחים בשטח נעלמו בלי זכר. נוצר חשבון Sentry (אחסון EU), וה-DSN הוזן לפרופילי ה-build של preview ו-production. תיקוני ההקשחה מאתמול פורסמו יחד עם ההפעלה כעדכון OTA להתקנות הקיימות.
v01.254.000שיפוראפליקציית שליחיםminorהקשחת אפליקציית השליחים לקראת גרסה חדשה — אמינות ראיות, פוש, ומנגנון עדכון-חובה
סבב הקשחה רוחבי באפליקציית השליחים ובצד השרת שלה לקראת השקת גרסה.
פרטים נוספים ↓הסתר ↑
סבב הקשחה רוחבי באפליקציית השליחים ובצד השרת שלה לקראת השקת גרסה. נסגרו פערי אובדן-ראיות (כפתור חזרה פיזי שמחק תמונות POD בלי אישור, אזהרת 'אין הוכחת מסירה' שהתעלמה מהוכחות בתור הסנכרון, תמונות סגירת גוביינא שלא נשמרו לאחסון יציב), נוספה ולידציה לשדות צ'ק בגוביינא, רישום טוקן פוש קיבל retry עם backoff וה-endpoint שלו כבר לא קורס כשהמכשיר לא רשום, נוסף מנגנון עדכון-חובה (426) מקצה לקצה עם מסך חוסם, מצב משמרת מדווח כעת לשרת במפורש כך שדשבורד האדמין לא תלוי רק ב-GPS, נוספו מגבלות קצב לכל נקודות ההעלאה, ומסכי הסגירות יושרו למערכת העיצוב ולנגישות.
- כפתור חזרה פיזי באנדרואיד עובר דרך אישור-זריקה וניקוי קבצים בכל מסכי ההוכחות (POD/חתימה/גוביינא/כשל)
- מנגנון עדכון-חובה: השרת אוכף MOBILE_MIN_APP_VERSION ומחזיר 426, האפליקציה מציגה מסך עדכון חוסם — והתור האופליין שומר על הוכחות עד לעדכון
- רישום טוקן פוש עמיד: retry עם backoff בצד האפליקציה + טיפול במכשיר לא-רשום בצד השרת
- מצב משמרת מפורש (start/stop) נשמר בשרת — 'בשטח' בדשבורד האדמין כבר לא תלוי רק בדגימות GPS
- ולידציית שדות צ'ק בגוביינא (תאריך אמיתי, ספרות בלבד) ורשימת רווחים עם עימוד במקום רינדור מאות שורות
- מגבלות קצב פר-משתמש על כל נקודות ההעלאה (POD/חתימה/גוביינא/סגירות/מיקום)
v01.253.002תיקוןאינטגרציות / אישופהזמנת חנות שנתקעה בגלל תקלה רגעית מול ליונוויל משוגרת מעכשיו מחדש אוטומטית
כשהשיגור לליונוויל נכשל ברגע ייבוא הזמנה מחנות אישופ (למשל מכסת קצב 429), ההזמנה נשמרה כמשלוח ממתין כדי שלא תאבד — אבל שום מנגנון לא ניסה לשגר אותה שוב, ומנגנון מניעת הכפילויות דילג עליה לנצח, כך שתקלה רגעית תקעה הזמנה ע…
פרטים נוספים ↓הסתר ↑
כשהשיגור לליונוויל נכשל ברגע ייבוא הזמנה מחנות אישופ (למשל מכסת קצב 429), ההזמנה נשמרה כמשלוח ממתין כדי שלא תאבד — אבל שום מנגנון לא ניסה לשגר אותה שוב, ומנגנון מניעת הכפילויות דילג עליה לנצח, כך שתקלה רגעית תקעה הזמנה עד התערבות ידנית. מעכשיו סנכרון החנויות מזהה משלוחים ממתינים כאלה ומשגר אותם מחדש אוטומטית עם המתנה מדורגת בין ניסיונות (5 דקות עד 6 שעות), גם בחנויות שעובדות במצב push. כישלון קבוע — כתובת שגויה או מיצוי הניסיונות — מסומן על המשלוח עם סיבת הכשל כדי שהצוות יראה אותו במקום לולאה שקטה. בנוסף: זמן ההמתנה לשליחת WhatsApp הועלה מ-15 ל-30 שניות בשני הספקים (Meta ו-Green API), ו-timeout בודד כבר לא שולח התראת מערכת למנהל — התראה נשלחת רק כשמצטברים 3 ומעלה תוך 30 דקות באותו ספק, סימן לתקלה אמיתית ולא לרעש רגעי.
v01.253.001תיקוןבוט / הודעות ללקוחותשלילת-צורך לא נקראת עוד כבקשת דחייה, ותלונות על עיכוב שלנו לא מגיעות לשולח
שני תיקונים מדיווחי כשל.
פרטים נוספים ↓הסתר ↑
שני תיקונים מדיווחי כשל. נמען שכתב 'תודה, לא צריך אחרי שבת' (=צריך לפני שבת) קיבל מהבוט קביעה הפוכה — עיכוב אספקה והערת 'לא לספק לפני' לשליח. מעכשיו שומר דטרמיניסטי מזהה שלילת-צורך וחוסם כל כתיבת דחייה או הערת-שליח מאותה שיחה עד הכרעת נציג — כולל ניסיון חוזר של המודל בהודעה הבאה (נעילה עמידה של 48 שעות). בנוסף, הודעת בקשת-ביטול לשולח ציטטה את נימוק הנמען כלשונו — כולל 'עיכוב משמעותי וחריגה מה-SLA' — וחשפה תלונה על השירות שלנו; מסנן הניסוח מסיר כעת פסוקיות-אשמה על עיכוב/תקלה שלנו מכל הודעה לשולח, תוך שמירת סיבות לגיטימיות ('הזמינה בטעות', 'לא הגיע לנקודת האיסוף').
v01.253.001שיפוראינטגרציות / תחזוקההסרת שני נתיבי אבחון זמניים של חיבורי חנויות
אחרי שאינטגרציות אישופ וקונימבו אומתו ועובדות בפרודקשן, הוסרו שני נתיבי האבחון הפנימיים הזמניים (platform-only, קריאה-בלבד) ששימשו לשליפת מבנה ההזמנה הגולמי מהספקים בזמן הפיתוח — /api/admin/eshop-probe ו-/api/admin/konim…
פרטים נוספים ↓הסתר ↑
אחרי שאינטגרציות אישופ וקונימבו אומתו ועובדות בפרודקשן, הוסרו שני נתיבי האבחון הפנימיים הזמניים (platform-only, קריאה-בלבד) ששימשו לשליפת מבנה ההזמנה הגולמי מהספקים בזמן הפיתוח — /api/admin/eshop-probe ו-/api/admin/konimbo-probe. ניקוי scaffolding; אין השפעה על לקוחות.
יולי 2026
v01.253.000חדשבוט קבוצות / תרחישיםminorשאלת צפי חכמה: איסוף נשאל אצל השליח המשובץ, וכשל מסירה מוסבר ללקוח
שלוש יכולות חדשות בשאלות צפי מקבוצות לקוחות.
פרטים נוספים ↓הסתר ↑
שלוש יכולות חדשות בשאלות צפי מקבוצות לקוחות. משימת איסוף משובצת — הבוט שואל את שליח האיסוף בקבוצתו בניסוח איסוף; ללא שיבוץ — פתק לצוות (נדרשת התערבות אנושית). שאלת צפי על משלוח שנכשל בו ניסיון מסירה — הלקוח מקבל שורת סטטוס בטוחה (ללא שמות שליחים, לעולם) והסבר כשל בניסוח בטוח שממופה מקטגוריות ולא מהטקסט הגולמי, כולל 'מתוכנן ניסיון נוסף' רק כשבאמת מתוכנן. וכשהכשל הוא כתובת או טלפון שגויים שטרם עודכנו — הבוט לא שולח שליח לניסיון אבוד אלא מבקש מהלקוח את הפרט המעודכן: טלפון נקלט ונכתב אוטומטית, כתובת מועברת לצוות לעדכון. תרחיש הבקשה (address_fix_request) הוא opt-in פר-חברה.
- צפי איסוף נשאל אצל שליח האיסוף המשובץ — כמו צפי מסירה
- כשל מסירה מוסבר ללקוח בניסוח בטוח, בלי שמות שליחים ובלי טקסט גולמי
- כתובת/טלפון שגויים שטרם תוקנו — הלקוח מתבקש לשלוח את הפרט כתנאי לניסיון נוסף
- חבילה בניסיון שלישי או חוזרת לשולח — לעולם לא מובטח ניסיון נוסף
v01.252.000שיפורבירורים ידניים / הרשאותminorתזכורות אוטומטיות לשליחים — רק בהפעלה מפורשת, וזמינות לבעלים בלבד
עד היום כל בירור ידני מדף המשלוח (בירור צפי, שאלה לשליח, בקשת תמונת מסירה) הפעיל תזכורות אוטומטיות לקבוצת השליח באופן קבוע — בלי שום מתג.
פרטים נוספים ↓הסתר ↑
עד היום כל בירור ידני מדף המשלוח (בירור צפי, שאלה לשליח, בקשת תמונת מסירה) הפעיל תזכורות אוטומטיות לקבוצת השליח באופן קבוע — בלי שום מתג. כשנפתחו חמישה בירורים באותה קבוצה, כל מחזור הפיל חמש שורות 'תזכורת' זהות בתוך שניות, פעמיים-שלוש ביום, ואיש לא הבין מאיפה זה מגיע. מעכשיו תזכורות הן בחירה מפורשת לכל פנייה — כפתור פעמון ליד שליחת הבירור — והאפשרות שמורה למשתמש בדרגת בעלים בלבד. ברירת המחדל תמיד כבויה. גם מתגי הנדנוד בהגדרות הבוט (נדנוד שאלות צוות ונדנוד פר-תרחיש) נעולים כעת לדרגת בעלים, ושמירת הגדרות על ידי משתמש אחר משמרת את ערכי הבעלים ללא שינוי. השרת אוכף את ההגבלה בכל המסלולים, כולל בירור צפי מרובה מרשימת המשלוחים. באותו יום תוקנו גם שני כשלי שיוך-תשובות בקבוצות: תשובה שכולה תיוג (@) של אדם אינה נחשבת עוד תשובה לשום שאלה — עד היום תיוג של עמיתה הועבר לשליח כ'עדכון מהשולח' וסגר את הבירור, כך שהטלפון האמיתי שנשלח שתי דקות אחריו נזרק; ותשובה שנכתבת דקות ספורות אחרי ששאלו את הכותב שאלה אנושית בקבוצה — במיוחד כשהשאלה ציטטה הודעה שלו — משויכת לשיחה ההיא ולא לבירור ישן של הבוט, אחרי ששעות הקבלה של מחסן לאיסוף הוצגו ללקוח אחר כחלון המסירה של המשלוח שלו. בהמשך היום בוצעה ביקורת רגרסיה מלאה על כל 86 דוחות הכשלים ההיסטוריים: אפס רגרסיות — כל תיקון עבר אומת שהוא עדיין קיים, מכוסה בטסט ושהמסלול אליו שלם. שלוש נקודות חשיפה שנמצאו טופלו מיד: שומר 'השיחה הסמוכה' צומצם לבירורים מול שליחים בלבד (כדי שלא ישתיק אישור-טלפון מילולי של לקוח), מחרוזת הקישור בין דיווח-ללא-ברקוד לתווית שאחריו חולצה לקבוע משותף (שינוי ניסוח לא ישבור עוד את ההתאוששות בשקט), ותיעוד פנימי מיושן עודכן.
- כפתור פעמון חדש ליד כל בירור לשליח — מפעיל תזכורות לפנייה זו בלבד, מוצג לבעלים בלבד
- פניות קיימות שנפתחו לפני השינוי מפסיקות להזכיר מיד
- מתגי הנדנוד בהגדרות הבוט נעולים לדרגת בעלים; שמירה של נציג אינה דורסת אותם
- בירור שקט (ללא תזכורות) ממתין לתשובה 24 שעות במקום לנעול את המשלוח ל-4 ימים
v01.251.002תיקוןבוט קבוצות / תרחישיםתשובה תפעולית של שליח לא מועברת עוד ללקוח כמו-שהיא — היא עולה לצוות
לקוח ששאל על צפי מסירה קיבל בחזרה, מילה במילה, את תגובת הקבלן שכוונה בכלל לצוות — שאלה-נגדית תפעולית על החזרת המשלוח.
פרטים נוספים ↓הסתר ↑
לקוח ששאל על צפי מסירה קיבל בחזרה, מילה במילה, את תגובת הקבלן שכוונה בכלל לצוות — שאלה-נגדית תפעולית על החזרת המשלוח. מנגנון ניסוח-הבטוח ללקוח דווקא שפט נכון שאין בתשובה שום תוכן להעברה, אבל מנגנון הגיבוי — שנועד להגן מתקלת AI רגעית — דרס את השיפוט ושלח את הטקסט הגולמי. מעכשיו שני המצבים מופרדים: שיפוט 'אין מה להעביר' מציף הודעה פנימית לצוות בתיבת הלקוח (עם ציטוט תשובת השליח) ולא שולח ללקוח דבר, בעוד תקלת AI אמיתית ממשיכה ליהנות מהגיבוי. ההודעה שנשפטה כלא-מתאימה גם נעצרת מהמשך עיבוד, כך שתרחיש אחר לא יפעל עליה בטעות. אותו תיקון הוחל גם על תרחיש תיאום-מועד המקביל.
v01.251.001חדשפורטל לקוחות / משלוחיםפורטל הלקוחות: אייקון הוכחת מסירה בטבלת המשלוחים — עם תצוגת התמונות בריחוף
בטבלת המשלוחים בפורטל הלקוחות, לצד אייקון "מדבקה הודפסה" הקיים, מופיע מעתה אייקון מגן בכל שורה של משלוח שיש לו הוכחת מסירה.
פרטים נוספים ↓הסתר ↑
בטבלת המשלוחים בפורטל הלקוחות, לצד אייקון "מדבקה הודפסה" הקיים, מופיע מעתה אייקון מגן בכל שורה של משלוח שיש לו הוכחת מסירה. ריחוף על האייקון פותח את תמונות ההוכחה עצמן ישירות מהטבלה — בלי להיכנס לדף המשלוח — ולחיצה על תמונה פותחת אותה בגודל מלא בלשונית חדשה. בנוסף: שליחת WhatsApp דרך Meta שנכשלת בשגיאה חולפת של Meta (קוד 131000) מנוסה כעת שוב אוטומטית — במקום להיכשל מיידית ולהציף התראת מערכת על כל שיבוש רגעי בצד Meta. ובהמשך היום — המשתנה {details} (בלוק פרטי המשלוח המלא: מספר, שם נמען, רחוב, דירה/קומה, כניסה וקוד, עיר, טלפון והערת מסירה) זמין מעתה בכל תבניות תרחישי הבוט — בכל התרחישים ובכל סוגי ההודעות שנוגעות למשלוח מזוהה (הודעות פתיחה, העברות תשובה, אישורי קבלה, הודעות ביטול/תלונה/עיכוב לשולח, אישורי שידור ועוד) — ולא רק בהודעות הפתיחה כפי שהיה. התבניות שמעדכנות טלפון או כתובת מציגות ב-{details} את הערך המעודכן שנכתב זה עתה, ותבנית שמכילה {details} כשאין בלוק זמין נשלחת נקייה — בלי להשאיר את הטוקן בהודעה.
v01.251.000שיפורמשלוחים / דף משלוחminorכרטיסיית התפעול עוצבה מחדש סביב "אירועים תפעוליים" — מציגה רק מה שקרה במשלוח
כרטיסיית התפעול בדף המשלוח גדלה לשמונה ומעלה שורות שרובן ריקות ("לא בוצע", "לא הוגדר") — רעש שמסיח מהמידע האמיתי.
פרטים נוספים ↓הסתר ↑
כרטיסיית התפעול בדף המשלוח גדלה לשמונה ומעלה שורות שרובן ריקות ("לא בוצע", "לא הוגדר") — רעש שמסיח מהמידע האמיתי. העיצוב החדש מיישם עיקרון פשוט: הכרטיסייה מציגה מצב, לא יכולות. שורה מופיעה רק לאירוע תפעולי שקרה בפועל — ליקוט פעיל, יעד שבת/אקספרס שהוגדר, תווית, בירור שנשלח, פנייה קיימת — עם כל הפקדים והשינויים שהאירוע עבר, לצמיתות. כל ההפעלות עברו לכפתור אחד: "הוספת אירוע" פותח תפריט מקובץ (תפעול / בירורים) של כל עשרת סוגי האירועים; בחירת אירוע שדורש הגדרה — פרשה, תאריך אקספרס, טקסט שאלה, תווית — עוברת לתת-מסך בתוך אותו תפריט, והאירוע מופיע בכרטיסייה מרגע הפעלתו. אירוע שאינו זמין מוצג מעומעם עם הסיבה כטקסט משנה ("לא משויך שליח", "המשלוח טרם נמסר"), ואירועי השליח מציגים את שם השליח. ליד כל סוג אירוע — גם בתפריט וגם בשורות — נוסף אייקון מידע שבריחוף מסביר את מהות האירוע ואופן השימוש בו. משלוח ללא אירועים מציג שורה שקטה אחת במקום ערימת שורות ריקות. הוחל על שתי הפריסות — דף המשלוח המלא וה-Drawer. ובהמשך היום חודד עיקרון בטיחות: שליחת בירור היא פעולת אל-חזור, ולכן בחירת בירור בתפריט אינה שולחת דבר — היא רק מוסיפה את השורה לכרטיסייה במצב "טרם נשלח", והשליחה בפועל נעשית במודע מכפתור השורה; טיוטה שנוספה בטעות ניתנת להסרה ב-X לפני שנשלח דבר. ובהמשך היום — עוזר ה-AI הפנימי למד לפתוח אירועים תפעוליים בשפה חופשית: "תברר צפי מול השליח על 26350496", "תשאל את הנמען אם קיבל", "תבקש תמונת מסירה", "תוודא כתובת", "תוסיף לליקוט", "תגדיר יעד שבת/אקספרס", "תצמיד תווית". בירורים ששולחים WhatsApp כפופים לחובת אישור מפורש מהמשתמש לפני השליחה (העוזר מציג מה יישלח ולמי ושואל), מכבדים את הרשאות המשתמש ואת אותם שומרי כפילות של הכרטיסייה, והתשובות נקלטות ומוצגות בדף המשלוח כרגיל. אגב כך הוקשח גם כלי פתיחת הפניות הקיים של העוזר: בדיקת הרשאה, ולידציית קטגוריה ורישום ביומן הפעילות — באותם כללים של פתיחת פנייה ידנית. בנפרד, בדוחות התשלום לשליחים פוצל שדה "חבילות נוספות" לשני שדות — "חבילות נוספות במסירה" ו"חבילות נוספות באיסוף" — בכרטיס דוח הרווחים של השליח, בדוח בפורטל השליח, בפירוט התשלום לסאב ובייצוא האקסל, כך שברור כמה מכספי החבילות הנוספות הגיע ממסירות וכמה מאיסופים. ובנפרד — תוקן הגורם למסך "משהו השתבש" שהופיע לאחרונה בעת פתיחת דף משלוח אחרי ביקור בדף ניהול השליחים (שני חלקים של המערכת שמרו נתוני שליחים באותו מטמון בצורות שונות, ופתיחת משלוח קרסה על הצורה הלא-צפויה); בנוסף, טאב שנשאר פתוח מלפני עדכון גרסה מתרענן מעתה אוטומטית פעם אחת כשהוא נתקל בקבצי גרסה ישנים, במקום להציג את מסך השגיאה הכללי. ובנפרד — הוקשחה התאמת אזורי החלוקה: עד היום אזורים שחלקו קידומת מספרית ("11" מול "11ב") נחשבו התאמה בכל המערכת — זיהוי טעויות מיון, אזהרת טרום-שיבוץ, סריקת מחסן, הצ'קליסט והמעוכבים בפורטל השליחים ותצוגת "אחראים באזור" בדף המשלוח — בגלל הקלה שנועדה לערים שמפוצלות לתתי-אזורים (ירושלים: "1- מרכז" ≈ "1- צפון"). מעתה ההקלה חלה רק כשעיר המשלוח היא אכן ישוב רב-אזורי; לכל שאר הישובים נדרשת התאמת אזור מדויקת, כך ששליח האחראי על 11ב אינו נחשב עוד אחראי על משלוחי אזור 11.
- הכרטיסייה מציגה רק אירועים שקרו במשלוח — אפס שורות ריקות
- כפתור "הוספת אירוע" אחד עם תפריט מקובץ של כל סוגי האירועים
- אירוע לא זמין מוסבר בטקסט משנה במקום להיעלם או להישאר סתום
- אייקון מידע ליד כל סוג אירוע — הסבר על מהות האירוע ואופן השימוש בריחוף
- אירוע שהופעל נשאר בכרטיסייה לצמיתות עם כל היסטוריית השינויים שלו
- עוזר ה-AI פותח אירועים תפעוליים בשפה חופשית — בירורים באישור מפורש בלבד
v01.250.000חדשמשלוחים / דף משלוחminorסקציית "בירורים" בדף המשלוח — אימות מסירה ובירור צפי בלחיצת כפתור, עם מעקב תשובות
כרטיסיית התפעול בדף המשלוח מציגה כעת סקציית "בירורים" עם שתי פעולות מהירות: "אימות מסירה" שולח לנמען את תבנית בדיקת המסירה ("קיבלת את המשלוח?") ועוקב אחר תשובתו, ו"בירור צפי" שולח שאלת צפי לקבוצת ה-WhatsApp של השליח המשו…
פרטים נוספים ↓הסתר ↑
כרטיסיית התפעול בדף המשלוח מציגה כעת סקציית "בירורים" עם שתי פעולות מהירות: "אימות מסירה" שולח לנמען את תבנית בדיקת המסירה ("קיבלת את המשלוח?") ועוקב אחר תשובתו, ו"בירור צפי" שולח שאלת צפי לקבוצת ה-WhatsApp של השליח המשויך למשלוח (ברגל הרלוונטית — שליח האיסוף למשימת איסוף). ליד כל פעולה מוצג צ'יפ סטטוס חי — לא בוצע / ממתין לתשובה / נענה (עם התשובה המילולית) / הכחיש קבלה / לא נענה — ולחיצה עליו פותחת את היסטוריית הניסיונות המלאה: מתי נשלח, מי יזם (משתמש או הבוט), מה נענה וכמה תזכורות נשלחו. תשובת השליח נקלטת אוטומטית מהקבוצה (תגובת-ציטוט מזוהה דטרמיניסטית), בירור צפי שלא נענה מקבל תזכורות אוטומטיות בשעות הפעילות, וכפתור שאינו זמין מסביר למה (אין שליח משויך, אין קבוצה מקושרת, לא הוגדרה תבנית). ההיסטוריה כוללת גם בירורי צפי שהבוט פתח בעצמו בעקבות שאלות לקוחות — כך שכל סיפור הצפי של המשלוח במקום אחד. תשובת הנמען לאימות מסירה נשמרת מעתה גם במלואה (הטקסט עצמו, לא רק אישר/הכחיש), וכפתור האייקון הישן של בדיקת המסירה בכותרת הדף הוחלף בסקציה החדשה. בהמשך היום נוסף שלב 2 — הבירורים הפכו לשגרת עבודה ברמת רשימת המשלוחים: כל שורה נושאת צ'יפ בירורים חי ("בירור פתוח" בכתום, "נענה"/"אישר קבלה" בירוק, "הכחיש קבלה" באדום; ריחוף מציג את התשובה המילולית), נוסף פילטר "בירורים" (ממתין לתשובה / נענה ב-7 הימים האחרונים) שמסונכרן גם עם ספירות הפילטרים האחרים, ובסרגל הפעולות הגורפות נוסף "בירור צפי" מרוכז: בחירת משלוחים שולחת הודעה מאוחדת אחת לכל קבוצת שליח (לא הצפה של הודעה-לכל-משלוח), עם רשימת המשלוחים ובקשה לציין מספר משלוח ליד כל תשובה. שליח שעונה בציטוט עם מספרי משלוחים — כל תשובה נקשרת למשלוח שלה; תשובה קולקטיבית ("הכל עד 17:00") סוגרת את כולם; ותשובה ממוספרת גם בלי ציטוט נתפסת במנגנון קיבוץ-הברקודים הקיים. ובהמשך — שלב 3: שלושה סוגי בירור חדשים בסקציית הבירורים. "שאלה לשליח" — שאלה חופשית בכל נושא שנשלחת לקבוצת השליח עם פרטי המשלוח, והתשובה נקלטת ומוצגת כמו בירור צפי. "בקשת תמונת מסירה" — בקשה מהשליח לתמונת POD למשלוח שנמסר; הבירור נסגר רק בתמונה (טקסט כמו "מיד אשלח" לא סוגר אותו), והתמונה משויכת רק בזיהוי ודאי — ציטוט הבקשה שלנו או מספר המשלוח בכיתוב — נשמרת אוטומטית על המשלוח (סקציית התמונות, קטגוריית POD) וזמינה בלחיצה מההיסטוריה. "אימות כתובת" — הודעה ישירה לנמען (צ'אט 1:1) עם הכתובת הרשומה, כולל דירה/קומה/הערות, ובקשה לאשר או לתקן; התשובה נרשמת על המשלוח לטיפול הצוות — עדכון הכתובת נשאר החלטה אנושית, ונמען לעולם לא מקבל תזכורות אוטומטיות. כל הסוגים החדשים משתתפים גם בצ'יפ וּבפילטר "בירורים" ברשימת המשלוחים.
- אימות מסירה מול הנמען בלחיצה אחת — עם צ'יפ סטטוס חי והתשובה המילולית שחזרה
- בירור צפי לקבוצת השליח בלחיצה — התשובה נקלטת אוטומטית ומוצגת על המשלוח
- תזכורות אוטומטיות לשליח שלא ענה, בשעות הפעילות בלבד
- היסטוריית בירורים מלאה: מתי, מי יזם, מה נענה — כולל בירורים שהבוט פתח
- כפתור לא זמין מסביר בדיוק למה (אין שליח, אין קבוצה, חסרה תבנית)
- שלב 2: צ'יפ בירורים על כל שורה ברשימת המשלוחים + פילטר "ממתין לתשובה / נענה לאחרונה"
- שלב 2: בירור צפי מרוכז מסרגל הפעולות — הודעה מאוחדת אחת לכל קבוצת שליח
- שלב 2: תשובות ממוספרות-ברקוד ותשובות קולקטיביות בציטוט נסגרות אוטומטית על המשלוחים הנכונים
- שלב 3: שאלה חופשית לשליח עם מעקב תשובה
- שלב 3: בקשת תמונת מסירה — נסגרת רק בתמונה, שנשמרת אוטומטית על המשלוח
- שלב 3: אימות כתובת מול הנמען ב-1:1 — התשובה נרשמת, העדכון נשאר החלטה אנושית
v01.249.007תיקוןהרשאות סוכניםסוכן ראה משלוחים של לקוחות שאינם שלו — כשהנמען חלק שם עם לקוח שלו
סוכן איתר בחיפוש משלוח של שולח שאינו לקוח שלו, רק משום ששם הנמענת היה זהה לשם לקוחה שכן משויכת אליו.
פרטים נוספים ↓הסתר ↑
סוכן איתר בחיפוש משלוח של שולח שאינו לקוח שלו, רק משום ששם הנמענת היה זהה לשם לקוחה שכן משויכת אליו. הסיבה: סינון המשלוחים של סוכן כלל מסלול-גיבוי לפי שם (למשלוחי legacy שאינם מקושרים לרשומת לקוח), שהשווה בטעות גם את שדה שם הנמען — ולא רק את שם השולח — מול שמות לקוחות הסוכן. כך כל משלוח שנשלח אל אדם ששמו זהה לשם לקוח של הסוכן דלף לרשימה, לחיפוש, למפה ולפתיחת המשלוח. התיקון הוחל על כל שבעת המסלולים שחולקים את הסינון: ההשוואה לפי שם נעשית מעתה מול שם השולח בלבד, ורק במשלוחים שאינם מקושרים לרשומת לקוח — משלוח מקושר נשפט לפי הקישור בלבד, כך שגם התנגשות שמות בין שתי רשומות לקוח אינה מדליפה. אומת מול נתוני האמת: התיקון מסיר בדיוק שבעה משלוחים דולפים ואינו מסתיר אף משלוח לגיטימי. ובהמשך תוקן ליקוי עמוק יותר בזיהוי משימות: גם משלוח-מסירה רגיל מורכב משתי רגליים — איסוף ומסירה — ולעיתים שליח משובץ רק על רגל האיסוף. עד היום העיצוב הסתמך רק על סוג המשימה של המשלוח, כך שדיווח של שליח-איסוף ('הנמענת לא מוצאת את האיסוף') הוצג לשולח עם כתובת היעד — כתובתו של השולח עצמו — בתוספת הצהרה שגויה ש'הכתובת שגויה'. מעכשיו הרגל שדרכה השליח המדווח מקושר למשלוח קובעת: שליח שכל הביקורים שלו על המשלוח הם איסוף מקבל התנהגות איסוף מלאה — בלוק כתובת המוצא, ניסוח איסוף, אי-כתיבת שדות יעד מתשובת השולח (בכל ארבעת התרחישים הכותבים), ואי-העברת הנחיות 'תחזירו' לשליח שמעולם לא אסף. תבנית 'כתובת שגויה' מציגה כעת את הדיווח האמיתי של השליח בניסוח בטוח ללקוח במקום ההצהרה הקבועה, והמסווג מחריג 'לא מוצא את החבילה/האיסוף' — קושי באיתור החבילה, לא בכתובת.
v01.249.006תיקוןבוט צ'אט לקוחות קצה / נמען שגויטלפון מתוקן מהשולח מעודכן במשלוח אוטומטית; ושומר מפני קבוצת שליח שהיא בעצם קבוצת לקוח
שלושה תיקונים משני אירועים.
פרטים נוספים ↓הסתר ↑
שלושה תיקונים משני אירועים. (1) נמען דיווח 'זו טעות, אני לא הנמענת' — כנראה מספר שגוי במשלוח. הבוט עדכן את השולח וביקש 'לעדכן פרטי נמען/טלפון או לבטל — השיבו כאן', אבל לא רשם בשום מקום שתשובה ממתינה: כשהשולח ענה בציטוט עם המספר הנכון, דבר לא קרה, והצוות עדכן ידנית 38 שעות אחר-כך. מעכשיו הפנייה נרשמת (48 שעות — עסקים עונים גם ביום העסקים הבא), טלפון מתוקן בתשובה נכתב למשלוח מיד באותו מסלול כתיבה של יתר התרחישים, והשולח מקבל אישור עם המספר החדש. ההודעה לשולח כוללת כעת גם את בלוק פרטי המשלוח המלא — כולל הטלפון הרשום אצלנו, שהוא בדרך כלל השדה שבו הטעות — כדי שיהיה מול מה לבדוק. (2) באותה שיחה, 'אומרת שלא קיבלה הודעה' סווג כטענת אי-מסירה — אבל היא לא קיבלה את ההודעה (כי המספר שגוי), לא את המשלוח. זיהוי מחלוקת המסירה מחריג כעת אי-קבלה שהמושא שלה הוא הודעה/סמס, על כל הצורות ('את ההודעה', 'שום הודעה', 'כל הודעה'), ועדיין מזהה הודעה שטוענת גם שהחבילה עצמה לא הגיעה — כולל בניסוח משותף ('לא קיבלה שום הודעה ושום חבילה'). (3) בקשת בירור-עיכוב שנועדה לשליח נשלחה לקבוצת לקוח — ולקוח אחר בכלל: קבוצת הוואטסאפ הרשומה על השליח הייתה בפועל קבוצת לקוח (שיבוש נתונים, יחיד מסוגו במערכת). נוסף שומר: קבוצה שרשומה גם על לקוח לעולם לא תקבל תוכן מופנה-שליח — תוכן כזה נושא פרטי נמענים של לקוחות אחרים; במקום זה הטיפול עובר לצוות. בהמשך היום תוקן גם קצה משלים: שליח שחזר על דיווח ('טלפון לא תקין') בזמן שהפנייה לשולח עדיין ממתינה קיבל שתיקה מוחלטת — מניעת-הכפילות צדקה כשלא פנתה לשולח שוב, אבל איש לא אמר לשליח שהעניין בטיפול, ונציגה נכנסה ושכפלה ידנית את הפנייה שהבוט כבר שלח. מעכשיו דיווח חוזר — כשהפנייה פתוחה כבר חצי שעה לפחות (כדי לא לענות לזנב הודעות של הדיווח המקורי) — נענה בשורה קצרה: 'הדיווח כבר הועבר לשולח וממתינים לתשובתו', פעם אחת לשעתיים לכל משלוח. הוחל על ארבעת תרחישי הדיווח (אין מענה, טלפון שגוי, כתובת שגויה, סירוב לקבל).
v01.249.005תיקוןבוט צ'אט לקוחות קצה / תלונות מסירהתשובת השליח לבירור מסירה מגיעה כעת לנמען שפתח אותו — ולא משויכת למשלוח אחר
נמען התלונן שלא קיבל משלוח שסומן כנמסר וביקש תמונה.
פרטים נוספים ↓הסתר ↑
נמען התלונן שלא קיבל משלוח שסומן כנמסר וביקש תמונה. הבוט דיווח לקבוצת השליחה ('והשב כאן — מה קרה במסירה?'), והשליחה ענתה 'נמסר בארון חשמל לפני 3 ימים'. אבל הדיווח לא רשם בשום מקום שתשובה ממתינה — כך שהתשובה הייתה יתומה, ומנגנון אחר תפס אותה: היא שויכה כפתרון של פנייה פתוחה על משלוח אחר לגמרי, שולח לא-קשור קיבל 'עדכון מהשליח', והנמען ששאל — נשאר בלי כלום. שלושה תיקונים: (1) דיווח תלונת מסירה לקבוצת שליח פותח כעת פנייה ממתינה, כך שהתשובה משתייכת אליו. (2) התשובה מנותבת קודם כל לנמען שפתח את הבירור — בניסוח בטוח ללקוח (לעולם לא מילות השליח הגולמיות), ורק בתוך חלון 24 השעות של וואטסאפ; שיחת הנמען מסומנת לנציג בכל מקרה, כי תשובת השליח היא טענה ולא מסירה מאומתת, והתוכן נשמר גם בתיק המשלוח כרשומה עמידה. תשובה שאינה נושאת מידע ('רגע, אבדוק') לא סוגרת את הבירור — הוא נשאר פתוח לתשובה האמיתית. (3) שומר נוסף במנגנון שיוך דיווחי 'הסתדר': גם כשפנייה אחת בדיוק פתוחה בקבוצה, אם ההודעה האחרונה שלנו באותה קבוצה (עד רבע שעה) עסקה במשלוח אחר — הבוט שותק במקום לנחש; שני האירועים שנצפו הגיעו 6–11 דקות אחרי הודעה כזאת בדיוק. הביקורת ההנדסית תפסה לפני השחרור שתהליך התזכורות היה מבטל את הפנייה החדשה תוך רבע שעה — כי תלונת מסירה נפתחת מעצם טבעה על משלוח שכבר 'נמסר', והתהליך סוגר פניות על משלוחים סגורים; הוחרג. באותו יום תוקן גם סדר-הודעות הפוך שהשאיר שליח ללא מענה: שליח כתב 'אמ' (אין מענה), שלח צילום מדבקה שנייה אחר-כך, והוסיף 'והמקום נראה סגור' — שלוש הודעות, אפס תגובה. מנגנון השחזור הקיים ידע לחבר מדבקה שנשלחה לפני דיווח, אבל לא דיווח שנשלח לפני מדבקה. כעת, כשמגיעה הודעת מדבקה-בלבד שניות אחרי דיווח מאותו שולח שזוהה אך נכשל מחוסר מספר משלוח, השניים מחוברים והתרחיש רץ עם המספר ביד. שני תנאים קשיחים: הדיווח הקודם חייב להיות ללא מספר משלוח משלו, וחייבת להיות רשומת כשל תואמת ביומן ההחלטות לאותו טקסט בדיוק — כך שפטפוט או דיווח שכבר טופל לעולם לא ישוחזרו. ותוקן גם שידור-על-תלונה: נציגה שאלה 'מה עם האיסוף?', הקבלנית השיבה בציטוט 'זה לא משודר כאיסוף אז לא משובץ על שליח' — הסבר על שידור קיים בסוג שגוי — והבוט קרא את המילה 'משודר', שאב את מספר המשלוח מהודעת הנציגה המצוטטת, ושידר משימה חדשה (ובסוג שגוי) שהצוות נאלץ לבטל. מעכשיו: ביטוי שידור תצפיתי ('לא משודר', 'לא נסרק', 'לא מופיע לי') שמגיע כתגובת-ציטוט להודעה של אדם — בלי מספר משלוח משל הכותב — נקרא כהסבר ולא כבקשה, והבוט שותק; בקשה מפורשת ('תשדרו', 'שימו עלי') ממשיכה לעבוד בכל הקשר, כולל בציטוט הודעת נציג, וקבלן שפותח בעצמו ב'לא משודר' ממשיך לקבל את הזרימה הרגילה.
v01.249.004תיקוןבוט צ'אט לקוחות קצה / זיהוי משלוחלקוח שאל על צפי משלוח שלו — והבוט ענה 'אינו משויך למשלוח שלך'
לקוח שאל בקבוצה 'מה קורה עם 26198708?', והבוט הפיק פתק פנימי שהמשלוח 'אינו משויך למשלוח שלו במערכת' — למרות שהוא כן.
פרטים נוספים ↓הסתר ↑
לקוח שאל בקבוצה 'מה קורה עם 26198708?', והבוט הפיק פתק פנימי שהמשלוח 'אינו משויך למשלוח שלו במערכת' — למרות שהוא כן. הסיבה: מבנה משפחת לקוחות. הקבוצה רשומה על לקוח-בן (קקאו טבעי) שהוא תת-לקוח של לקוח-אב (אלפהבית), והמשלוח שייך לאב. הבוט חיפש רק ב'לקוח + הילדים שלו' — לא כלל את האב — ולכן לא מצא. הניתוב ההפוך (החוצה) כבר עבד נכון: משלוח של אב בלי קבוצה משלו מנותב לקבוצת המשפחה היחידה; התיקון פשוט מַראה את זה גם פנימה. כעת, כששואלים בקבוצה על משלוח, הבוט מחפש בכל המשפחה שחולקת את הקבוצה — אב, בנים ואחים — אך ורק כשלמשפחה קבוצה אחת בדיוק, בדיוק כמו הכלל שכבר קיים בניתוב היוצא. כשלבנים יש קבוצות נפרדות (עסקים שונים) — ההיקף נשאר צר כדי שמשלוח של אח אחד לא יעלה בצ'אט של האחר. התיקון הוחל על שלושה תרחישים שמזהים משלוח לפי הלקוח (צפי מסירה, מחלוקת מסירה, ותיאום מועד — שהיה הצר ביותר). מבנה משפחה בעומק שלוש-שכבות נשאר בהיקף הצר כדי למנוע חשיפה לצ'אט הלא-נכון.
v01.249.003חדשבוט תפעולי / כתובת מסירהשליח מדווח שחסר מספר דירה/קומה — יש לנו? נשלח לו. אין? נברר מול השולח
כששליח או קבלן מדווח שחסר לו פרט כתובת כדי למסור (מספר דירה, קומה, כניסה או קוד כניסה), הבוט בודק כעת מה יש לנו לפני שהוא פונה לשולח.
פרטים נוספים ↓הסתר ↑
כששליח או קבלן מדווח שחסר לו פרט כתובת כדי למסור (מספר דירה, קומה, כניסה או קוד כניסה), הבוט בודק כעת מה יש לנו לפני שהוא פונה לשולח. אם הפרט קיים אצלנו — הוא נשלח לשליח מיד ('לפי הרישום שלנו למשלוח X: דירה 4'), בלי להטריד את השולח; אם באמת חסר אצלנו — נפתחת פנייה לשולח לאותו פרט ספציפי ('חסר אצלנו: קומה'), במקום להודיע לו סתם ש'הכתובת שגויה'. הרקע: קבלן כתב 'לא רשום מספר דירה, איפה להשאיר?' על משלוח שהיה בו מספר דירה, והבוט פנה לשולח בכל זאת; ובמקרה אחר שליח שאל 'קומה? דירה?' על משלוח שבו הפרטים באמת חסרו, ולא נעשה כלום. מדידה: מתוך 37 פניות כתובת ב-30 יום, ל-10 כבר הייתה דירה ול-12 קומה — כלומר בכשליש מהמקרים כבר החזקנו את הפרט. זיהוי איזה פרט חסר נעשה בקריאת AI ממוקדת; בכל ספק הבוט פונה לשולח כמו קודם. בנוסף, כשיש אישור גורף להניח ליד הדלת והבוט מאשר לשליח להניח מיד — ההודעה כוללת כעת גם קומה/דירה/כניסה/הערה, כדי שידע ליד איזו דלת. התרחיש 'כתובת שגויה/חסרה' כבוי כברירת מחדל ומופעל פר-לקוח.
- פרט כתובת שחסר לשליח ונמצא אצלנו — נשלח אליו מיד במקום להטריד את השולח
- פרט שבאמת חסר — פנייה ממוקדת לשולח על אותו פרט, לא 'כתובת שגויה' כללית
- אישור הנחה ליד הדלת כולל כעת קומה/דירה/כניסה כדי שהשליח ידע היכן
v01.249.002תיקוןבוט תפעולי / פרטי משלוח לשליחבלוק פרטי המשלוח לשליח חשף כתובת אבל לא קוד כניסה והנחיות מסירה
שליח צילם מדבקה של משלוח, קיבל רחוב/עיר/טלפון, ונתקע כשעה — כי מה שהיה צריך כדי למסור בפועל (קוד כניסה 0852#, 'להשאיר בארון חשמל') חי בהערת היעד החופשית, שהבוט מעולם לא הציג.
פרטים נוספים ↓הסתר ↑
שליח צילם מדבקה של משלוח, קיבל רחוב/עיר/טלפון, ונתקע כשעה — כי מה שהיה צריך כדי למסור בפועל (קוד כניסה 0852#, 'להשאיר בארון חשמל') חי בהערת היעד החופשית, שהבוט מעולם לא הציג. מדידה על 26,574 משלוחים הראתה שזו לא פינה: השדות המובנים לכניסה/קוד מאוכלסים ב-0% ו-2% בלבד, בעוד הערת היעד מאוכלסת ב-40% מהמשלוחים — ו-59% מההערות שנדגמו קריטיות למסירה (קוד כניסה, 'להשאיר ליד הדלת', קוד שער, בית פרטי). כלומר השליח נתקע על אותו מחסור בכל משלוח כזה. בלוק פרטי המשלוח שהבוט שולח לשליח (וללקוח העסקי) כולל כעת גם כניסה, קוד כניסה, והערת המסירה של הנמען — שורה אחת, מכווצת ומוגבלת באורך. אותה תוספת הוחלה גם על הודעת שיבוץ האיסוף שהקבלן קורא כדי להחליט אם לקחת את האיסוף, שם הערת המוצא נושאת את אותו סוג מידע ('המחסן בכניסה האחורית, קוד 4417'). ההערות הפנימיות באמת (הערת שליח, הערה ארגונית, הערת משלוח, מחיר) נשארות מוסתרות מהקבוצה כפי שהיו. במקביל, התקציר האוטומטי שמנוסח ללקוח כשיש קושי במסירה כבר לא יבקש 'קוד כניסה' מתחת לבלוק שכבר מציג אותו בהערה.
v01.249.001שיפורדף משלוח / תיק המשלוחליטושים בתיק המשלוח
הוסר טאב הסינון 'ניסיונות מסירה' מתיק המשלוח — ניסיונות המסירה מוצגים ממילא בדף המשלוח עצמו, והטאב הכפיל מידע שכבר נגיש שם.
v01.249.000חדשבוט צ'אט לקוחות קצה / עיכוביםminorעיכוב במסירה — הבוט מבקש צפי מהשליח שמחזיק את המשלוח, ומציין כמה ימים הוא אצלו
עד היום פנייה של נמען על משלוח שחרג מימי ההפצה הסתיימה בהסלמה לנציג: מי שבאמת יודע איפה החבילה — השליח שמחזיק אותה — לא נשאל כלל, והתשובה ללקוח הייתה תלויה בכך שנציג יבחין בפתק.
פרטים נוספים ↓הסתר ↑
עד היום פנייה של נמען על משלוח שחרג מימי ההפצה הסתיימה בהסלמה לנציג: מי שבאמת יודע איפה החבילה — השליח שמחזיק אותה — לא נשאל כלל, והתשובה ללקוח הייתה תלויה בכך שנציג יבחין בפתק. נוסף תרחיש 'עיכוב במסירה — בקשת צפי מהשליח': כשהמשלוח בסטטוס 'יצא להפצה' והנמען מדווח על עיכוב, נשלחת לקבוצת השליח בקשת צפי מסירה, וההסלמה לנציג נשארת במקביל. שלוש הגבלות מכוונות: התרחיש פועל אך ורק כשהמשלוח כבר בידי שליח המסירה — בסטטוסים מוקדמים יותר העיכוב הוא אצלנו ואין את מי לשאול, ולכן הבוט שותק; הוא נשלח רק לקבוצה מקושרת ולעולם לא לצ'אט פרטי; והוא מופעל רק בענף החריגה מההתחייבות, לא בכל שאלת 'מתי יגיע'. ההודעה לשליח מציינת תמיד כמה ימי עסקים המשלוח אצלו — מרגע השיבוץ אליו, לא מרגע שנקלט אצלנו — בדיוק כמו השורה שמפיק כפתור 'העתקה לקבלן' בעמוד פערי ההפצה, ובאותו חישוב ימי עסקים. הסיבה מהותית: משלוח ששכב אצלנו במחסן ארבעה ימים והועבר לשליח אתמול הוא עיכוב שלנו, ופתיחת הודעה במספר שאינו באחריותו מזמינה אותו להתעלם ממנה. הצגת המספר הנכון גם מגנה עליו וגם מחדדת לנו היכן העיכוב האמיתי. התרחיש כבוי כברירת מחדל ומופעל פר-לקוח בהגדרות → תרחישי בוט, כולל תבנית הודעה הניתנת לעריכה.
- בקשת צפי אוטומטית לקבוצת השליח כשנמען מדווח על חריגה מימי ההפצה
- ההודעה מציינת כמה ימי עסקים המשלוח אצל אותו שליח — מרגע השיבוץ אליו בלבד
- פועל רק כשהמשלוח כבר בידי שליח המסירה; כשהעיכוב אצלנו הבוט שותק
- כבוי כברירת מחדל — מופעל פר-לקוח בהגדרות → תרחישי בוט
v01.248.006תיקוןבוט תפעולי / מנוע התרחישיםדיווח 'הסתדר' של שליח שויך למשלוח הלא-נכון — הבוט הפסיק לנחש
בקבוצת שליח, נציגה התלוננה על משלוח 26308421 שהושאר מאחורי הדלת.
פרטים נוספים ↓הסתר ↑
בקבוצת שליח, נציגה התלוננה על משלוח 26308421 שהושאר מאחורי הדלת. השליח ענה 'לא השארתי מאחורי הדלת' ואז 'מסרתי ביד לבן שלה' — שתי הודעות שעוסקות באותו משלוח שהנציגה שאלה עליו. הבוט לקח את המשפט השני וגישר אותו ללקוח בננה כפתרון של פנייה פתוחה אחרת לגמרי, על משלוח 26208682 — שהוא בכלל משימת איסוף. הלקוחה ענתה 'זה איסוף' ונציגה נאלצה לכתוב 'מתנצלים, טעות של הבוט'. הסיבה: כשדיווח פתרון אינו מזכיר מספר משלוח ואינו מצטט הודעה, הקוד בחר את הפנייה הפתוחה האחרונה באותה קבוצה. מדידה על 30 יום הראתה שזה לא מקרה קצה אלא ברירת המחדל — אף אחד מ-19 דיווחי הפתרון לא הכיל מספר משלוח, ו-12 מהם נורו כששתי פניות או יותר היו פתוחות באותה קבוצה, כלומר הימור על מה שנאמר ללקוח משלם. באירוע עצמו היו שלוש פניות פתוחות. מעכשיו, כשדבר בהודעה אינו מזהה משלוח, הבוט מגשר רק אם פנייה אחת בדיוק פתוחה בקבוצה; אחרת הוא שותק והפנייה נשארת פתוחה לתשובה האמיתית שלה. נוסף שומר שני, בלתי תלוי: ניסוח של מסירה ('מסרתי', 'נמסר', 'סופק', 'הושאר') אינו יכול לפתור משימת איסוף — באיסוף אוספים, לא מוסרים. שני המשלוחים היחידים מסוג איסוף בדגימה קיבלו בדיוק דיווח כזה, כך שזו תבנית ולא תקלה בודדת. שני השומרים דטרמיניסטיים ואינם תלויים בשיפוט של מודל; מחיר מודע הוא ששליח שמסיים איסוף בניסוח 'מסרתי במחסן' לא ייצור עדכון אוטומטי — עדכון שהוחמץ זול בהרבה מעדכון שגוי.
v01.248.005שיפורבוט תפעולי / מנוע התרחישיםהודעת המשך של לקוח אחרי שהתשובה כבר הועברה — מסומנת לנציג במקום להיעלם
פנייה נסגרת ברגע שהתשובה הראשונה מתקבלת, ומאותו רגע אין פנייה פתוחה בשיחה — כך שכל מה שהלקוח הוסיף מיד אחריה נפל בשקט ולא הגיע לאיש.
פרטים נוספים ↓הסתר ↑
פנייה נסגרת ברגע שהתשובה הראשונה מתקבלת, ומאותו רגע אין פנייה פתוחה בשיחה — כך שכל מה שהלקוח הוסיף מיד אחריה נפל בשקט ולא הגיע לאיש. מדידה על 30 יום: 99 מתוך 123 הפניות שנסגרו (80%) קיבלו הודעת המשך בתוך חמש דקות, וכולן נזרקו — מספרי טלפון נוספים ('0556710967 מספר נוסף'), תיקוני כתובת ('מספר בית לשנות גם ל- חמדת השקד 5'), הנחיות מסירה ('שישימו ליד הדלת זה בית פרטי'), וגם ההמשך של האירוע שפתח את כל הבירור הזה ('תתקשרו לפני, או שתשלחו ווטסאפ'). מעכשיו הודעה כזו מקבלת פתק פנימי בצ'אט העסקי שאומר במפורש שהיא לא בוצעה, ושיש לבדוק אם היא דורשת פעולה. הבוט אינו שולח דבר לשליח, אינו נוגע בפנייה, אינו כותב למשלוח, וההודעה ממשיכה בדרכה הרגילה — כך שבקשה שהיא באמת נושא חדש (למשל תיאום מועד אחר) עדיין פותחת תרחיש משלה. הריסון הזה הוא הלקח המרכזי: שלושה תכנונים שניסו להכריע אוטומטית אם הודעה כזו ממשיכה את התשובה או פותחת נושא חדש נפסלו כולם — איחוד לפי סמיכות בזמן גרם לגישור בליל ללקוח והוחזר לאחור; היצמדות לציטוט החייתה תוכן שהמערכת פסלה במכוון, כי פנייה נשארת פתוחה דווקא כשההודעה נשפטה כלא-תשובה; והעברה ישירה לשליח ייחסה הנחיה למשלוח הלא-נכון. השאלה עצמה דו-משמעית, ונציג שקורא את השיחה מכריע אותה בשנייה. מסונן דרך זיהוי הנחיה כדי שכל 'תודה' לא ייצור פתק, ופועל רק כשפנייה אחת בדיוק נסגרה — כששתיים נסגרו יחד אין דרך לייחס, והמערכת שותקת.
v01.248.004תיקוןבוט צ'אט לקוחות קצה / בקשת ביטולבקשת ביטול — הודעה כפולה לשולח, וסתירה לוגית בנוסח
לקוחה ביקשה לבטל משלוח.
פרטים נוספים ↓הסתר ↑
לקוחה ביקשה לבטל משלוח. ב-06:09 נשלחה לקבוצת השולח (ערוץ 2000) השאלה 'המשלוח טרם נאסף — האם לבטל?'; הצוות ביטל בפועל ב-06:38; וב-09:01 נשלחה לאותה קבוצה הודעה שנייה על אותו משלוח, שאמרה 'המשלוח כבר נאסף ונמצא בתהליך (בוטל), ולכן לא ניתן לבטלו'. ארבע תקלות נפרדות באותה הודעה, וכולן תוקנו. (1) הכפילות: מנגנון מניעת-הכפילות בדק אם פתק ה-AI של השיחה מכיל את הסימן 🛑 — אבל אותו שדה נדרס בכל מחזור עיבוד, ובנוסף הפתק שנכתב בענף 'פנייה חוזרת' כלל לא הכיל את הסימן. כלומר הדגל מחק את עצמו כבר בהודעה הבאה: ב-06:11 הוא עוד תפס (ותוך כדי מחק את עצמו), ב-06:21 פתק אחר דרס את מה שנשאר, וב-09:01 כבר לא היה דבר שיעצור שליחה שנייה. במקומו נרשם כעת ביומן העיבוד — יומן מוסף-בלבד שאינו נדרס — סימון של מה שהבוט **באמת שלח**, ולא של מה שהמודל ביקש; כך שדגל שהתרחיש שלו כבוי, או ששליחתו נכשלה, אינו חוסם בטעות את הניסיון הבא. חלון החסימה 24 שעות. אותה תקלה בדיוק הייתה קיימת גם בדגל תלונת המסירה (🔴) ובדגל הכתובת הלא-מעודכנת (📍) — ותוקנה בשלושתם יחד. (2) הסתירה: משלוח שכבר בוטל / נמסר / נכשל סופית מוגדר כעת כשלב נפרד שאין בו מה לבטל או לעצור — במצב כזה השולח אינו מקבל הודעה כלל, נכתב פתק מדויק לנציג, וגם התשובה לנמען מוחלפת: במקום להבטיח לו 'אנחנו בודקים מול השולח' (הבטחה שהקוד בדיוק החליט לא לקיים) הוא מקבל את הסטטוס בפועל. הנוסח לשולח חדל לטעון 'נמצא בתהליך' ומציין 'סטטוס נוכחי'. (3) ניסוח פנימי שדלף: תיאור הפנייה נכתב על ידי המודל, והוא הוסיף לו פריט-פעולה שמיועד לנציג שלנו ('— לבדוק מול השולח לאישור ביטול') — שנכנס כלשונו להודעה שהלקוח העסקי קרא. השורש היה בפרומפט עצמו, שהדגים למודל בדיוק את הצורה הזאת; הדוגמה תוקנה ונוסף כלל מפורש שהתיאור מצוטט למי שמחוץ לחברה ואסור שיכיל הנחיה. בנוסף נוסף ניקוי דטרמיניסטי כרשת ביטחון, שהוחל גם על שלושת הזרימות האחיות שמצטטות את אותו תיאור לשולח או לשליח (נמען שגוי, תלונת מסירה, כתובת לא-מעודכנת). (4) מספר המשלוח הופיע פעמיים — בכותרת ההודעה ובתוך התיאור — ומוסר כעת מהתיאור כשהוא בסוגריים; מספר שמשובץ בתוך המשפט נשאר במקומו במכוון, כדי לא לשבש את העברית. בנוסף, הפתק לנציג בפנייה חוזרת חדל לטעון שהשולח עודכן, שכן ייתכן שהניסיון הקודם נכשל או שלא היה צ'אט מקושר. (5) נוסף לכך — הבוט כתב על עצמו בלשון כפולה ('מצטער/ת', 'מבינ/ה', 'מתנצל/ת'), וזה הסימן הבולט ביותר שמסגיר ללקוח שמולו עומדת מכונה; לקוחות אכן שאלו בשיחה 'זאת תשובה של בוט?'. הפרומפט לא הגדיר לבוט זהות כלל, והדוגמאות שבו עצמן נכתבו בלוכסן — ולכן המודל חיקה אותן. מעתה הבוט מדבר על עצמו בלשון נקבה יחיד באופן עקבי ('מצטערת', 'מבינה', 'מתנצלת'), כמקובל בשירות לקוחות, והלוכסן בגוף ראשון נאסר במפורש. בפנייה אל הלקוח, שמגדרו אינו ידוע, הנוסח מנוסח מראש כך שלא יידרש מגדר כלל (שאלה במקום ציווי, לשון רבים מנומסת) — כך ש'אנא שמור/י על זמינות' הפך ל'אנא שמרו על זמינות', ו'האם את/ה X?' הפך ל'הגענו ל-X?'. (6) ובהמשך לכך — הפנייה אל הלקוח עצמו כבר אינה ניטרלית כברירת מחדל אלא מזהה את מגדרו לפי השם הפרטי: מודול חדש מכריע מגדר מול רשימות שמות (עברית, ערבית ורוסית בכתיב עברי), והתשובה מוזרקת להקשר שהמודל מקבל. שלוש החלטות תכנון: אין ניחוש מורפולוגי לפי סיומת — 'נגמר ב-ה' = נקבה' מפיל את משה, שלמה, יהודה ואריה, וגם הופך 'מאפיית רינה' לאישה; שם דו-מגדרי (אור, טל, שחר, עדן, יובל, עמית, שרון) מוכרז ככזה מראש ומוחזר כבלתי-מוכרע; ושם שאינו ברשימות נשאר בלתי-מוכרע והבוט מנסח בלי מגדר — פנייה במגדר שגוי גרועה מלוכסן. במדידה על 20,000 שמות נמענים אמיתיים מוכרעים 55% (33% נשים, 22% גברים); רוב הבלתי-מוכרעים הם שמות עסקים ('בית', 'מרכז', 'קרית') ושמות דו-מגדריים — כלומר בדיוק המקרים שבהם ניטרליות היא התשובה הנכונה. שני אותות גוברים על השם: אם הכותב חושף את מגדרו בהודעותיו ('אני בטוחה', 'הייתי צריך') — הבוט הולך אחרי מה שנכתב, שכן בעל הטלפון אינו תמיד הנמען הרשום; ואם התברר שאין זה הנמען כלל — חזרה לניסוח ניטרלי. נוסף סקריפט למדידת הכיסוי, שמדפיס את השמות הנפוצים שטרם הוכרעו כרשימת עבודה להרחבה. (7) ולבסוף — הבטחה שלישית שלא כובדה, שהתגלתה בבדיקת משלוח 26242993: הנמען דיווח ב-12:46 שהשליח לא העלה את החבילה ליישוב אלא הניח אותה במחסום, והבוט ענה 'פתחתי כרגע בירור דחוף מול הגורמים הרלוונטיים' — אך לא נפתח דבר. השליח סימן 'נמסר' ב-12:55, תשע דקות אחרי התלונה, והדיווח לקבוצת השליח היה מותנה בסטטוס 'נמסר/הושלם' בלבד. כלומר: בזמן שהתלונה נכתבה המשלוח היה 'יצא להפצה', ולכן לא נשלח דיווח — לא בפרומפט ולא בקוד — והדבר היחיד שקרה הוא הסלמה לנציג. השער הורחב וכולל כעת גם 'יצא להפצה': ברגע שהחבילה בידי שליח המסירה, תלונה על אופן המסירה היא שלו לענות עליה, וזהו דווקא החלון שבו התלונה הכי ניתנת לפעולה — השליח עדיין במסלול. נוסח הדיווח מותאם לסטטוס: לשליח שטרם סימן מסירה נכתב 'המשלוח נמצא אצלך כעת בהפצה' במקום 'המשלוח מסומן כנמסר על-ידך', שהיא האשמה בדבר שלא נטען; ותבנית פר-לקוח שנשמרה בעבר ומקודד בה המשפט הישן לא תשמש במצב הזה. במקביל תוקנה גם ההבטחה עצמה: הבוט אינו מצהיר עוד שפנה לשליח — האם הדיווח ייצא בפועל נקבע אחרי שהוא כבר ענה, לפי תנאים שאינם גלויים לו (שליח משובץ, קבוצה מקושרת, תרחיש מופעל) — ומבטיח רק את מה שנכון בכל מקרה: שהפנייה הועברה לבדיקה דחופה ושנחזור עם תשובה.
v01.248.003תיקוןאינטגרציית אישופאישופ — הזמנות נקלטו בעיכוב של כשלוש שעות
הזמנה שנוצרה בחנות אישופ בשעה 12:39 נקלטה אצלנו כמשלוח רק ב-15:43.
פרטים נוספים ↓הסתר ↑
הזמנה שנוצרה בחנות אישופ בשעה 12:39 נקלטה אצלנו כמשלוח רק ב-15:43. הסיבה: חלון הזמן שנשלח ל-getorderlist נבנה לפי שעון השרת — ובוורסל השרת רץ ב-UTC — בעוד שאישופ קוראת את התאריכים לפי שעון ישראל. התוצאה היא חלון שמפגר בקביעות בשעתיים-שלוש (לפי שעון קיץ/חורף), כך שהזמנה נכנסה לטווח החיפוש רק אחרי שהשעון ב-UTC 'השלים' את הפער — כלומר כשלוש שעות אחרי שבוצעה. החלון נבנה כעת בשעון Asia/Jerusalem עם התחשבות בשעון קיץ, והזמנות נקלטות תוך דקות כמצופה. הובהר גם בתיעוד הקוד שהסינון של אישופ הוא לפי מועד יצירת ההזמנה — העברה של הזמנה ישנה לסטטוס המשדר לא מחזירה אותה לחלון, ולכן משיכה תקופתית אינה תחליף למצב Push (רישום Webhook על סטטוס מפעיל).
v01.248.002תיקוןבוט תפעולי / מנוע התרחישיםבוטל: איחוד תשובה מפוצלת — גרם לגישור תשובות לא קשורות
האיחוד שנוסף אתמול (תשובת לקוח/שליח שפוצלה לכמה הודעות מגושרת במלואה) הוחזר לאחור לאחר שגרם לתקלה בפרודקשן.
פרטים נוספים ↓הסתר ↑
האיחוד שנוסף אתמול (תשובת לקוח/שליח שפוצלה לכמה הודעות מגושרת במלואה) הוחזר לאחור לאחר שגרם לתקלה בפרודקשן. שליח ענה קודם לשאלת נציג על משלוח אחר ("מארז"), אחר כך שלח "תכף אשלח לכם מסודר", ורק אז את הצפי האמיתי ("יום א"). האיחוד קיפל את שלושתן וגישר ללקוח "מארז / תכף אשלח לכם מסודר / יום א" כתשובת הצפי — הודעה חסרת פשר. ההגנות שנבנו לא תפסו את זה: ה"נושא האחר" היה שאלת נציג ולא גישור נוסף (ולכן תנאי "גישור יחיד פתוח" התקיים), ולהודעות לא היה מספר משלוח (ולכן החיתוך לפי משלוח לא ירה), ובדיקת ה-LLM על הטקסט המאוחד אישרה אותו כי הוא אכן הכיל צפי תקין. המסקנה: בלי מזהה משלוח בהודעות אין דרך אמינה לדעת שכל הודעה ברצף שייכת לאותה תשובה. הבאג המקורי (חצי תשובה שאבדה) חוזר להיות פתוח.
v01.248.001תיקוןעוזר AI פנימי / סטטיסטיקות צ׳אט עסקיעוזר AI — מספר שנמסר בלי לספור בפועל, והתאמת שם שליח שהחזירה שליח לא קשור
מניתוח שיחות אמת (20-21/07).
פרטים נוספים ↓הסתר ↑
מניתוח שיחות אמת (20-21/07). (1) בשיחה על זיפ העוזר ענה נכון על שלוש שאלות כמות (186 משלוחים, 36 בטבריה — אומת, מדויק), ואז על השאלה הרביעית ('כמה פתוחים בטבריה') מסר בביטחון '12 משלוחים פתוחים' — **בלי לקרוא לאף כלי**. המספר האמיתי הוא 64. שומר האמינות תפס עד כה טענות ביצוע ('✅ נשלח') והצגת פרטי משלוח, אבל לא מספר בתשובה לשאלת 'כמה' — וזו בדיוק התשובה שנציג פועל לפיה. כעת מספר שנמסר כעובדה בלי שרצה כלי סופר נדחה אוטומטית והמודל נדרש לספור באמת. (2) התאמת שם שליח: המנגנון שתוקן לאחרונה (שמזהה שם מלא המפוצל לשם פרטי ומשפחה) הוא מכוון-רחב, ולכן שם קצר כמו 'אל אי' התאים במקרה ל-10 שליחים — כי 'אל' ו'אי' מופיעים בתוך שמות אחרים — והמערכת בחרה אחד שרירותי; הנציג ביקש 'אל איי שליחויות' וקיבל שליחה לא קשורה, בעוד השליח האמיתי היה באותה רשימה. נוסף דירוג התאמות: התאמה מדויקת גוברת על התאמה רציפה, וזו גוברת על צירוף-מילים מקרי, ושליח פעיל מועדף. כשההתאמה חלשה ויש מועמדים נוספים — הכלי מסמן זאת ומחזיר את החלופות במקום להציג ניחוש כעובדה. (3) עמוד הסטטיסטיקות של הצ׳אט העסקי נפל עם השגיאה 'Unexpected end of JSON input' בכל מעבר מ'שבוע' ל'חודש' או ל'3 חודשים'. הסיבה: השרת שלף את כל הודעות התקופה לזיכרון וחישב עליהן בקוד — כ-29 אלף הודעות בחודש — ומסד הנתונים סירב להחזיר תשובה בגודל כזה. שבוע הצליח במקרה כי הוא נכנס בדוחק מתחת לתקרה. כל החישוב (פילוח יומי, לפי משתמש, מפת השעות, קהלים, צ׳אטים עמוסים ושיעור ההכלה) הועבר לשאילתה עצמה, כך שחוזרות מאות שורות מסוכמות במקום עשרות אלפי הודעות — כל שלוש התקופות נטענות כעת בכחצי שנייה. המספרים אומתו מול החישוב הקודם ויצאו זהים. בנוסף, שגיאת שרת שמחזירה תשובה ריקה מוצגת כעת כהודעה קריאה במקום שגיאת דפדפן. דוח רווחי הנהגים עבר לסינון טננט ישירות על עמודת הביקור במקום דרך המשלוח — מדידה על הנהג העמוס ביותר הראתה שהניסוח הקודם אילץ סריקה סדרתית של כל 427 אלף הביקורים (209ms), והמעבר מפעיל את האינדקס הקיים ומוריד ל-31ms. שקילות שתי העמודות אומתה על כל השורות ונשמרה כסקריפט בדיקה חוזר.
- מספר שנמסר בלי שנספר בפועל נדחה אוטומטית — נצפה '12 פתוחים' כשהאמת 64
- דירוג התאמות שם שליח: מדויק > רציף > צירוף מילים מקרי, ושליח פעיל מועדף
- התאמה חלשה מסומנת ומחזירה חלופות במקום ניחוש שמוצג כעובדה
- סטטיסטיקות הצ׳אט העסקי: 'חודש' ו'3 חודשים' נטענים שוב, בכחצי שנייה
v01.248.000שיפורהרשאות / ביצועים / בוט AI / פורטל לקוחות / חנויותminorסוכן רואה רק את הלקוחות שלו, וטאב פתוח ברקע מפסיק להעיר את השרת
שלושה תיקונים מסקר העומסים.
פרטים נוספים ↓הסתר ↑
שלושה תיקונים מסקר העומסים. (1) הרשאות: התראת 'טעות מיון' שודרה לכל מי שמחובר ל-tenant, והיא כוללת ברקוד, שם לקוח, שם נהג ועיר יעד — כלומר סוכן שמשויך ללקוחות מסוימים קיבל התראות על לקוחות שאינם שלו, ויכול היה להיכנס מהן לכרטיס המשלוח. אותה בעיה בדיוק תוקנה כבר בערוץ עדכוני המשלוחים; הערוץ הזה נשכח. עכשיו כל אירוע נבדק מול היקף ההרשאות של הסוכן לפני שהוא נשלח, ובמקרה של תקלה במסד הנתונים ההתראה נחסמת ולא נשלחת. (2) ביצועים: שישה מנגנוני רענון אוטומטי המשיכו לפנות לשרת גם בטאבים מוסתרים — כולל שני מונים שיושבים בסרגל הצד, כלומר בכל עמוד ובכל טאב פתוח. הם היו התנועה הגדולה ביותר במערכת שאינה webhook. כעת הטיימר נעצר כשהטאב מוסתר ומתרענן מיד עם החזרה אליו, כך שמה שמוצג תמיד עדכני. (3) אמינות: תהליך מענה ה-AI ללקוח נהרג לעיתים באמצע בגלל מגבלת זמן, והשאיר פניות תקועות במצב 'בעיבוד' לנצח — הלקוח פשוט לא קיבל תשובה. עכשיו התהליך מפסיק לקחת פניות חדשות לפני מגבלת הזמן ומסיים בשלום, ובנוסף נוספה רשת ביטחון שמחזירה לתור פניות שנתקעו. פנייה ישנה מדי לא נענית באיחור אלא מסומנת לטיפול — מענה על הודעה מלפני שעתיים גרוע מלא לענות. בהמשך אותו סקר: (4) דוח התשלום לשליח שלף את הביקורים שלו מכל הלקוחות במערכת וסינן את הזרים בקוד — הסינון עבר לשאילתה עצמה, כך שהבידוד נאכף במסד הנתונים ולא בשכבת הקוד. (5) לצ׳אט ה-AI לא הייתה שום הגבלת קצב, ובנוסף בדיקת המכסה היומית קראה את המונה ורק אחר כך קידמה אותו — כך שכמה בקשות במקביל כולן ראו את אותו מספר, כולן עברו, והעודף חויב על המפתח של שיפינסט. הקידום עצמו הוא כעת הבדיקה. (6) חמשת סנכרוני החנויות רצו בסדר קבוע ובלי תקציב זמן, ולכן החנויות בסוף הרשימה לא סונכרנו כלל — לא באיחור — כי הריצה נקטעה תמיד באותה נקודה. הסדר עורבב והריצה מסתיימת מסודר, כולל דיווח כמה חנויות נדחו. (7) פורטל: מגבלת הכתובות המועדפות הועלתה מ-100 ל-500. לקוח הפצה הגיע לתקרה עם 97 כתובות שונות — כלומר שימוש לגיטימי ולא כפילויות — וכל ניסיון לשמור כתובת נוספת נכשל. התקרה נועדה למנוע התפוצצות של הרשימה, לא לשמש מכסה; היא גם הפסיקה להיות משוכפלת בין השרת למסך ההגדרות, כך שלא ייווצר מצב שהמסך חוסם במספר אחד והשרת בוחן אחר. לצד זה נוסף ייבוא כתובות מקובץ Excel: הלקוח מעלה טבלה, המערכת מזהה את העמודות לפי הכותרות בעברית או באנגלית, מתקנת שמות ערים לשם הרשמי מול מרשם היישובים (״ת״א״ הופך ל״תל אביב יפו״), ומדלגת על כתובות שכבר קיימות אצלו וכן על כפילויות בתוך הקובץ עצמו. לפני האישור מוצג בדיוק מה יקרה — כמה שורות ייובאו, כמה שמות ערים יתוקנו, לאילו שורות לא נמצא יישוב תואם וכמה שורות לא ייכנסו אם אין מספיק מקום עד התקרה. בנוסף נוספו ייצוא הרשימה הקיימת לאקסל והורדת קובץ תבנית, כך שאפשר להוריד, לערוך בנוחות ולהעלות בחזרה. פענוח הקובץ מתבצע בדפדפן ולא בשרת.
- סוכן מקבל התראות טעות-מיון רק על הלקוחות המשויכים אליו
- תקלה במסד הנתונים חוסמת את ההתראה במקום לשדר אותה לכולם
- טאב מוסתר לא פונה יותר לשרת — הטיימר נעצר ומתרענן עם החזרה לטאב
- מונה הלידים ומונה תובנות ה-AI בסרגל הצד הפסיקו לרוץ בכל טאב פתוח ברקע
- עמודי תיאום האיסופים, תמונת המחסן והמשתמשים — אותו טיפול
- מענה AI תקוע חוזר לתור אוטומטית במקום להישאר 'בעיבוד' לנצח
- פנייה ישנה מדי מסומנת לטיפול ידני ולא נענית באיחור
- דוח תשלום השליח מסונן לפי לקוח כבר בשאילתה — בידוד במסד הנתונים, לא בקוד
- הגבלת קצב לצ׳אט ה-AI (צוות ופורטל) — לפי משתמש ולא לפי כתובת IP
- המכסה היומית נתפסת אטומית — בקשות מקבילות לא חורגות יותר מהמכסה החינמית
- חנויות בסוף רשימת הסנכרון מסונכרנות סוף-סוף — הסדר מעורבב ויש תקציב זמן
- ריצת סנכרון שנגמר לה הזמן מדווחת כמה חנויות נדחו במקום לשתוק
- מגבלת הכתובות המועדפות בפורטל עלתה מ-100 ל-500
- ייבוא כתובות מועדפות מקובץ Excel, עם תיקון שמות ערים וזיהוי כפילויות
- ייצוא הרשימה לאקסל והורדת קובץ תבנית — עריכה בחוץ והעלאה בחזרה
v01.247.001תיקוןתשתית / ניטורנפילת מסד נתונים כבר לא מציפה את המנהל בעשרות התראות זהות
בין ה-19 ל-21 ביולי הגיעו למנהל המערכת עשרות התראות WhatsApp, חלקן זהות לחלוטין ובאותה שנייה.
פרטים נוספים ↓הסתר ↑
בין ה-19 ל-21 ביולי הגיעו למנהל המערכת עשרות התראות WhatsApp, חלקן זהות לחלוטין ובאותה שנייה. הסיבה לא הייתה ריבוי תקלות אלא פגם בצינור ההתראות עצמו: למנגנון מניעת הכפילויות שתי שכבות — זיכרון מקומי ורשומת סימון במסד הנתונים — ורק השנייה חוצה בין הרצות מקבילות. כשהיא נכשלה, המערכת בחרה להמשיך ולשלוח בכל זאת. אלא שהסיבה כמעט תמיד לכישלון שלה היא שמסד הנתונים עצמו הוא התקלה — כלומר ההגנה כובתה בדיוק ברגע שבו כל מסלול במערכת נופל בו-זמנית וזקוק לה. כעת ההתנהגות הפוכה: כשלא ניתן לתאם בין ההרצות, נשלחת התראת תשתית אחת בלבד בכל רבע שעה והשאר מדוכאות. במקביל, כל שגיאות הקישוריות למסד הנתונים (P6000, P6001, P6004, P1001, P2024 ודומותיהן) מקובצות תחת מזהה אחד — תקלת תשתית אחת מייצרת התראה אחת, לא אחת לכל מסלול שנפל בגללה. בנוסף תוקנו שני מקורות רעש: (1) דחייה צפויה של ליונוויל בייבוא חוזר — 403 "מספר הזמנה כבר קיים" ו-429 חריגה ממכסת הקצב — נרשמה כשגיאת מערכת חמורה; ייבוא חוזר של קובץ בן 500 שורות ייצר כך 253 התראות רצופות שאין מה לעשות איתן. כעת הן נרשמות כאזהרה, עדיין מוצגות בסיכום הייבוא, וללא צירוף פרטי הנמען ללוגים. (2) הסנכרון מול בלדר סרק בכל הרצה את כלל המשלוחים של הלקוח — 212,611 שורות ו-480MB — כדי לאתר 3 משלוחים, וחרג ממגבלת הזמן של מסד הנתונים ולעיתים גם מזמן הריצה המרבי. נוסף אינדקס ייעודי; זמן השאילתה ירד מחריגה מוחלטת ל-3 מילישניות.
- כשל בתיאום ההתראות שולח מעתה התראה אחת לרבע שעה במקום מטח בלתי מוגבל
- כל שגיאות הקישוריות למסד הנתונים מקובצות להתראה אחת במקום אחת לכל מסלול
- דחיית ייבוא חוזר של ליונוויל (403/429) ירדה מדרגת שגיאה לאזהרה — ללא התראה וללא פרטי נמען בלוגים
- סנכרון בלדר: 3 מילישניות במקום חריגה מהזמן המרבי, בזכות אינדקס חלקי בן 16KB
v01.247.000שיפוריבוא משלוחים מאקסלminorיבוא מאקסל: שורד סגירת טאב, לא בולע שורות, ומזהה ייבוא חוזר
יבוא של 710 שורות יצר 600 משלוחים בלבד, ואיש לא ידע.
פרטים נוספים ↓הסתר ↑
יבוא של 710 שורות יצר 600 משלוחים בלבד, ואיש לא ידע. שלושה ליקויים נפרדים הצטברו לזה, וכולם תוקנו. (1) הדפדפן היה המנוע — הוא החזיק את השורות בזיכרון ושלח אותן לשרת במנות; המנה החמישית מעולם לא יצאה, ו-4 המנות שכן רצו נרשמו כארבע רשומות היסטוריה נפרדות שכל אחת מדווחת "150 מתוך 150 הצליחו" בירוק. כעת הבקשה הראשונה מעלה את כל הקובץ, השורות נשמרות לפני שנוצר משלוח אחד, וכל בקשה אחריה רק אומרת "המשך את היבוא הזה" — מה שנותר מחושב בשרת מהפרש בין השורות שהועלו לתוצאות שנרשמו. כך הנהג בר-החלפה: הדפדפן מוביל כל עוד הטאב פתוח, וקרון חדש מסיים יבוא נטוש. סגירת טאב מעכבת יבוא — כבר לא מאבדת אותו. (2) לקובץ לא הייתה שורת כותרות, והשורה הראשונה — הזמנה אמיתית — נבלעה ככותרות. כעת המערכת מזהה קובץ שמתחיל ישר בנתונים לפי ראיה חיובית (טלפון או שני שדות מספריים), ממציאה שמות עמודות בעצמה, ולא מקריבה שורה. (3) זיהוי הכפילויות נשען אך ורק על עמודת "מזהה הזמנה", ולקובץ הזה היא כלל לא מופתה — כך שהמערכת דיווחה "0 כפולים" בביטחון, כשהמשמעות האמיתית הייתה "לא הצלחתי לבדוק". ייבוא חוזר של הקובץ כדי להשלים את החסר היה יוצר 600 כפילויות בשקט. כעת נוספה בדיקה שנייה מול היסטוריית היבוא של אותו לקוח: הזהות של שורה נגזרת ממזהה ההזמנה וגם מטלפון+רחוב+מספר, והמערכת מציגה באנר "N מתוך M השורות כבר יובאו" עם כפתור להסרתן בלחיצה. בדיקה מול הקובץ האמיתי: 708 מתוך 710 שורות זוהו נכון. הבדיקה מייעצת בלבד ולעולם לא מדלגת לבד — משלוח חוזר לאותה כתובת הוא תרחיש לגיטימי אצל לקוחות עלוני השבת.
- כל שורות הקובץ נשמרות בשרת לפני יצירת המשלוח הראשון — היבוא ניתן לשחזור מרגע זה
- קרון חדש (resume-imports) מסיים יבוא שהדפדפן נטש — סגירת טאב, נפילת רשת או פונקציה שנהרגה
- רשומת היסטוריה אחת לכל יבוא, עם מספר השורות האמיתי של הקובץ — יבוא חלקי מזוהה מיד
- אסימון בעלות מבטיח שהדפדפן והקרון לא יעבדו על אותן שורות במקביל וייצרו כפילויות
- כל אזכור של פיצול פנימי הוסר מהממשק — שם הקובץ, ההתראה וההיסטוריה
- קובץ שמתחיל ישר בנתונים כבר לא מאבד את שורתו הראשונה
- באנר "כבר ייבאת את השורות האלה" עם הסרה בלחיצה — עובד גם לקבצים ללא מזהה הזמנה
v01.246.001תיקוןבוט תפעולי / מנוע התרחישיםתשובה בציטוט על תמונה שלא זוהתה — הבוט שותק במקום לשייך למשלוח שגוי
לקוח הגיב בציטוט (swipe) על תמונת מדבקה של משלוח 26187386, עם מספרי טלפון מעודכנים.
פרטים נוספים ↓הסתר ↑
לקוח הגיב בציטוט (swipe) על תמונת מדבקה של משלוח 26187386, עם מספרי טלפון מעודכנים. הבוט מעולם לא זיהה את מספר המשלוח בתמונה, ולכן לא ידע על איזה משלוח התשובה — אבל ה-fast-path של הטלפון, שמניח ש"relay יחיד פתוח = חד-משמעי", התעלם מהציטוט ושייך את הטלפונים ל-relay הפתוח היחיד (כתובת שגויה על משלוח 26329877 אחר לגמרי), ושידר אותם לשליח הלא-נכון. כעת, תשובה שמצטטת הודעה שאינה השאלה שלנו מנותבת אך ורק למשלוח שאותה הודעה עוסקת בו — ואם הבוט לא מצליח לזהות את המשלוח (כמו תמונה שלא בוצע עליה OCR), הוא שותק במקום לנחש. ציטוט הוא אות מיקוד מפורש: לגורם אנושי ברור מיד על מה התשובה מתייחסת; הבוט, שלא מזהה את המספר, חייב לשתוק. שמירה על ההתנהגות הדטרמיניסטית לתשובת-טלפון על גישור "אין מענה" (ללא תלות ב-LLM).
v01.246.000חדשבוט תפעולי / מנוע התרחישיםminorתרחיש חדש: "לקוח מסרב לקבל" — גישור לשולח
נבנה תרחיש בוט חדש (ניתן להפעלה ב-/settings/bot-scenarios, כבוי כברירת מחדל): כששליח/קבלן מדווח בקבוצתו שהנמען מסרב לקבל את המשלוח, הבוט מודיע ללקוח העסקי ושואל כיצד להמשיך — להחזיר, לתאם מחדש או ליצור קשר — ומעביר את תש…
פרטים נוספים ↓הסתר ↑
נבנה תרחיש בוט חדש (ניתן להפעלה ב-/settings/bot-scenarios, כבוי כברירת מחדל): כששליח/קבלן מדווח בקבוצתו שהנמען מסרב לקבל את המשלוח, הבוט מודיע ללקוח העסקי ושואל כיצד להמשיך — להחזיר, לתאם מחדש או ליצור קשר — ומעביר את תשובת הלקוח חזרה לשליח. עד כה דיווח כזה ("לקוח מסרב לקבל") לא זוהה על ידי אף תרחיש והשולח מעולם לא עודכן. שונה מ"אין מענה" (שם הנמען לא נמצא) ומכשל מסירה (שסוגר את המשלוח): כאן הנמען נוכח ומסרב, ויש החלטה אמיתית לשולח. מבנית זהה לגישור "אין מענה", ללא אפשרות ההשארה ליד הדלת שאינה רלוונטית לסירוב פנים-אל-פנים.
- תרחיש רשום עם toggle, כבוי כברירת מחדל (opt-in per-tenant)
- מילות טריגר: "מסרב לקבל", "לא מעוניין", "לא רוצה לקבל", "טוען שלא הזמין" ועוד
- מגשר לשולח ומחזיר את הנחייתו לשליח; מכבד את כל הגנות הגישור הקיימות (זיהוי משלוח, ניתוק שיחה, פנייה בקבוצות בלבד)
v01.245.004תיקוןבוט תפעולי / מנוע התרחישיםשאלה "מה לאסוף" לא נענית בכתובת
קבלן שאל "26377358 מה לאסוף?" (איזה מוצר/פריט לקחת באיסוף), והבוט השיב בפרטי הכתובת של המשלוח — כלומר ענה "מאיפה" על שאלת "מה".
פרטים נוספים ↓הסתר ↑
קבלן שאל "26377358 מה לאסוף?" (איזה מוצר/פריט לקחת באיסוף), והבוט השיב בפרטי הכתובת של המשלוח — כלומר ענה "מאיפה" על שאלת "מה". תוכן המשלוח (המוצר) אינו קיים אצלנו במערכת ואי אפשר לגזור אותו מפרטי המשלוח. חודדה הגדרת תרחיש "פרטי משלוח" כך ששאלה על תוכן/מהות המשלוח (מה לאסוף, מה בחבילה, איזה מוצר, כמה פריטים) אינה מזוהה כבקשת פרטים — הבוט שותק והצוות משיב, במקום לתת תשובה מטעה.
v01.245.003ייעולביצועי ממשקסגירת סריקת-הביצועים: בוררי לקוחות ותפריט הפילטרים
השלמת הסריקה שנפתחה בעקבות התקיעה בחיפוש דוח עמלות הסוכן.
פרטים נוספים ↓הסתר ↑
השלמת הסריקה שנפתחה בעקבות התקיעה בחיפוש דוח עמלות הסוכן. נסרקו 93 שדות חיפוש במערכת, ואחרי אימות פרטני נמצאו שישה מקומות שסבלו מאותה תבנית — חיפוש שמסנן רשימה גדולה בזיכרון ומצייר מחדש את כל התוצאות בכל הקשה. הארבעה האחרונים נסגרו כאן: שלושת בוררי הלקוחות (קישור לקוח-בן, קישור ללקוח-אב, חיבור לסאמיט) ותפריט הפילטרים המשותף — שמשמש את מסכי המשלוחים, הלקוחות, השליחים והלידים, ושרשימת ה'עיר' שלו נבנית מאגרגציה על כל המשלוחים ויכולה להגיע למאות ערים. בכולם מוצגות מעתה עד 50 שורות עם כפתור 'הצג הכל', כך שההקלדה נשארת חלקה. בדיאלוג הסאמיט תוקן בנוסף חיפוש ריבועי: כל שורה ברשימה סרקה את כל לקוחות הדייר כדי לזהות כפילות מזהה — הוחלף באינדקס שנבנה פעם אחת. שאר המערכת נמצאה נקייה: הטבלאות הראשיות (משלוחים, לקוחות, שליחים, לידים) כבר עובדות עם עימוד בצד שרת או טבלה מווירטואלית.
v01.245.002שיפורצ'אט עסקי / סטטיסטיקותסטטיסטיקות הצ'אט העסקי סופרות רק הודעות שנשלחו על ידי העסק
משתמשים ציינו שספירת ההודעות הנכנסות מלקוחות אינה רלוונטית לניתוח העבודה — מה שמעניין הוא כמה הודעות אנחנו שולחים ומי שולח אותן.
פרטים נוספים ↓הסתר ↑
משתמשים ציינו שספירת ההודעות הנכנסות מלקוחות אינה רלוונטית לניתוח העבודה — מה שמעניין הוא כמה הודעות אנחנו שולחים ומי שולח אותן. כל הספירות בעמוד הסטטיסטיקות (סה"כ, גרף יומי, פילוח משתמשים, מפת חום, פילוח קהלים, צ'אטים עמוסים, וההשוואה לתקופה הקודמת) כוללות מעכשיו רק הודעות יוצאות — AI ואנשי צוות (מהמערכת, מוואטסאפ ומטלפון העסק) — והקטגוריה 'לקוחות (וואטסאפ)' הוסרה מהגרף ומהייצוא לאקסל. הודעות הלקוחות עדיין מזינות את מדדי האיכות שזקוקים להן כנקודת ייחוס: שיעור הכלה, זמן תגובה והודעות ממתינות למענה.
v01.245.001תיקוןסנכרון ספקים / ליונווילסנכרון הגיבוי מפסיק לחנוק את מכסת ה-API של ליונוויל
אחרי שהוגדל קצב סנכרון-הגיבוי (19/07), הדוח הנקי חשף שהריצות מייצרות יותר מאלף כשלי 429 ביום: ההנחה שקצב ליונוויל נשלט על ידי מספר הבקשות המקביליות הופרכה — המגבלה שלהם היא על נפח הבקשות.
פרטים נוספים ↓הסתר ↑
אחרי שהוגדל קצב סנכרון-הגיבוי (19/07), הדוח הנקי חשף שהריצות מייצרות יותר מאלף כשלי 429 ביום: ההנחה שקצב ליונוויל נשלט על ידי מספר הבקשות המקביליות הופרכה — המגבלה שלהם היא על נפח הבקשות. ריצה שנתקלת בקיר המשיכה לירות את כל ה-batch, שרפה את המכסה על ניסיונות אבודים וגזלה קיבולת גם מהפעולות האינטראקטיביות (יצירת משימות, דחיפות סטטוס). נוסף מפסק זרם לשני מסלולי הסנכרון (sync-recent ו-sync-open): אחרי חמישה כשלי 429 רצופים — כל אחד כבר אחרי ניסיון חוזר פנימי — הריצה נעצרת מיד, והריצה הבאה ממשיכה בדיוק מאותה נקודה (המיון לפי מועד סנכרון אחרון). כך הסנכרון שואב בקצב המרבי שליונוויל מרשה באותו רגע, בלי לנחש את המכסה ובלי לבזבז אותה, וגודל ה-batch נשאר תקרה לימים שבהם המכסה מרשה יותר.
v01.245.000חדשנוכחותminorהיסטוריית עריכות למשמרות נוכחות
כל פעולת ניהול על משמרת עובד מתועדת מעתה ביומן בלתי-נמחק: מי ביצע, מתי, ומה השתנה — כולל הערכים הישנים והחדשים של כל שדה.
פרטים נוספים ↓הסתר ↑
כל פעולת ניהול על משמרת עובד מתועדת מעתה ביומן בלתי-נמחק: מי ביצע, מתי, ומה השתנה — כולל הערכים הישנים והחדשים של כל שדה. התיעוד מכסה עריכת שעות והפסקות, הוספת משמרת ידנית, מחיקה, אישור, דחייה והחתמת כניסה/יציאה שבוצעה ע"י מנהל עבור עובד. ציר-זמן של ההיסטוריה מוצג בתוך דיאלוג עריכת המשמרת, עם תרגום השינויים לעברית (למשל: הפסקה: 0 דק' ← 30 דק'). שמירה ללא שינוי אמיתי לא יוצרת רשומה. הפיצ'ר נולד מאירוע שבו שעות של עובד נערכו בטעות ולא היה ניתן לשחזר מי עשה מה — מעתה זה תמיד ניתן לבירור.
- כל עריכה נרשמת עם מבצע, זמן, וערכים ישן←חדש לכל שדה
- מכוסה: עריכה, הוספה ידנית, מחיקה, אישור, דחייה, החתמות מנהל
- ציר-זמן בתוך דיאלוג עריכת המשמרת
- שמירה ללא שינוי לא מרעישה את ההיסטוריה
v01.244.000חדשצ'אט עסקיminorצ'אט עסקי — העברת כמה הודעות יחד, תגובת אימוג'י בלחיצה, הדבקת קבצים ומפרידי תאריך
ארבעה שיפורים בצ'אט הלקוחות העסקיים בעקבות משוב משתמשים.
פרטים נוספים ↓הסתר ↑
ארבעה שיפורים בצ'אט הלקוחות העסקיים בעקבות משוב משתמשים. (1) העברה מרובת הודעות: 'בחר הודעות' בתפריט ההודעה פותח מצב בחירה בסגנון וואטסאפ — מסמנים עד 30 הודעות ומעבירים את כולן יחד לצ'אטים אחרים, בסדר הכרונולוגי; סימון 'הודעות שהועברו' מופיע פעם אחת בראש הצרור ולא על כל הודעה. (2) תגובת אימוג'י בלחיצה אחת: סמיילי בריחוף על הודעה (ושורת אימוג'ים בתפריט לחיצה-ארוכה במובייל) שולח את האימוג'י כתגובת ציטוט להודעה — מה שעד היום דרש 'השב' והקלדה ידנית. הספק (Green API) אינו תומך בשליחת ריאקציה נטיבית, ולכן הלקוח רואה הודעת תשובה עם האימוג'י ולא בועית ריאקציה. (3) צירוף קובץ בהדבקה ובגרירה: Ctrl+V עם תמונה או קובץ בלוח (למשל צילום מסך) פותח את דיאלוג השליחה עם הקובץ טעון והטקסט שהוקלד הופך לכיתוב; אפשר גם לגרור קובץ לאזור השיחה. (4) מפרידי תאריך: צ'יפ 'היום' / 'אתמול' / תאריך מלא מופיע בין הודעות כשמתחלף יום, כמו בוואטסאפ — במקום רצף אחד ללא התמצאות בזמן; בנוסף, בזמן גלילה צפה בראש הצ'אט תווית עם התאריך של ההודעות הנראות כרגע, והיא נעלמת כשהגלילה נעצרת.
- מצב בחירה מרובה: עד 30 הודעות בהעברה אחת, נשלחות בסדר כרונולוגי לכל יעד
- סימון 'הודעות שהועברו' פעם אחת בראש הצרור, לא על כל הודעה
- תגובת אימוג'י מהירה בריחוף ובתפריט — נשלחת כתגובת ציטוט (לספק אין ריאקציות נטיביות)
- Ctrl+V מדביק תמונה/קובץ ישירות לשיחה; הטיוטה שהוקלדה הופכת לכיתוב
- גרירת קובץ לאזור השיחה פותחת את דיאלוג הצירוף
- מפרידי 'היום' / 'אתמול' / תאריך מלא בציר ההודעות
- תווית תאריך צפה בראש הצ'אט בזמן גלילה — נעלמת כשהגלילה נעצרת
v01.243.003שיפוראדמין / סנכרון ספקיםדוח משלוחים שגויים — שגיאות חולפות ישנות נסגרות מעצמן
דוח הסנכרון באדמין הצטבר לאלפי רשומות rate_limit/timeout ישנות שאיש לא יכול היה לעשות איתן דבר: שגיאה חולפת היא תיעוד של קריאת API בודדת שנכשלה, לא מצב פתוח — אבל שום מנגנון לא סגר אותה, ומכיוון שה-crons מסנכרנים רק משלו…
פרטים נוספים ↓הסתר ↑
דוח הסנכרון באדמין הצטבר לאלפי רשומות rate_limit/timeout ישנות שאיש לא יכול היה לעשות איתן דבר: שגיאה חולפת היא תיעוד של קריאת API בודדת שנכשלה, לא מצב פתוח — אבל שום מנגנון לא סגר אותה, ומכיוון שה-crons מסנכרנים רק משלוחים פתוחים וטריים, ישות ישנה לעולם לא מנוסה שוב והשורה ישבה בדוח לנצח. שלושה תיקונים: (1) סנכרון מוצלח של משלוח סוגר מעכשיו את כל שגיאות הסנכרון הפתוחות שלו — לא רק not_found — כי קריאה שהצליחה זה עתה מפריכה את כולן; (2) ה-cron הלילי מסמן כפגות-תוקף (auto_expired) שגיאות חולפות שניסיון הכשל שלהן ישן מ-14 יום; (3) הצבר הקיים נוקה — 5,683 שורות ישנות נסגרו. שגיאות not_found (זרימת המחיקה האוטומטית) ו-forbidden (בעיית הרשאות שדורשת עין אנושית) לא נכללות בתפוגה. הדוח מציג מעכשיו רק כשלים עדכניים שאפשר לפעול לגביהם.
v01.243.002שיפורבוט WhatsApp / צ'אט לקוחות קצהתלונת מסירה מנותבת לפי אשמה: כתובת לא-מעודכנת הולכת לשולח, לא לשליח
המקרה החי הראשון של דיווח-תלונה-לשליח חשף פער ניתוב: הלקוח התלונן שהמשלוח נמסר לכתובת הישנה — אבל השליח מסר בדיוק לכתובת שרשומה על המשלוח; האשם האמיתי הוא רשומות השולח, שממשיך להוציא הזמנות לכתובת שהנמען כבר ביקש לעדכן.
פרטים נוספים ↓הסתר ↑
המקרה החי הראשון של דיווח-תלונה-לשליח חשף פער ניתוב: הלקוח התלונן שהמשלוח נמסר לכתובת הישנה — אבל השליח מסר בדיוק לכתובת שרשומה על המשלוח; האשם האמיתי הוא רשומות השולח, שממשיך להוציא הזמנות לכתובת שהנמען כבר ביקש לעדכן. הבוט מבצע כעת טריאז' אשמה לפני הדיווח: תלונת התנהלות/נזק של השליח (הונח במקום שגוי, ללא תיאום, נזק) ממשיכה לקבוצת השליח כולל התמונות; תלונת כתובת-לא-מעודכנת נשלחת דווקא לקבוצת הלקוח השולח — 📍 בקשה לעדכן את הכתובת ברשומותיו להזמנות הבאות, כולל הכתובת הנכונה כשהנמען מסר אותה. תבנית ההודעה לשולח ניתנת לעריכה בדף תרחישי הבוט, תחת אותו טוגל של תלונות המסירה. כשלא ברור מי אשם — הבוט לא מדווח לאף אחד והנציג מכריע.
v01.243.001תיקוןבוט WhatsApp / צ'אט לקוחות קצהדיווח תלונה/ביטול לא נשלח שוב לקבוצה אחרי שנציג סימן 'טופל'
ביקורת על 18 השעות הראשונות של תרחישי עדכון-השולח/שליח חשפה שתלונת מסירה אחת דווחה שלוש פעמים לקבוצת השליח: נציג סימן את השיחה 'טופל' בין הודעות הלקוח, היפוך הסטטוס איפס את מנגנון מניעת-הכפילויות, וכל הודעת המשך של הלקוח…
פרטים נוספים ↓הסתר ↑
ביקורת על 18 השעות הראשונות של תרחישי עדכון-השולח/שליח חשפה שתלונת מסירה אחת דווחה שלוש פעמים לקבוצת השליח: נציג סימן את השיחה 'טופל' בין הודעות הלקוח, היפוך הסטטוס איפס את מנגנון מניעת-הכפילויות, וכל הודעת המשך של הלקוח פתחה דיווח חדש. המנגנון בודק כעת את הערת ה-AI של השיחה בלבד, ללא תלות בסטטוס הטיפול — פנייה חוזרת באותו נושא מקבלת הערה 'הנמען חזר על הפנייה' במקום הודעה נוספת לקבוצה.
v01.243.000חדשאינטגרציות / חנויותminorקונימבו — שידור יזום דרך כפתור 'שדר משלוח', עם זיהוי לפי טוקן ודיווח חזרה
בתיאום עם קונימבו מומש 'שדר משלוח' — הלקוח לוחץ על הכפתור בהזמנה, וקונימבו דוחפת אותה לשיפנסט מיד, במקום משיכה אוטומטית.
פרטים נוספים ↓הסתר ↑
בתיאום עם קונימבו מומש 'שדר משלוח' — הלקוח לוחץ על הכפתור בהזמנה, וקונימבו דוחפת אותה לשיפנסט מיד, במקום משיכה אוטומטית. בניגוד לאישופ (endpoint פר-חנות), קונימבו שולחת את כל הלקוחות של כל הטננטים ל-endpoint גלובלי אחד, והזיהוי אצלנו נעשה לפי טוקן: לכל חיבור מונפק טוקן שהלקוח מעתיק להגדרות חברת השילוח בקונימבו. הטוקן נשמר מוצפן (להצגה חוזרת ללקוח) וה-SHA-256 שלו נשמר בעמודה מאונדקסת לחיפוש O(1) בקבלת ה-webhook (אותה גישה כמו מפתחות ה-API שלנו). ה-endpoint הגלובלי מזהה את החנות מהטוקן (מקבל אותו מ-header/query/body — גמיש, כי קונימבו טרם סגרו את התחבורה). הדחיפה נושאת רק את מספר ההזמנה, ולכן אנחנו מושכים את נתוני ההזמנה המלאים ב-GET /v1/orders/{id} עם הטוקן של החנות לפני היצירה, יוצרים משלוח ומשדרים לליונוויל, ואז מעדכנים את ההזמנה בקונימבו בחזרה: בהצלחה — סטטוס עם מספר המשלוח (מה שהלקוח רואה בממשק); בכישלון — סטטוס עם הסיבה. בפורטל נוסף לכרטיס חנות הקונימבו בלוק עם כתובת ה-Webhook והטוקן להעתקה, וכפתור 'צור טוקן / החלף טוקן'. השידור אידמפוטנטי (דדופ לפי מספר הזמנה) כך שדחיפה כפולה לא יוצרת משלוח כפול; המענה תמיד 200 אחרי אימות, כדי שלא ייווצר ניסיון חוזר.
- כפתור 'שדר משלוח' בקונימבו דוחף רק את מספר ההזמנה; שיפנסט מושכת את הנתונים המלאים ב-GET לפני היצירה
- endpoint גלובלי אחד לכל שיפנסט; זיהוי החנות לפי טוקן (SHA-256 מאונדקס לחיפוש מהיר)
- טוקן פר-לקוח, מוצפן להצגה חוזרת בפורטל עם כתובת ה-Webhook להעתקה
- דיווח חזרה להזמנה: הצלחה עם מספר המשלוח, כישלון עם הסיבה
- קונימבו שולחת token ו-order_id ב-query string (בלי headers מותאמים); ה-endpoint מקבל GET וגם POST
- אידמפוטנטי — דחיפה כפולה לא יוצרת משלוח כפול; מענה 200 מונע ניסיון חוזר
v01.242.000תיקוןאינטגרציות / חנויותminorקונימבו — שידור הזמנות לליונוויל, ותיקון '404 = אין הזמנות' שסימן חנות תקינה ככושלת
חיבור חנות קונימבו אמיתית ראשונה חשף שני פערים.
פרטים נוספים ↓הסתר ↑
חיבור חנות קונימבו אמיתית ראשונה חשף שני פערים. (1) ייבוא ההזמנות מקונימבו יצר שורות מקומיות מתות עם ברקוד מזויף (KN-...) בלי שידור לליונוויל — בדיוק כמו הבאג שתוקן באישופ. כעת הייבוא עובר דרך הצינור המשותף של יצירת משלוח (createShipmentForTenant): שידור אמיתי לליונוויל, ברקוד אמיתי, פריטים, ודדופ אטומי (claim row) כמו ב-WooCommerce ואישופ. סנכרון המסירה חזרה לקונימבו נשמר. (2) קונימבו מחזירה HTTP 404 עם {status:not_found, message:'There are no orders for your query'} כשאין הזמנות חדשות — תשובת רשימה ריקה תקינה — אבל הקוד התייחס אליה ככישלון חיבור: כל מחזור סנכרון בלי הזמנה חדשה נרשם כשגיאה, צבר consecutiveFailures, שלח התראת מנהל, ובסוף היה משתיק את החנות ב-backoff. מכיוון שברוב חלונות ה-5 דקות אין הזמנה חדשה, חנות בריאה לחלוטין הייתה נראית שבורה. כעת listOrders מזהה את ה-404 הזה ומחזיר רשימה ריקה, בעוד 401/403/500 עדיין נזרקים כשגיאה אמיתית. בנוסף נוסף route אבחון פנימי (platform-only) לשליפת הזמנת קונימבו בודדת לפי מזהה (עוקף את חלון הסנכרון) לצורך בדיקה מקצה-לקצה.
- הזמנות קונימבו משודרות לליונוויל עם ברקוד אמיתי ופריטים — לא עוד שורות מקומיות מתות
- דדופ אטומי מונע יצירת שתי משימות ליונוויל לאותה הזמנה
- תוקן: '404 אין הזמנות' של קונימבו טופל ככישלון חיבור — סימן חנות תקינה ככושלת והשתיק אותה
- 401/403/500 עדיין מזוהים כשגיאות אמת
v01.241.001תיקוןבוט תפעולי / מנוע התרחישיםטענת אי-מסירה עם כמה משלוחים בהודעה אחת — פתק לצוות במקום פנייה למשלוח שגוי
לקוח כתב בהודעה אחת שתי טענות אי-מסירה על שני משלוחים שונים ("25691330 ...
פרטים נוספים ↓הסתר ↑
לקוח כתב בהודעה אחת שתי טענות אי-מסירה על שני משלוחים שונים ("25691330 ... לא קיבל ... 25981856 כתוב בוצע ולקוחה לא קיבלה כלום"). תרחיש טענת אי-מסירה לקח את המספר הראשון, פנה לנמען שלו בבקשת אישור, ובשקט השמיט את הטענה השנייה — כלומר פנה לנמען הלא-נכון על משלוח שהתלונה עליו הייתה של לקוח אחר. כעת, כשההודעה מזכירה יותר ממשלוח אחד בבירור, הבוט אינו מנחש על מי לפעול אלא פותח פתק לצוות עם ההודעה המלאה, כך שהצוות מטפל בשתי הטענות. משלוח יחיד (או משלוח שצוטט) עדיין מריץ את הזרימה המלאה. פנייה אוטומטית לנמען היא צעד רגיש, ולכן בכל עמימות עדיף פתק לצוות על פני ניחוש.
v01.241.000חדשבוט תפעולי / מנוע התרחישיםminorכשל מסירה חכם: הלקוח מעודכן רק כשזה באמת נוגע אליו + תרחיש חדש למשלוח ניזוק
עד היום כל דיווח כשל מסירה מהשליח עדכן את הלקוח העסקי — כולל כשלים פנימיים שלנו: משלוח שהגיע לשליח בטעות מיון או שאינו באזור ההפצה שלו.
פרטים נוספים ↓הסתר ↑
עד היום כל דיווח כשל מסירה מהשליח עדכן את הלקוח העסקי — כולל כשלים פנימיים שלנו: משלוח שהגיע לשליח בטעות מיון או שאינו באזור ההפצה שלו. לעדכן שולח ש"המשלוח לא נמסר" על טעות מיון שלנו זה גם שגוי (המשלוח פשוט ינותב מחדש) וגם מביך. כעת הדיווח עובר טריאז' לפני שמישהו מעודכן: כשל בצד השולח או הנמען (אין מענה, סירוב, כתובת שגויה) — הלקוח מעודכן עם הסיבה כרגיל; כשל פנימי (טעות מיון, מחוץ לאזור — מזוהה גם במילות מפתח דטרמיניסטיות וגם ב-AI) — נרשם פתק לצוות השירות בלבד והלקוח אינו מעודכן; וכשהסיבה לא ברורה — הבוט שואל את השליח בקבוצה "מה הסיבה?" ופועל לפי התשובה, כשבכל ספק ברירת המחדל היא פתק לצוות בלי לעדכן את הלקוח. גם שליח שלא ענה לשאלה בכלל לא נעלם: אחרי שש שעות נרשם פתק לצוות שהסיבה לא נמסרה. בנוסף נולד תרחיש חדש — "משלוח ניזוק": שליח שמדווח שמשלוח נשבר / נפגם / דולף / נקרע וחוזר, מפעיל עדכון לשולח עם תיאור ענייני של הנזק (מנוסח ללא האשמות וללא מידע פנימי) והודעה שהמשלוח מוחזר אליו.
- כשל פנימי (טעות מיון / לא באזור ההפצה) כבר לא מדווח לשולח — נרשם פתק לצוות בלבד
- סיבת כשל לא ברורה? הבוט שואל את השליח בקבוצה ומחליט לפי התשובה — בספק, פתק לצוות
- שליח שלא ענה לשאלת הסיבה — פתק אוטומטי לצוות אחרי שש שעות, שום כשל לא נעלם בשקט
- תרחיש חדש "משלוח ניזוק": דיווח נשבר/נפגם/דולף מעדכן את השולח שהמשלוח ניזוק וחוזר אליו
v01.240.002שיפורבוט תפעולי / מנוע התרחישיםצילום מדבקה מציג את מספר המשלוח שלנו, ושידור מרובה עלה ל-16 בבת אחת
שני שיפורים בתרחיש השידור.
פרטים נוספים ↓הסתר ↑
שני שיפורים בתרחיש השידור. (1) מדבקת משלוח נושאת גם את הברקוד שלנו וגם את המזהה שאנחנו משדרים אליו אצל הקבלן, וה-OCR קרא לעיתים את המזהה הזר — הקבוצה ראתה "מספר שזוהה: 2236987", מספר שלא אומר כלום לצוות. הזיהוי עצמו תמיד היה תקין (שני המספרים מובילים לאותו משלוח), אבל התצוגה בלבלה. כעת, כשהמערכת מאשרת שהמספר שנקרא הוא כינוי של אותו משלוח, מוצג הברקוד שלנו. קריאה שגויה באמת אינה נפתרת לכלום ונשארת כפי שנסרקה — אין כאן "תיקון" של OCR. (2) שידור מרובה בהודעה אחת הועלה מ-8 ל-16 משלוחים. קבלן שהדביק כ-35 ברקודים נאלץ לשלוח את היתרה ארבע פעמים. נמדד מהאירוע: 8 משלוחים ארכו כ-40 שניות, כ-5 שניות למשלוח, בעוד העבודה רצה ברקע אחרי שה-webhook כבר ענה — ולכן תקציב הריצה נקבע מפורשות ל-300 שניות ו-16 משלוחים (כ-80 שניות) יושבים בתוכו בהפרש גדול. לא הועלה יותר בכוונה: מגבלה גלויה שמסבירה את עצמה עדיפה על timeout שקט באמצע שידור, שבו חלק מהמשלוחים משודרים ואין תשובה כלל.
v01.240.001תיקוןבוט תפעולי / מנוע התרחישיםתשובה קצרה לא נתלשת משיחה אחרת, ותשובת השליח מנוסחת ללקוח
שני תיקונים בהעברת תשובות.
פרטים נוספים ↓הסתר ↑
שני תיקונים בהעברת תשובות. (1) מילה בודדת ("בערב") נשלפה מתוך שיחה תפעולית חיה על איסוף בכתובת אחרת, ושויכה לבירור בן ארבע שעות על משלוח אחר לגמרי — השליח קיבל אותה כהנחיית השולח, בעוד ההודעה הבאה של הלקוח הייתה "בערב יהיה מאוחר". נבדק שסף זמן אינו פתרון: מדידה על 30 יום מראה ש-38% מהתשובות האמיתיות מגיעות אחרי שעתיים ו-25% אחרי ארבע שעות. לעומת זאת, מידת ההתקדמות של השיחה כן מפרידה — התשובה הקצרה הלגיטימית הרועשת ביותר הגיעה אחרי 11 הודעות ביניים, והשגויה אחרי 22. כעת תשובה קצרה מאוד שאינה מצטטת את השאלה ואינה מזכירה משלוח נפסלת כשהשיחה כבר התקדמה, ונשארת פתוחה לתשובה אמיתית. (2) תשובת השליח על צפי מסירה מועברת ללקוח בניסוח מסונן במקום כלשונה — שליח עונה לסדרן, לא ללקוח, ו-"היום, היום. הכל היום." יצא כצפי הרשמי. אותו מנגנון ניסוח שכבר משמש בתיאום מועד; אם לא נשאר תוכן בטוח, הטקסט המקורי עדיין עובר — צפי לא מלוטש עדיף על שתיקה.
v01.240.000חדשבוט WhatsApp / צ'אט לקוחות קצהminorלבוט יש עיניים — תמונות מלקוחות מנותחות במקום להסלים אוטומטית
עד היום הבוט של צ'אט לקוחות הקצה היה עיוור לתמונות: כל תמונה בלי הקשר חיובי מובהק גררה הסלמה שקטה לנציג — גם כשלקוחה שלחה צילום של השער שלה לצד 'נא להתקשר כדי שאפתח את השער' (מקרה אמת מהיום, משלוח 26352138).
פרטים נוספים ↓הסתר ↑
עד היום הבוט של צ'אט לקוחות הקצה היה עיוור לתמונות: כל תמונה בלי הקשר חיובי מובהק גררה הסלמה שקטה לנציג — גם כשלקוחה שלחה צילום של השער שלה לצד 'נא להתקשר כדי שאפתח את השער' (מקרה אמת מהיום, משלוח 26352138). מעתה התמונות עצמן (עד 2 מהרצף האחרון) יורדות ממטא ומצורפות לבקשת הסיווג — הבוט רואה אותן: צילום הקשר (שער, דלת, בניין) מטופל כעזרה — ההוראה נרשמת לשליח כולל פרט ויזואלי מועיל ('שער חום כפול'), והלקוח מקבל תשובה; צילום של בעיה (חבילה פגומה, מוצר שגוי) מוסלם עם תיאור מדויק של מה שנראה; צילומי מסך נקראים כטקסט. עובד בכל שלושת ספקי ה-AI (Anthropic, Gemini, תואם-OpenAI). רשת ביטחון כפולה: כשל בהורדת תמונה מחזיר את הבוט לכללי העיוורון הזהירים, וגם שם רוככה ההתנהגות — הוראת מסירה טקסטואלית ברורה לצד תמונה שלא נבדקה מטופלת כרגיל עם הערה 'צורפה תמונה שלא נבדקה', במקום להעניש את הלקוח בשתיקה על צירוף תמונה מועילה.
- תמונות מהרצף האחרון (עד 2) מצורפות לסיווג — הבוט רואה ושופט אותן בעצמו
- צילום הקשר (שער/דלת/בניין) = עזרה: ההוראה נרשמת לשליח עם הפרט הוויזואלי, והלקוח נענה
- צילום בעיה (נזק/מוצר שגוי) = הסלמה עם תיאור מדויק של הנראה בתמונה
- כשל הורדה → נסיגה לכללים העיוורים, שרוככו: טקסט ברור + תמונה לא-נבדקת מטופל, לא מושתק
- בהמשך היום: תרחיש 'בקשת ביטול מהנמען — עדכון השולח' (הגדרות ← תרחישי בוט) — השולח מקבל שאלה לפי שלב המשלוח: טרם נאסף = 'ניתן לבטל, לאשר?'; כבר נאסף = 'לא ניתן לבטל — עצירה/החזרה?'; ההסלמה לנציג נשארת תמיד, והביטול בפועל לעולם לא אוטומטי
- תרחיש 'תלונת מסירה/נזק — דיווח לשליח': תלונה על משלוח שנמסר (הונח במקום שגוי / נזק) מדווחת אוטומטית לקבוצת השליח המשובץ — כולל העברת התמונות שהנמען צירף ככיתוב על הדיווח; רק בסטטוס נמסר/הושלם, רק לקבוצה מקושרת, וההסלמה לנציג נשארת
v01.239.006תיקוןמשלוחים / פערי הפצהמשלוח שנמסר לא יוצג עוד כ'מעוכב' — בעמוד המשלוח ובפערי ההפצה
משלוח שנמסר בזמן הוצג בפאנל 'סטטוס צ'קליסט / עיכוב' כ'מעוכב 6 ימי עסקים', והופיע גם בטבלת פערי ההפצה.
פרטים נוספים ↓הסתר ↑
משלוח שנמסר בזמן הוצג בפאנל 'סטטוס צ'קליסט / עיכוב' כ'מעוכב 6 ימי עסקים', והופיע גם בטבלת פערי ההפצה. שתי סיבות נפרדות: (1) הפאנל בעמוד המשלוח חישב עיכוב משעון פערי-ההפצה בלי לבדוק שהמשלוח עדיין פתוח — השעון הוא sticky בכוונה, ולכן כל משלוח שנמסר 'צבר עיכוב' לנצח; מעתה החישוב מגודר לסטטוסי הפצה פתוחים, כמו בשאר המסכים. (2) בפערי ההפצה הסינון לפי סטטוס דווקא עבד — אבל הנתון עצמו היה שגוי: לפני תיקון ה-OCC מ-17/07, שני webhooks מקבילים ברגע המסירה יכלו לדרוס בשקט את סטטוס 'הושלם' חזרה ל'יצא להפצה' (בלי שום רישום), וגם אחרי התיקון — הד ישן מליונוויל שהגיע יותר מ-15 דקות אחרי המסירה (נצפו 56 דקות ואף 4 ימים) עקף את מגן הרגרסיה, פתח מחדש משלוחים שנמסרו ואף שלח ללקוח הודעת 'יצא להפצה' באיחור. המגן הורחב: כשביקור המסירה שלנו כבר הושלם בפועל, שום סטטוס לא-טרמינלי נכנס לא פותח מחדש את המשלוח, בלי תלות בחלון הזמן. בנוסף רוצף כל המצאי ההיסטורי: 18 משלוחים שנמסרו אך נשארו תקועים בסטטוס פתוח (חלקם מאז יולי 2025) אומתו אחד-אחד מול ליונוויל ותוקנו ל'הושלם' עם רישום מלא ביומן הפעילות.
v01.239.005תיקוןבוט תפעולי / מנוע התרחישיםפנייה ללקוח שלא נמסרה — הצוות מקבל התראה במקום שתיקה
שליח דיווח על בעיה, הבוט פנה ללקוח, ההודעה ללקוח לא נמסרה — והשליח נשאר בלי מענה.
פרטים נוספים ↓הסתר ↑
שליח דיווח על בעיה, הבוט פנה ללקוח, ההודעה ללקוח לא נמסרה — והשליח נשאר בלי מענה. הבוט פעל נכון: הוא מדכא את האישור "מברר מול הלקוח" כשהשאלה לא הגיעה ליעדה, כדי לא להבטיח בירור שלא קרה. אבל התוצאה הייתה מבוי סתום שקט שאיש לא ידע עליו. כעת נכתב פתק לצוות בשרשור של השליח, המסביר שההודעה לא נמסרה (ככל הנראה מספר שאינו WhatsApp) ושהשליח ממתין למענה. בנוסף — הבוט מפסיק לנסות לשלוח למספרים שאינם ניידים: קו משרדי (02/03/04/08/09) או VoIP (077/078) אינם יכולים לקבל WhatsApp, ומתוך 440 לקוחות פעילים ל-23 מספר כזה הוא היעד היחיד. במקום שליחה שנדונה מראש לכישלון, הפנייה עוברת ישירות לטיפול הצוות.
v01.239.004תיקוןמשלוחים / אינטגרציית ליונווילהסרת שליח מדף המשלוח מתעדכנת גם בליונוויל
כשהסירו שיבוץ של שליח או קבלן מתוך דף פרטי המשלוח (וגם ממסך האיסופים), ההסרה נשמרה רק אצלנו — בליונוויל המשימה נשארה משובצת לשליח הקודם.
פרטים נוספים ↓הסתר ↑
כשהסירו שיבוץ של שליח או קבלן מתוך דף פרטי המשלוח (וגם ממסך האיסופים), ההסרה נשמרה רק אצלנו — בליונוויל המשימה נשארה משובצת לשליח הקודם. הסיבה: בקוד עדכון המשימה, הבלוק ששולח את ההסרה לליונוויל ישב בתוך ענף השיבוץ — ענף שרץ רק כשבוחרים שליח חדש — ולכן בפועל מעולם לא הופעל. הסרה דרך בורר השליחים ברשימת המשלוחים דווקא כן סונכרנה, ומכאן התחושה שזה עובד 'לפעמים'. מעתה כל הסרת שיבוץ שולחת לליונוויל את ניקוי השליח מהמשימה, בדיוק כמו במסלול ההמוני.
v01.239.003תיקוןמשלוחיםציר הזמן בעמוד המשלוח — 'קליטה' מציגה את הקליטה למחסן באמת
שורת 'קליטה' בציר הזמן של עמוד המשלוח הוצגה מתוך שדה שעון פערי-ההפצה, שנחתם כבר במעבר הראשון לסטטוס פעיל — כלומר ברגע האיסוף מבית העסק.
פרטים נוספים ↓הסתר ↑
שורת 'קליטה' בציר הזמן של עמוד המשלוח הוצגה מתוך שדה שעון פערי-ההפצה, שנחתם כבר במעבר הראשון לסטטוס פעיל — כלומר ברגע האיסוף מבית העסק. משלוח שנאסף ונסרק למחסן רק כעבור כמה ימים הציג 'קליטה' עם תאריך האיסוף, זהה לשורת 'איסוף' שמעליה, במקום מועד הסריקה בפועל. מעתה השורה קוראת את תאריך הקליטה למחסן האמיתי (inInventoryAt), ומשלוח שטרם נקלט פשוט לא מציג שורת קליטה. עמודת 'תאריך קליטה מלקוח' בטבלת המשלוחים לא השתנתה — שם השדה הישן מוצג בכוונה ותחת שם מדויק.
v01.239.002תיקוןמשלוחים / אינטגרציית ליונווילמשימות איסוף נולדות מתויגות כ'איסוף' גם בליונוויל
כששיבצנו איסוף על קבלן הפצה, שיגור המשימה אליו בליונוויל התייחס אליה כמשלוח רגיל — כתובת היעד מופתה אצל הקבלן ככתובת האיסוף, וכדי שהכתובות יגיעו נכון היה צריך לבחור ידנית 'איסוף' בדיאלוג השיגור.
פרטים נוספים ↓הסתר ↑
כששיבצנו איסוף על קבלן הפצה, שיגור המשימה אליו בליונוויל התייחס אליה כמשלוח רגיל — כתובת היעד מופתה אצל הקבלן ככתובת האיסוף, וכדי שהכתובות יגיעו נכון היה צריך לבחור ידנית 'איסוף' בדיאלוג השיגור. הסיבה: משימת איסוף שנוצרה מהמערכת נולדה בליונוויל ללא סוג (task_type) — השדה נשמר עד היום רק אצלנו ולא נשלח אליהם. מעתה כל יצירת משלוח שולחת את הסוג לליונוויל, כך שאיסופים מתויגים כ'איסוף' מרגע היצירה — מה שאמור ליישר גם את ברירת המחדל של שיגור לקבלן. הסוג נקבע אך ורק ברגע היצירה; משימות קיימות אי אפשר לתקן בדיעבד, ושם הבחירה הידנית בדיאלוג נשארת.
v01.239.001ייעולפורטל לקוחותדשבורד הפורטל — 21 שאילתות במקביל הפכו לחמש
כל כניסה של לקוח לדשבורד ירתה 21 שאילתות בבת אחת: ספירה נפרדת לכל אחד מ-12 קודי הסטטוס, ועוד שבע ספירות סיכום.
פרטים נוספים ↓הסתר ↑
כל כניסה של לקוח לדשבורד ירתה 21 שאילתות בבת אחת: ספירה נפרדת לכל אחד מ-12 קודי הסטטוס, ועוד שבע ספירות סיכום. ההנמקה שנרשמה בקוד הייתה ש'זמן התגובה נקבע לפי השאילתה האיטית ביותר, לא לפי מספרן' — נכון לגבי זמן תגובה, אבל לא לגבי מאגר החיבורים, שגודלו 10. כלומר טעינה אחת ביקשה בערך פי שניים מכל המאגר, ובכניסות מקבילות של כמה לקוחות זה מפסיק להיות דף איטי והופך לשגיאת timeout על המאגר — אותו כשל שנרשם ב-02/07. כל הספירות האלה מסננות ממילא את אותה עמודת סטטוס, ולכן GROUP BY אחד מחזיר את כולן: הדשבורד ירד ל-5 שאילתות. המספרים זהים לחלוטין, כולל שורות עם סטטוס ריק או לא מוכר שממשיכות להיספר תחת 'לא ידוע', והפילוח לפי קוד בפאנל הצדדי נשאר כשהיה. הלוגיקה חולצה לפונקציה משותפת עם בדיקות שמקבעות את השקילות.
v01.239.000שיפורתשתית / ניטורminorמסלול ששבור באמת יצעק — והתראות הרעש נשארות שקטות
תקלת הבוקר חשפה נקודה עיוורת: ה-webhook של Green API החזיר 500 כל דקה במשך כעשר שעות ואיש לא קיבל התראה, בעוד שטיימאאוטים חולפים של ספקים חיצוניים כן צלצלו — בדיוק הפוך מהרצוי.
פרטים נוספים ↓הסתר ↑
תקלת הבוקר חשפה נקודה עיוורת: ה-webhook של Green API החזיר 500 כל דקה במשך כעשר שעות ואיש לא קיבל התראה, בעוד שטיימאאוטים חולפים של ספקים חיצוניים כן צלצלו — בדיוק הפוך מהרצוי. הסיבה: כל 500 לא-מטופל הועבר ללוגר עם notifyAdmin=false, בכוונה, כדי לא לשלוח WhatsApp על כל שגיאה בודדת. השיקול נכון, אבל 'לעולם לא להתריע' הפך מסלול ששבור ברציפות לבלתי-נראה. נוסף מונה כשלים פר-מסלול בחלון מתגלגל: שגיאה בודדת או שתיים לא מייצרות רעש, אבל מסלול שנכשל שוב ושוב מייצר התראה אחת — ואז שותק לשעה כדי לא להציף. הספירה ב-Redis (אותו חיבור של מגביל הקצב), כך שהסף גלובלי ולא נספר בנפרד בכל instance; בלי Redis יש נפילה חיננית לזיכרון. במקביל, שליפת המשלוח מליונוויל מקבלת ניסיון חוזר אחד — רק ל-GET, לעולם לא ל-POST/PUT, כדי שניסיון חוזר לא ייצור משלוח כפול — ותקרת הזמן של ה-webhook הועלתה כך שהשלבים המאוחרים לא ייקטעו בשקט באמצע.
- התראה על מסלול שנכשל ברציפות, במקום שקט מוחלט על 500 לא-מטופל
- שגיאה בודדת או שתיים לא מייצרות התראה — רק כשל מתמשך חוצה את הסף
- התראה אחת למסלול לשעה, כך שתקלה מתמשכת לא מציפה את הטלפון
- הספירה ב-Redis ולכן גלובלית לכל ה-instances; בלי Redis נפילה חיננית לזיכרון
- ניסיון חוזר לשליפת משלוח מליונוויל — רק לקריאות GET, לעולם לא ליצירה או לעדכון סטטוס
- תקרת הזמן של webhook ליונוויל הועלתה, כדי ששלבים מאוחרים לא ייקטעו בשקט
v01.238.000שיפורמשלוחים / סטטוסיםminorאוצר המילים של הסטטוסים עבר לשמות עצמאיים
שני סטטוסים נשאו את השמות שהגיעו מאוצר המילים של המוביל ושימשו כזהות הקנונית שלנו: ROUNDTRIP_DELIVERED ו-FINAL_FAILED.
פרטים נוספים ↓הסתר ↑
שני סטטוסים נשאו את השמות שהגיעו מאוצר המילים של המוביל ושימשו כזהות הקנונית שלנו: ROUNDTRIP_DELIVERED ו-FINAL_FAILED. הם הוחלפו ב-DELIVERED_PENDING_RETURN ו-UNDELIVERABLE — שמות שגם מתארים מדויק יותר מה קורה בפועל. שאר תשעת הסטטוסים לא נגעו: שישה מהם מונחים לוגיסטיים גנריים שקיימים בכל מערכת בעולם, ושלושה (סטטוסי המחסן) הם ממילא הרחבה של Shipnest. השינוי לא דרש מיגרציית נתונים ולא שבר אף מנוי webhook.
- אין מיגרציית נתונים — שורות קיימות שמחזיקות את הטוקן הישן ממשיכות להתנרמל דרך LEGACY_STATUS_ALIASES, ו-rawStatusValues מוסיף אותו לפילטרי SQL כך שהן עדיין נתפסות
- ה-webhook shipment.status_changed ממשיך לשלוח את הערכים הישנים דרך toOutboundStatus — מנויים קיימים לא מושפעים, וההחלפה תגיע בגרסת API הבאה עם הודעה מראש
- תוקן באג שהתגלה תוך כדי: עמוד המעקב הציבורי החזיק עותק כפול של טבלת הסטטוסים, שהיה מציג כל משלוח עם טוקן ישן כ'משלוח חדש'. הוחלף בייבוא מהמקור המשותף
- נוספו 7 טסטים שמצמידים את שלושת מנגנוני התאימות
v01.237.002תיקוןאבטחה / אינטגרציותהסרת מפתח API מקומפל בקוד והשבתת סקריפטי הבדיקה מול ליונוויל
מפתח API של פרודקשן לליונוויל היה כתוב במפורש בארבעה סקריפטים מאז ה-3 ביוני.
פרטים נוספים ↓הסתר ↑
מפתח API של פרודקשן לליונוויל היה כתוב במפורש בארבעה סקריפטים מאז ה-3 ביוני. המפתח הוחלף בקריאה ל-LIONWHEEL_API_KEY מהסביבה, ושלושת סקריפטי ה-probe (בדיקת שדות שיטתית ומנייה של endpoints לא מתועדים) הושבתו בחסימה קשיחה — ליונוויל עדכנה את תנאי השימוש שלה ב-20 ביולי, ונספח א' סעיף 7.2 אוסר במפורש על enumeration ו-probing. הקבצים נשמרו כרישום היסטורי ולא נמחקו. נוסף מסמך docs/development-chronology.md המתעד את סדר בניית המערכת מתוך היסטוריית ה-git. בהמשך היום נוקה גם התיעוד הציבורי: הוסרו טבלת קודי הסטטוס המספריים של ליונוויל ורשימת מגבלות ה-API שלהם, והוחלפו בתיאור התנהגות הסנכרון מצד Shipnest. בנוסף, כל שימוש במפתח הגלובלי המשותף נרשם עכשיו ללוג פעם אחת לכל call site, ומשתנה הסביבה LIONWHEEL_REQUIRE_TENANT_KEY מאפשר להפוך אותו לשגיאה קשיחה אחרי שכל הטננטים יוגדרו. לבסוף נוסף ל-pre-commit hook סורק credentials שחוסם commit שמוסיף מפתח או token בקוד — נבדק מול 60 הcommits האחרונים ללא התראות שווא. הרוטציה עצמה חסומה: בממשק של ליונוויל אין אפשרות להנפיק מפתח מחדש, כך שהמפתח הישן נשאר תקף עד שתטופל פנייה לתמיכה שלהם.
v01.237.001תיקוןתשתית / מסד נתוניםה-webhook של Green API חזר לפעול — הודעות WhatsApp נכנסות שוב
רוטציית ה-secrets של אינטגרציית Prisma-Vercel העבירה הבוקר את כתובת ה-Accelerate למשתנה DATABASE_PRISMA_DATABASE_URL, בעוד DATABASE_URL נדרס לכתובת postgres:// ישירה.
פרטים נוספים ↓הסתר ↑
רוטציית ה-secrets של אינטגרציית Prisma-Vercel העבירה הבוקר את כתובת ה-Accelerate למשתנה DATABASE_PRISMA_DATABASE_URL, בעוד DATABASE_URL נדרס לכתובת postgres:// ישירה. התיקון הקודם עדכן את בניית ה-client כך שיעדיף את המשתנה החדש, אבל ההחלטה האם להחיל את הרחבת Accelerate המשיכה לקרוא את DATABASE_URL הגולמי בלבד — כך שה-client דיבר דרך Accelerate בלי ההרחבה שלו. התוצאה: כל שאילתה עם cacheStrategy נזרקה עם 'Unknown argument cacheStrategy', ובראשן שליפת ה-webhookSecret הפר-tenant — מה שהחזיר 500 על כל קריאה ל-webhook של Green API, אחת לדקה, וחסם כל הודעת WhatsApp נכנסת (ה-inbox, הבוט ומנוע התרחישים). שתי ההחלטות נגזרות עכשיו ממקור אמת יחיד, ונוסף טסט רגרסיה שמכסה בדיוק את הצירוף הזה.
v01.237.000חדשמשלוחים / בוט WhatsAppminorתיק המשלוח — כל מה שנאמר ונעשה סביב משלוח, בכפתור אחד
אנחנו קוראים כל מה שקורה בקבוצות של הלקוחות והשליחים, אבל עד היום כמעט לא עשינו עם זה כלום: הבוט הגיב לכמה תרחישים וסגר את הפנייה, וכל השאר — פניות שירות, טענות כשל, אין מענה, טעויות כתובת, טעויות מיון, התכתבויות בקבוצות…
פרטים נוספים ↓הסתר ↑
אנחנו קוראים כל מה שקורה בקבוצות של הלקוחות והשליחים, אבל עד היום כמעט לא עשינו עם זה כלום: הבוט הגיב לכמה תרחישים וסגר את הפנייה, וכל השאר — פניות שירות, טענות כשל, אין מענה, טעויות כתובת, טעויות מיון, התכתבויות בקבוצות המחסן — נשאר קבור ב-inbox בלי שום קשר למשלוח שעליו דובר. הסיבה הטכנית: אף טבלת הודעות במערכת לא נשאה מזהה משלוח, ולכן 'תראה לי כל מה שנאמר על משלוח X' לא היה ניתן לשאילתה בכלל. נוספה שכבת קישור ייעודית, וכפתור חדש בכותרת דף המשלוח שפותח 'תיק המשלוח': ציר זמן אחד שמאחד את שיחות הקבוצות, בירורי הבוט, התראות הצוות, מחלוקות המסירה, הערות ה-AI וניסיונות המסירה — מקובץ לפי יום, עם סינון לפי סוג ומעבר לשיחה המלאה. הקישור דטרמיניסטי בלבד: הודעה נכנסת לתיק רק כשהיא מציינת מספר משלוח אמיתי, או כשהתרחיש/הבירור כבר ידע בוודאות על איזה משלוח מדובר — אין ניחוש ואין עלות AI. שלושה תרחישים שעד היום לא תיעדו דבר (בקשת פרטי משלוח, דיווח כשל מסירה, שיוך איסוף) מתעדים כעת את פעולתם.
- כפתור 'תיק המשלוח' בכותרת דף המשלוח — בתצוגה המלאה ובחלונית הצדדית כאחד
- ציר זמן מאוחד: שיחות קבוצה, בירורי בוט, התראות צוות, מחלוקות מסירה, הערות AI וניסיונות מסירה
- כל הודעה בקבוצה שמזכירה מספר משלוח נכנסת לתיק — גם כשאף תרחיש לא הופעל והבוט שתק בכוונה
- קישור דטרמיניסטי בלבד: ברקוד תקין בהודעה, ציטוט הודעה מזוהה, או בירור שכבר ידע את המשלוח — ללא הסקה וללא עלות AI
- סינון לפי סוג (שיחות / בירורי בוט / התראות / ניסיונות מסירה) עם מונים, וקיבוץ לפי יום
- הודעה שמונה כמה משלוחים (דוח מרוכז / תשובה מרוכזת של קבלן) מפוצלת — כל תיק מקבל רק את הקטע שלו, ולא את פרטי שאר הלקוחות
- סקריפט מילוי-לאחור מחיל את אותו כלל בדיוק על היסטוריית השיחות הקיימת
v01.236.004ייעולשליחים / דוח תשלוםדוח תשלום השליח — חיפוש המשלוחים הפך למיידי
אותה תקלה שתוקנה אתמול בדוח עמלות הסוכן התגלתה (בסריקת-מערכת של כל שדות החיפוש) גם בדוח התשלום החודשי של השליח — טאב 'תשלומים' בכרטיס השליח.
פרטים נוספים ↓הסתר ↑
אותה תקלה שתוקנה אתמול בדוח עמלות הסוכן התגלתה (בסריקת-מערכת של כל שדות החיפוש) גם בדוח התשלום החודשי של השליח — טאב 'תשלומים' בכרטיס השליח. בטבלת המשלוחים, כל הקשה בשדה החיפוש ציירה מחדש את כל שורות החודש: לשליח עמוס אלפי שורות (למשל 1263 בחודש), כל אחת עם ברקוד ותגית, מה שחסם את הקלט לשניות (רינדור מלא של 1263 השורות נמדד ב-~11 שניות). עכשיו הטבלה המוטמעת המשותפת (EmbeddedDataTable) מגבילה את הרינדור ל-50 שורות עם כפתור 'הצג הכל', כך שכל הקשה מציירת חופן שורות בלבד — ההקלדה מיידית והסינון מיידי, בעוד שהמעבר בין הטאבים (מסירות/איסופים/החזרות…) והסיכומים ממשיכים לשקף את מלוא הנתונים. התיקון חל גם על שאר הטבלאות המוטמעות בכרטיס השליח (משלוחים, ביקורים אחרונים, צ'ק-ליסט), שנהנות מאותה תקרה.
v01.236.003ייעולתשתית / ביצועיםהיגיינת נתונים: retention ליומן משלוחים, סטטיסטיקות גוביינא רזות וניטור גודל DB
המשך תוכנית ההיערכות לסקיילינג: (1) רשומות ה-audit של משלוחים — 99.5% מטבלת היומן, הרעש התפעולי של ה-webhooks — נמחקות מעתה אוטומטית אחרי 12 חודשים (במנות, בניקוי הלילי); כל שאר סוגי הרשומות (משתמשים, הרשאות, קונפיג) נשמ…
פרטים נוספים ↓הסתר ↑
המשך תוכנית ההיערכות לסקיילינג: (1) רשומות ה-audit של משלוחים — 99.5% מטבלת היומן, הרעש התפעולי של ה-webhooks — נמחקות מעתה אוטומטית אחרי 12 חודשים (במנות, בניקוי הלילי); כל שאר סוגי הרשומות (משתמשים, הרשאות, קונפיג) נשמרים לצמיתות. (2) סטטיסטיקות הגוביינא הפכו את כיוון הסינון: במקום לטעון את רשימת כל הברקודים הפעילים (שגדלה עם הטבלה) לכל טעינת מסך, נטענת רק רשימת היתומים (אנומליות בודדות שנשארות זעירות) — אומת בבדיקת שוויון מלאה מול נתוני production. (3) דוח גודל DB שבועי נכתב ללוג (סך הכול + 10 הטבלאות הגדולות), עם התראת WhatsApp לאדמין אם הגודל חוצה 20GB.
v01.236.002ייעולסוכנים / דוח עמלותדוח עמלות הסוכן — חיפוש הלקוחות הפך למיידי
בטבלת 'פירוט לפי לקוח' שבדוח העמלות, הקלדה בשדה החיפוש השתהתה שניות והתצוגה קפצה — כל הקשה ציירה מחדש את כל הרשימות בדוח, כולל רשימת המשלוחים (אלפי שורות) ואת כל שורות הלקוחות, מה שחסם את שדה הקלט.
פרטים נוספים ↓הסתר ↑
בטבלת 'פירוט לפי לקוח' שבדוח העמלות, הקלדה בשדה החיפוש השתהתה שניות והתצוגה קפצה — כל הקשה ציירה מחדש את כל הרשימות בדוח, כולל רשימת המשלוחים (אלפי שורות) ואת כל שורות הלקוחות, מה שחסם את שדה הקלט. עכשיו רשימת המשלוחים הכבדה ממוזכרת (memo) ואינה מצוירת מחדש בזמן חיפוש לקוח, וטבלת הלקוחות מגבילה את מספר השורות המצוירות ל-30 עם כפתור 'הצג הכל' — כך שכל הקשה מציירת חופן שורות בלבד. הסינון מיידי, הקלט חלק, והכולל בתחתית הטבלה ממשיך לסכם את כל התוצאות המסוננות (לא רק את המוצגות). השהיית ההקלדה ירדה מ-2–5 שניות ל-פחות מ-100 מ״ש.
v01.236.001ייעולתשתית / ביצועיםסבב חיזוק תשתית לקראת גדילה — שאילתות תחומות, crons עמידים ועלות webhooks
סבב ראשון מתוכנית ההיערכות לסקיילינג: דף פערי ההפצה הוסב לסינון על עמודות מסונכרנות (is_roundtrip) ולשליפת נהגים מטבלת הביקורים במקום חקירת JSON על כל משלוח — אומת בבדיקת שוויון מול נתוני production (זהות מלאה בנהגים ובת…
פרטים נוספים ↓הסתר ↑
סבב ראשון מתוכנית ההיערכות לסקיילינג: דף פערי ההפצה הוסב לסינון על עמודות מסונכרנות (is_roundtrip) ולשליפת נהגים מטבלת הביקורים במקום חקירת JSON על כל משלוח — אומת בבדיקת שוויון מול נתוני production (זהות מלאה בנהגים ובתאריכי מסירה); נוספה תקרת שורות לשאילתות המסך. ה-crons של ניקוי הלוגים והגלגול היומי עברו למחיקה/עדכון במנות עם תקציב זמן כך שצבר גדול לא יתקע אותם, ההתראות היזומות קיבלו תקציב זמן שמונע קטיעה באמצע שליחה, ותורת שגיאות הסנכרון תוחמה. היסטוריית משלוחי לקוח קיבלה תקרת עמודים מחייבת, ומפתח גישה שהיה כתוב בקוד הועבר למשתנה סביבה. בהמשך היום נוסף שלב הוזלת ה-webhooks: אירוע Lionwheel כפול (payload זהה בייט-בבייט) נעצר עכשיו בשער אחרי שאילתה אחת במקום להריץ את כל צינור העיבוד (15–45 פניות DB + קריאות Lionwheel), באמצעות טבלת webhook_logs הקיימת עם אילוץ ייחודיות אטומי; ושאילתות ה-secrets שרצות על כל webhook נכנס (Lionwheel / Meta / Green API) עוברות עכשיו דרך cache של דקה ב-Prisma Accelerate — חיסכון ישיר בעלות שאילתות שגדל עם התנועה. שלב שלישי באותו יום — קצבי רשתות הביטחון: חותמות הסנכרון (lastSyncAt) ומעקב בדיקות ה-POD קודמו מ-JSON לעמודות אמיתיות עם backfill מלא, כך שבחירת המועמדים לסנכרון כבר לא מפרקת את ה-JSON המלא של כל שורה; תור ההודעות המתוזמנות עבר לעיבוד מקבילי בין חברות (סדרתי בתוך חברה — שמירה על קצב ה-instance) עם תקרה של 150 להרצה במקום 50; רשתות הביטחון מול Lionwheel הוגדלו (200 לרבע שעה למשלוחים טריים, 300 כל שעתיים לפתוחים); וההתאמה הלילית של עלויות עברה ללולאה פר-חברה שמנצלת את האינדקס הייעודי. שלב רביעי — מגביל הקצב עבר מזיכרון מקומי ל-Redis: עד היום כל instance ב-Vercel ספר לעצמו, כך שמגבלות ה-API הציבורי וההגנה מפני ניסיונות התחברות כוחניים כמעט לא נאכפו תחת עומס; עכשיו המונה גלובלי (אותו Redis שמשמש את עדכוני הזמן-אמת), עם נפילה אוטומטית לזיכרון מקומי ל-30 שניות בכל תקלת Redis — בקשה לגיטימית לעולם לא תיחסם בגלל תשתית.
v01.236.000חדשבוט WhatsApp / צ'אט לקוחות קצהminorהבוט מזהה 'לא הזמנתי / טעות במספר' — מעדכן את השולח אוטומטית ומשתיק התראות
עד היום, נמען שכתב לבוט 'לא הזמנתי כלום' או 'טעות במספר' קיבל הפניה לבית העסק (שהוא בכלל לא מכיר) — וההתראות האוטומטיות המשיכו להישלח למספר השגוי.
פרטים נוספים ↓הסתר ↑
עד היום, נמען שכתב לבוט 'לא הזמנתי כלום' או 'טעות במספר' קיבל הפניה לבית העסק (שהוא בכלל לא מכיר) — וההתראות האוטומטיות המשיכו להישלח למספר השגוי. מעתה הבוט מזהה את המקרה כתרחיש ייעודי: עונה לנמען בחום שאין צורך בשום פעולה מצדו, שולח הודעה אוטומטית לבית העסק השולח בצ'אט העסקי (עם מספר המשלוח, שם הנמען ותוכן הטענה, ובקשה לאשר ביטול או לעדכן פרטים), משתיק את ההתראות האוטומטיות למספר ל-30 יום (גם הודעות שכבר ממתינות בתור), ומתעד הכל בהערה לצוות. אם לשולח אין צ'אט עסקי מקושר — השיחה מוסלמת לנציג עם הסבר. בנוסף תוקנה דליפת הסלמות גדולה: כשספק ה-AI המוגדר ל-tenant נכשל (מפתח נדחה, חריגת מכסה, JSON שבור) — כ-30% מכלל ההסלמות — הבוט מנסה כעת אוטומטית ספק גיבוי מערכתי לפני שהוא מוותר ומעביר לנציג.
- תרחיש 'לא הזמנתי / זה לא אני / טעות במספר' מזוהה ומטופל אוטומטית מקצה לקצה
- הודעה אוטומטית לשולח בצ'אט העסקי — עם פרטי המשלוח ובקשת הנחיה (ביטול / עדכון פרטים)
- השתקת התראות אוטומטיות למספר שדווח כשגוי ל-30 יום, כולל הודעות שממתינות בתור
- fallback לספק AI מערכתי כשספק ה-tenant נכשל — חוסך כ-30% מההסלמות שנגרמו משגיאות טכניות
- התרחיש מנוהל מדף הגדרות ← תרחישי בוט: טוגל הפעלה פר-חברה (כבוי כברירת מחדל) ותבנית הודעת-שולח ניתנת לעריכה
- המשך היום (מסקנות ניתוח 184 שיחות אמת): הבוט רואה כעת את שם בית העסק השולח, את רשומת המסירה (מתי נמסר, איך, למי — כולל חשד לסימון 'נמסר' בשעת לילה) ואת כל המשלוחים של הטלפון — כפילויות ומשלוחים מחזוריים
- הודעות הֲכָלָה בהסלמות רגישות: חריגת SLA, 'נמסר אבל לא קיבלתי' וערעור על ניסיון מסירה — הלקוח מקבל התנצלות + 'נפתח בירור' + התחייבות למועד תשובה, במקום שתיקה
- סולם טיפול חדש לערעור על 'ניסיון מסירה נכשל' (הכוונה הגדולה בהסלמות): נמסר? נבדוק · כשל איסוף? מרגיעים · כתובת חסרה? מבקשים · אחרת — בלי להתווכח, הסלמה מסודרת
- הבוט נוקב בשם השולח כשנמען שואל 'מי שלח לי את זה?' (שם בלבד, לעולם לא טלפון/כתובת) — במקום 'פנה לבית העסק' חסר-מוצא
- אימות לפני דגל ב'לא הזמנתי': טענה עמומה מקבלת שאלת אימות אחת לפני השתקה ועדכון שולח — מונע השתקת נמען אמיתי
- בקשות ביטול/עצירה ('תבטלו', 'אל תשלחו', 'כבר אספתי') מזוהות, מאושרות ללקוח ומוסלמות עם הערה מובנית — במקום להירשם בטעות כהוראת מסירה
- כשל איסוף מבית העסק לא נשלח יותר לנמען כ'ניסיון מסירה נכשל' — ההתראה המבהילה שייצרה גל פניות תמיכה הושתקה (השולח עדיין מיודע)
- יכולת 'לא לספק לפני תאריך' (hold): הבוט קולט בקשת דחייה, מאמת תאריך (עתידי, עד 14 יום), מטביע על המשלוח, מסנכרן הוראה בולטת לשליח בליונוויל — ויציאה מוקדמת להפצה מציפה התראת מנהל
v01.235.000שיפורסוכניםminorדף הסוכן נבנה מחדש — Shell מרונדר-שרת עם טאבי ראוט
דף הסוכן היה רכיב client בן ~430 שורות ששלף את GET /api/agents/[id] בטעינה מאחורי ספינר, עם פריסת שתי-עמודות עמוסה.
פרטים נוספים ↓הסתר ↑
דף הסוכן היה רכיב client בן ~430 שורות ששלף את GET /api/agents/[id] בטעינה מאחורי ספינר, עם פריסת שתי-עמודות עמוסה. הוא נבנה מחדש כ-Shell מרונדר-שרת קבוע (הדר זהות + שורת טאבים + רייל מאפיינים מתקפל) סביב שני טאבים מבוססי-ראוט: 'סקירה' (משתמשים מקושרים, לקוחות משויכים, פילוח לידים, הערות) ו'עמלות' (דוח עמלות חודשי + כללי עמלה + חיוב/זיכוי). הטעינה מיידית ללא ספינר, ולכל טאב יש URL משלו וניתן לקישור ישיר. ההדר צומצם לפעולת עריכה אחת; פרטי הקשר (טלפון, אימייל, חברה, עמלת ברירת מחדל, תאריך הצטרפות) עברו לרייל מתקפל בקצה — בדיוק כמו בדף הלקוח ובדף השליח/קבלן. ההרשאות נפתרות פעם אחת בשרת: טאב 'עמלות' לא מרונדר כלל למי שאין לו הרשאת צפייה-בעמלות או עריכה, וגישה ישירה ל-URL שלו מחזירה 404. סוכן שצופה בדף שלו יכול לקרוא אך לעולם לא לערוך. אותו דפוס בדיוק של העיצוב מחדש שנעשה לדף הלקוח ולדף השליח.
- רינדור-שרת במקום שליפת-client מאחורי ספינר — טעינה מיידית, URL ייעודי לכל טאב
- שני טאבים: 'סקירה' (משתמשים, לקוחות, לידים, הערות) ו'עמלות' (דוח + כללים + חיובים)
- טאב 'עמלות' מגודר בהרשאה שנפתרת בשרת — אינו מופיע ללא הרשאת עמלות/עריכה, ו-404 בגישה ישירה
- רייל מאפיינים מתקפל (סטטוס, טלפון, אימייל, עמלה, הצטרפות) — עקבי עם דף הלקוח והשליח
- ה-Shell (הדר + רייל) קבוע ואינו מרונדר מחדש במעבר בין טאבים
v01.234.001חדשמשתמשים / נוכחותדיווח נוכחות לעובדים שכירים מתוך ממשק הניהול
עובדים שכירים שעובדים בממשק הניהול יכולים מעתה להחתים כניסה/יציאה ישירות מהסרגל העליון — כפתור 'כנס למשמרת' שהופך למונה שעות חי עם סטטוס משמרת.
פרטים נוספים ↓הסתר ↑
עובדים שכירים שעובדים בממשק הניהול יכולים מעתה להחתים כניסה/יציאה ישירות מהסרגל העליון — כפתור 'כנס למשמרת' שהופך למונה שעות חי עם סטטוס משמרת. הרכיב עצמו היה קיים במערכת אך לא הייתה דרך להפעיל אותו: נוסף שדה 'קישור לרשומת עובד (נוכחות)' בטופס עריכת משתמש שמחבר חשבון ניהול לרשומת עובד. הקישור נאכף מול ה-tenant, עובד שכבר מקושר למשתמש אחר מסומן וחסום לבחירה, ומשתמשים מקושרים ממשיכים להופיע בדף ניהול המשתמשים (עד היום הם נעלמו ממנו). השינוי נכנס לתוקף בהתחברות הבאה של המשתמש המקושר. בהמשך היום תוקנו שני באגים שמנעו מהכפתור להופיע בפועל: (1) ה-session בדפדפן לא קיבל את קישור העובד עבור משתמשי צוות — ה-callback שמשרת את הדפדפן לא העביר את השדה, בניגוד למקבילה שלו ב-middleware; (2) 'התחבר כמשתמש' (התחזות) לא אימץ את קישור העובד של משתמש היעד, וביציאה מהתחזות הקישור של המנהל עצמו נמחק עד ההתחברות הבאה. עכשיו ההתחזות משקפת נאמנה גם את זהות הנוכחות של המשתמש. תיקון שלישי ואחרון: הרשאות הנוכחות-העצמית (צפייה והחתמה) היו מוענקות רק לתפקיד 'שליח שכיר', כך שעובד מקושר בכל תפקיד אחר (אדמין, נציג שירות, מחסנאי וכו') קיבל 403 שקט והכפתור לא הוצג; ההרשאות הוענקו לכל תפקידי הצוות — הן ממילא מוגבלות לעצמי ולא פעילות ללא קישור עובד. אומת מקצה-לקצה בדפדפן: כפתור 'כנס למשמרת' מופיע בהתחזות למשתמש מקושר. ותיקון משלים: שער הכניסה למודול ניהול הנוכחות חסם כל משתמש מקושר-עובד ללא דגל גישה מפורש — גם אדמינים; מעתה הקישור לעובד לא מוריד הרשאות שהתפקיד כבר מקנה: מי שתפקידו כולל ניהול עובדים שומר על גישה מלאה למודול, והחסימה (עם דגל ה-override) חלה רק על עובדים שעתיים בתפקידים ללא הרשאת ניהול.
v01.234.000חדשAPI ציבורי / אינטגרציותminorמשלוחים שנוצרים מה-API הציבורי משוגרים אוטומטית לליונוויל
עד היום POST /api/v1/shipments יצר את המשלוח במערכת המקומית בלבד — לקוחה שיצרה משלוח דרך אוטומציה (Make) קיבלה רשומה עם הברקוד הפנימי שלה (1-23290) שלא הגיעה מעולם לליונוויל ולשליחים.
פרטים נוספים ↓הסתר ↑
עד היום POST /api/v1/shipments יצר את המשלוח במערכת המקומית בלבד — לקוחה שיצרה משלוח דרך אוטומציה (Make) קיבלה רשומה עם הברקוד הפנימי שלה (1-23290) שלא הגיעה מעולם לליונוויל ולשליחים. מעתה, כשהמשלוח משויך ללקוח מקושר לליונוויל, היצירה עוברת דרך אותו pipeline משותף של יצירה ידנית/פורטל/ייבוא: ליונוויל מנפיק את ברקוד המעקב האמיתי, הברקוד ששלח הקורא נשמר כ-externalOrderId (זמין לחיפוש ב-GET ?externalOrderId=), בדיקת הכפילויות תופסת קריאה חוזרת גם לפי externalOrderId, וכשל שיגור מחזיר שגיאה ברורה במקום ליצור משלוח רפאים. כתובת מוצא נשלחת לליונוויל רק אם הקורא סיפק כתובת אמיתית (sourceName לבדו לא דורס את נקודת האיסוף של החברה). אם ה-tenant לא מחובר לליונוויל או שהלקוח לא מקושר — נשמרת ההתנהגות הישנה (יצירה מקומית בלבד). המשלוח התקוע 1-23290 שוגר בדיעבד (ברקוד חדש 26326550, כולל העתקת יעד האקספרס שהוגדר ידנית) והרשומה הישנה הועברה לסל המיחזור. תיעוד ה-API הציבורי עודכן בהתאם.
- POST /api/v1/shipments משגר לליונוויל דרך ה-pipeline המשותף כשהלקוח מקושר
- הברקוד של הקורא נשמר כ-externalOrderId; ליונוויל מנפיק את ברקוד המעקב
- בדיקת כפילויות גם לפי externalOrderId — קריאה חוזרת לא יוצרת כפילות
- fallback ליצירה מקומית בלבד כשאין ליונוויל (ההתנהגות הקודמת)
- המשלוח התקוע 1-23290 שוגר בדיעבד כ-26326550
v01.233.005תיקוןיציבות / אינטגרציותסנכרון שדות ל-Lionwheel קיבל retry, וסנכרון בלדר קיבל שוליים בטוחים
השלמת שני הפריטים שנצפו בבדיקת הלוגים של יום ראשון.
פרטים נוספים ↓הסתר ↑
השלמת שני הפריטים שנצפו בבדיקת הלוגים של יום ראשון. (1) מנוע סנכרון-השדות ל-Lionwheel (עריכת כתובת/טלפון/חבילות/מחיר מהמערכת, מהפורטל, מהדף הציבורי ומהבוט) עבד עד היום בקריאה יחידה עם timeout של 30 שניות ובלי retry — רגע איטי של Lionwheel איבד את העריכה, וה-webhook הבא מהם אף היה עלול לדרוס אותה מקומית בערך הישן. עכשיו: קריאות דרך ה-client המרכזי (timeout 10s), עד 3 ניסיונות עם backoff על כשלים חולפים, שליפות-האימות רצות רק כשבאמת צריך (חוסך שתי קריאות לכל סנכרון של חבילות/מחיר), וכשל-אימות כבר לא נספר ככשל סנכרון. (2) ה-cron של סנכרון סטטוסי בלדר נהרג ב-SIGKILL כשה-proxy היה איטי (התקציב הפנימי לא קוטע קריאה שבאוויר) — הורחב ל-120/90 שניות, ודחיפת הסטטוס ל-Lionwheel שבתוכו עברה ל-helper המשותף עם retry, מה שסוגר גם מקרה קצה שבו סטטוס מקומי התעדכן אך Lionwheel לא היה מקבל אותו לעולם.
v01.233.004שיפורלקוחות / תמחורתמחור לקוח — הוסרה קטגוריית 'החזרה' המיותרת
בטאב התמחור של דף הלקוח הוצגה קטגוריית תעריף 'החזרה' (RETURN) — שדה שריד שאינו מחויב באף מסלול: חיוב לקוח בוחר רק מסירה/איסוף, ורגל ההחזרה של כפולה מתומחרת בתוך תוספת הכפולה.
פרטים נוספים ↓הסתר ↑
בטאב התמחור של דף הלקוח הוצגה קטגוריית תעריף 'החזרה' (RETURN) — שדה שריד שאינו מחויב באף מסלול: חיוב לקוח בוחר רק מסירה/איסוף, ורגל ההחזרה של כפולה מתומחרת בתוך תוספת הכפולה. הקטגוריה הוסרה מקבוצת 'תוספות', ושורת הסיכום בדיאלוג טעינת תבנית מציגה כעת מסירה ואיסוף בלבד.
v01.233.003תיקוןפורטל לקוחות / אבטחהפורטל לקוחות — סגירת שלוש דליפות בין לקוחות באותו טננט
לקוח בפורטל ראה בדף "API ו-Webhooks" את כל מפתחות ה-API של הטננט — כולל מפתחות שהנפיקו לקוחות אחרים ומפתחות צוות — ולא רק את שלו.
פרטים נוספים ↓הסתר ↑
לקוח בפורטל ראה בדף "API ו-Webhooks" את כל מפתחות ה-API של הטננט — כולל מפתחות שהנפיקו לקוחות אחרים ומפתחות צוות — ולא רק את שלו. כך לקוח חדש שטרם יצר מפתח ראה שני מפתחות פעילים ששייכים לשני לקוחות אחרים, על שמם, ה-prefix, ה-scopes ומועד השימוש האחרון שלהם. הסיבה: שאילתות הרשימה והביטול סיננו לפי tenantId בלבד, בלי customerId — למרות שמסלול היצירה כבר קושר כל מפתח ללקוח המנפיק, ושכבת האימות של ה-API הציבורי כבר מכבדת את הקישור הזה. תוקן בשלושת המקומות: טעינת ה-SSR של הדף, GET /api/portal/api-keys, ו-DELETE /api/portal/api-keys/[id] — שם הצירוף tenant+customer מלווה גם את פעולת הכתיבה עצמה ולא רק את החיפוש, כך שלקוח לא יכול לבטל מפתח ייצור של לקוח אחר. בנוסף, מכסת המפתחות הפעילים (10) נספרת מעתה לפי לקוח ולא לפי טננט — קודם לכן לקוח שמילא את המכסה חסם את שאר לקוחות הטננט מהנפקת מפתחות. נוספו בדיקות רגרסיה לשתי הנתיבות. — בעקבות הממצא נסרקו כל 40 מסלולי ה-API של הפורטל וכל רכיבי השרת שלו, ונמצאו שתי תקלות נוספות מאותה משפחה: (1) POST /api/portal/ai/chat קיבל sessionId מגוף הבקשה בלי לאמת בעלות — היסטוריית השיחה נטענה לפי tenantId בלבד ומוזרקת לפרומפט, כך שלקוח יכול היה לקבל סיכום של שיחת AI של לקוח אחר (ו-AiChatSession הוא מרחב מזהים משותף שכולל גם שיחות צוות פנימיות ושיחות WhatsApp מול צד שלישי); בנוסף עדכון כותרת השיחה בוצע לפי id בלבד, בלי tenantId, כלומר חצה טננטים. נוסף אימות בעלות (tenant+customer+context) לפני השימוש, והכתיבות עברו ל-updateMany עם אותו צירוף. (2) מסלולי /api/portal/team התעלמו מ-scopedCustomerIds של המנהל עצמו — ההנחה הייתה ש"בעלים לעולם אינם מוגבלים", אך אוסף ההרשאות שמנהל פורטל רשאי להעניק הוא superset של הרשאות הבעלים, כך שמנהל יכול היה להפוך משתמש מוגבל ל"בעלים" ולתת לו גישה לרשימת המשתמשים של חשבונות מחוץ להיקפו — כולל איפוס הזמנה שמייצר קישור התחברות פעיל. נבדק מול ה-DB: 0 משתמשים חיים במצב הזה, כלומר לטנטי בלבד. בנוסף נאכף שרתית portalAiEnabled (קודם רק הוסתר הווידג'ט בצד לקוח).
- מפתחות API בפורטל — סינון לפי לקוח ולא לפי טננט, בשלוש שאילתות
- ביטול מפתח — הצירוף tenant+customer מלווה גם את הכתיבה (updateMany)
- צ'אט AI בפורטל — אימות בעלות על sessionId לפני טעינת היסטוריה
- ניהול צוות בפורטל — מנהל מוגבל נשאר מוגבל
- מכסת מפתחות פעילים נספרת לפי לקוח
- 11 בדיקות רגרסיה חדשות; 1445 בדיקות עוברות
v01.233.002תיקוןשידורים / בלדרבלדר — תיקוני מיפוי שדות אחרי השידור הראשון (טלפון, כתובת, טלפונים נוספים)
אחרי השידור האמיתי הראשון לזיפ התגלו כמה שדות שלא נקלטו נכון, ותוקנו: (1) טלפון — נשלח בפורמט בינלאומי (+972…) שזיפ לא קולט; מומר כעת לפורמט ישראלי מקומי (0…).
פרטים נוספים ↓הסתר ↑
אחרי השידור האמיתי הראשון לזיפ התגלו כמה שדות שלא נקלטו נכון, ותוקנו: (1) טלפון — נשלח בפורמט בינלאומי (+972…) שזיפ לא קולט; מומר כעת לפורמט ישראלי מקומי (0…). (2) כניסה/קומה/דירה — נדחסו בטעות לשדה מספר הבית; נשלחים כעת בשדות הייעודיים של בלדר (35/36/37), ולכן השורה גדלה מ-28 ל-37 פרמטרים (בלדר מתעלם מהעודפים אצל חברות שלא תומכות). (3) טלפונים נוספים (additionalPhones) — לבלדר אין שדה עבורם, ולכן הם משורשרים כעת להוראות המשלוח כ'טל נוסף: …' (ההוראות מגיעות לשליח). כל הטלפונים מנורמלים לפורמט מקומי.
v01.233.001תיקוןשידורים / בלדרבלדר — תוקן החיבור לשרת הקבלן דרך פרוקסי היציאה (403 על פורט לא-סטנדרטי)
סדרת תיקונים לחיבור השידור מול שרת בלדר של זיפ.
פרטים נוספים ↓הסתר ↑
סדרת תיקונים לחיבור השידור מול שרת בלדר של זיפ. שורש הבעיה האמיתי (שהתגלה בסוף): פרוקסי היציאה שלנו (squid) החזיר 403 בניסיון לפתוח מנהור CONNECT לפורט 58090 — squid מתיר CONNECT רק לפורט 443 כברירת מחדל, ו-undici פותח מנהור CONNECT גם ל-HTTP רגיל. התוצאה: התקשורת בכלל לא יצאה אל זיפ (ה-whitelist שלהם היה תקין כל הזמן). התיקון: שליחת בקשות בלדר דרך הפרוקסי בשיטת forwarding רגיל (absolute-form) במקום CONNECT — squid מתיר זאת לפורט 58090 (טווח Safe_ports). בדרך תוקנו גם: (1) התחברות לפי כתובת IPv4 שאנחנו פותרים בעצמנו (רשומת A בלבד) — עוקף את רשומת ה-IPv6 השבורה של זיפ (fe80::1) שגרמה להמתנה של 20 שניות; (2) חשיפת שרשרת השגיאה המלאה + כתובת היעד בלוג; (3) בבדיקת החיבור מוצגת כתובת ה-IP המדויקת שיוצאת אלינו (138.199.167.152).
v01.233.000חדשאפליקציית שליחים / תשתית buildminorאפליקציית שליחים — עדכונים אלחוטיים (OTA) + דיווח קריסות
שתי תשתיות שמשנות את קצב האחזקה של האפליקציה: (1) OTA — נוסף expo-updates עם runtimeVersion לפי fingerprint וערוצי EAS (preview/production).
פרטים נוספים ↓הסתר ↑
שתי תשתיות שמשנות את קצב האחזקה של האפליקציה: (1) OTA — נוסף expo-updates עם runtimeVersion לפי fingerprint וערוצי EAS (preview/production). מהבנייה הזו והלאה, תיקוני JS (לא-נייטיביים) יגיעו לשליחים אוטומטית דרך 'eas update' — בלי בנייה מלאה והתקנה ידנית בכל פעם. (2) דיווח קריסות — נוסף @sentry/react-native + ErrorBoundary מותאם (מסך 'משהו השתבש' עם 'נסה שוב' במקום קריסה אדומה), עם תיוג כל אירוע ב-update-id/ערוץ כדי לאתר מאיזה bundle הקריסה. Sentry מגודר ב-EXPO_PUBLIC_SENTRY_DSN — no-op עד שמוגדר DSN, כך שה-build עובד עם או בלי חשבון Sentry. שינוי נייטיבי — נכלל ב-build v1.2.0 (versionCode 6) שיש לבנות פעם אחת; אחריו העדכונים אלחוטיים.
- OTA: תיקוני JS עתידיים מגיעים אוטומטית (eas update) בלי build והתקנה ידנית
- runtimeVersion=fingerprint — במפ גרסה חופשי, OTA נשבר רק בשינוי נייטיבי
- Sentry + ErrorBoundary: מסך שגיאה ידידותי + דיווח קריסות מתויג ל-update-id
- מגודר ב-DSN — ה-build עובד עם או בלי חשבון Sentry
v01.232.001תיקוןהתחברותמסך התחברות — הודעת שגיאה אמיתית במקום "Configuration"
חשבון שננעל אוטומטית אחרי חמישה ניסיונות כושלים הציג למשתמש את ההודעה הגנרית "אימייל או סיסמה שגויים", בלי שום רמז לכך שהחשבון נעול ושהמתנה תפתור את זה.
פרטים נוספים ↓הסתר ↑
חשבון שננעל אוטומטית אחרי חמישה ניסיונות כושלים הציג למשתמש את ההודעה הגנרית "אימייל או סיסמה שגויים", בלי שום רמז לכך שהחשבון נעול ושהמתנה תפתור את זה. הסיבה טכנית: כל שגיאה שנזרקת בשלב אימות הפרטים נבלעה על ידי ספריית ההתחברות והגיעה לדפדפן כמחרוזת חסרת משמעות, כך שהסיבה האמיתית אבדה בשרת. כעת השגיאות נושאות קוד שעובר ללקוח, והמסך אומר מה קרה: חשבון נעול (כולל הפניה לאיפוס סיסמה), חשבון לא פעיל, או חשבון שנפתח דרך Google ואין לו סיסמה. שגיאת סיסמה שגויה וכתובת שאינה קיימת ממשיכות להחזיר את אותה הודעה בדיוק, כדי שלא ניתן יהיה לגלות דרך מסך ההתחברות אילו כתובות רשומות במערכת.
v01.232.000חדשעוזר AI פנימיminorעוזר AI — פתיחת משלוחי איסוף, כפולות ויעד שבת (ולא רק מסירה)
הרחבה לכלי פתיחת המשלוח מהצ'אט: עד כה הוא ידע לפתוח מסירה רגילה בלבד.
פרטים נוספים ↓הסתר ↑
הרחבה לכלי פתיחת המשלוח מהצ'אט: עד כה הוא ידע לפתוח מסירה רגילה בלבד. כעת הוא מזהה את סוג המשלוח מבקשת הנציג ותומך בשלושה סוגים, בדיוק כמו טופס יצירת המשלוח: מסירה, **איסוף מלקוח**, ו**כפולה** (מסירה + איסוף חזרה באותו מעמד), בתוספת **יעד שבת** (פרשה) לכל סוג. באיסוף הכיוון מתהפך — הנציג נותן את כתובת המוצא (מאיפה אוספים) והיעד נלקח אוטומטית מכתובת העסק של הלקוח, כך שהעוזר לא מבקש מהנציג את הצד שהמערכת כבר יודעת; אם ללקוח לא מוגדרת כתובת עסק, הכלי אומר זאת במפורש במקום להמציא יעד. אכיפת שדות החובה הותאמה לסוג: באיסוף נדרשים שם המקום, טלפון וכתובת האיסוף — ולא פרטי נמען. הכפולה נשלחת בסימון הנכון (is_roundtrip בלבד, בלי סוג משימה) — הכלל שאומת מול נתוני הפרודקשן בטופס. התצוגה המקדימה מציגה את סוג המשלוח ואת שני צידי הכתובת, כדי שהנציג יוכל לוודא את הכיוון לפני האישור. 28 טסטים מכסים את שלושת הסוגים.
- פתיחת איסוף מלקוח — הנציג נותן את כתובת האיסוף, היעד נלקח מכתובת העסק אוטומטית
- פתיחת כפולה (מסירה + איסוף חזרה) בסימון הנכון
- יעד שבת (פרשה) בכל סוג משלוח
- שדות החובה והתצוגה המקדימה מותאמים לסוג — באיסוף לא נדרשים פרטי נמען
- ללקוח בלי כתובת עסק — הכלי מסרב לפתוח איסוף במקום להמציא יעד
v01.231.006חדששידורים / בלדרבלדר — כפתור 'בדיקת חיבור' בכרטיס השידורים של הנהג
נוסף כפתור 'בדיקת חיבור' בכרטיס השידורים של נהג בלדר, שמריץ בדיקה מול השרת של הקבלן דרך אותו נתיב פרוקסי שבו משתמש השידור בפועל — קריאת GetCustomerRecords לקריאה-בלבד, בלי ליצור הזמנה.
פרטים נוספים ↓הסתר ↑
נוסף כפתור 'בדיקת חיבור' בכרטיס השידורים של נהג בלדר, שמריץ בדיקה מול השרת של הקבלן דרך אותו נתיב פרוקסי שבו משתמש השידור בפועל — קריאת GetCustomerRecords לקריאה-בלבד, בלי ליצור הזמנה. כך אפשר לוודא שכתובת השירות, קוד הלקוח, ורשימת ההיתר (whitelist) של ה-IP שלנו אצל הקבלן תקינים — לפני שמשדרים משלוח אמיתי. הבדיקה מציגה כמה משלוחים נמצאו ואת זמן התגובה, או את הודעת השגיאה המדויקת. רצה מול ההגדרות השמורות (יש לשמור לפני בדיקה).
v01.231.004תיקוןעוזר AI פנימיעוזר AI — חיפוש שליח בשם מלא נכשל תמיד; ופנייה לשליח שאינו משויך למשלוח
מניתוח שיחות אמת (16/07): נציג ביקש לשלוח לשליח 'חזי דרוויש' והעוזר השיב 'לא מצאתי שליח בשם זה — תעביר לו את ההודעה ידנית'.
פרטים נוספים ↓הסתר ↑
מניתוח שיחות אמת (16/07): נציג ביקש לשלוח לשליח 'חזי דרוויש' והעוזר השיב 'לא מצאתי שליח בשם זה — תעביר לו את ההודעה ידנית'. השליח קיים ופעיל במערכת. שורש הבאג: שם השליח מפוצל לשני שדות (שם פרטי 'חזי', שם משפחה 'דרוויש'), והחיפוש חיפש את המחרוזת המלאה בכל שדה בנפרד — כך ש**שם מלא לא יכול היה להימצא לעולם**, בשום כלי (פרטי שליח, שיוך שליח, שליחה לקבוצה). כעת החיפוש מפרק את השם למילים ודורש שכל מילה תופיע באחד משדות השם, כך ש'חזי דרוויש' מאתר את השליח הנכון ואינו מתבלבל עם 'חזי גוזלן'; בנוסף מועדף שליח פעיל על פני שליח לא-פעיל בעל שם זהה. תיקון שני מאותה שיחה: הנציג ביקש במפורש לפנות לשליח מסוים 'למרות שלא עליו המשלוח' — עד כה הכלי ידע לפנות רק לשליח המשויך למשלוח; כעת ניתן לציין שליח אחר בשם או במזהה, עם אותה בדיקת חד-משמעיות (שם שמתאים לכמה שליחים מחזיר רשימה לבחירה ולא מנחש), ותוך שמירה מלאה על המדיניות שהבוט פונה לקבוצות בלבד. בנוסף: לקוח ששמו מכיל שם עיר ('מלכות ירושלים') סונן בטעות לפי העיר והוחזרו 142 משלוחים של כל הלקוחות במקום 10 של הלקוח — ההנחיות חודדו.
- שם שליח מלא ('חזי דרוויש') מאותר סוף-סוף — קודם כל חיפוש בשם מלא נכשל בהכרח
- אפשר לפנות לשליח שאינו משויך למשלוח, לפי שם או מזהה, עם בדיקת חד-משמעיות
- שליח פעיל מועדף על פני לא-פעיל בעל שם זהה
- לקוח ששמו מכיל שם עיר ('מלכות ירושלים') כבר לא מסונן כעיר
v01.231.005שיפורבוט תפעולי / מנוע התרחישיםהבוט פונה לשליחים בקבוצות בלבד — לעולם לא בצ׳אט אישי
מדיניות חדשה: הבוט לעולם אינו פותח צ׳אט אישי מול שליח או קבלן, אלא פונה רק לקבוצה המשויכת (שלו, או של המנהל שלו במקרה של שליח-משנה).
פרטים נוספים ↓הסתר ↑
מדיניות חדשה: הבוט לעולם אינו פותח צ׳אט אישי מול שליח או קבלן, אלא פונה רק לקבוצה המשויכת (שלו, או של המנהל שלו במקרה של שליח-משנה). אם אין קבוצה מקושרת — הבוט לא שולח לשום מקום, אלא מעביר לטיפול הצוות. עד כה שלושה נתיבים נפלו חזרה לצ׳אט אישי לפי מספר הטלפון של השליח: מנגנון פתרון הקבוצה המשותף (שמשרת את תרחישי הצפי, טענת אי-מסירה, יידוע שיבוץ איסוף ותזכורות הצ׳קליסט), תרחיש תיאום מועד מחדש, וכלי ה-AI לשליחת הודעה לשליח. קבוצה היא מרחב משותף שבו הצוות רואה מה נאמר ויכול להתערב; צ׳אט אישי אינו כזה. בנוסף, תרחיש תיאום המועד עבר להשתמש במנגנון המשותף, כך שגם שליח-משנה מקבל את הפנייה בקבוצת המנהל שלו במקום להיות מפוספס. לצד זה חודדה הגדרת תרחיש הצפי כך שבקשה לשנות סכום גוביינא, דיווח על נזק, בקשת ביטול או שאלת חיוב לא ייקראו בטעות כשאלת צפי מסירה. בנוסף — יידוע שיבוץ איסוף מדלג כעת על שליח מושבת: קבלן שהופסקה עבודתו קיבל הודעה על שיבוץ והשיב שזו טעות, ולכן הבדיקה הורחבה מ"אינו שכיר" גם ל"פעיל".
v01.231.002תיקוןבוט תפעולי / מנוע התרחישיםהבוט רואה משימות איסוף של השליח, ומזהה ציטוט בכל רצף ההודעות
שני תיקונים לזיהוי המשלוח שהשליח מדבר עליו.
פרטים נוספים ↓הסתר ↑
שני תיקונים לזיהוי המשלוח שהשליח מדבר עליו. (1) כששליח שאל על משימה שמשובצת עליו, הבוט חיפש רק ביקורי מסירה — ולכן משימת איסוף הייתה בלתי-נראית לו לגמרי: שאלה עם מספר קיבלה "לא משויך אליך", ושאלה בלי מספר גרמה לבוט לנחש משלוח מסירה אחר ולהקריא את פרטיו (השליח שאל "מאיפה האיסוף הזה" וקיבל כתובת של משלוח אחר). כעת גם ביקורי איסוף בתמונה, וכששתי משימות פתוחות — הבוט שותק במקום לנחש. (2) בתרחיש השידור, ציטוט שיושב על הודעה סמוכה ברצף (השליח מגיב "מחר בבוקר" על הודעת השיבוץ ואז כותב "תשים עלי" בהודעה נפרדת) לא נקרא, והבוט ביקש מספר משלוח שהוצג לו זה עתה. כעת נסרקים הציטוטים בכל הרצף.
v01.231.001שיפורצ'אט לקוחות עסקייםצ'אט עסקי — כפתור ההעברה לארכיון הוחלף בסימון נקרא/לא נקרא
ברשימת הצ'אטים, הכפתור שנחשף במעבר עכבר על שורה היה 'העבר לארכיון' — ונציגות דיווחו שהן לוחצות עליו בטעות ומעבירות לקוחות פעילים לארכיון.
פרטים נוספים ↓הסתר ↑
ברשימת הצ'אטים, הכפתור שנחשף במעבר עכבר על שורה היה 'העבר לארכיון' — ונציגות דיווחו שהן לוחצות עליו בטעות ומעבירות לקוחות פעילים לארכיון. הכפתור הזה הוחלף בטוגל 'סמן כנקרא' / 'סמן כלא נקרא' (לפי מצב הצ'אט), פעולה הפיכה שלא גורמת נזק בלחיצה מקרית. ההעברה לארכיון והשחזור ממנו נשארו זמינים בתפריט הקליק-ימני על השורה ובכותרת הצ'אט הפתוח. בנוסף — סימון הצ'אט הפתוח כ'לא נקרא' סוגר אותו עכשיו, כמו בוואטסאפ; קודם הסימון לא היה נראה כלל כי מחוון ה'לא נקרא' מוסתר על השורה הפעילה, והצ'אט היה מסומן כנקרא שוב בהודעה הבאה.
v01.231.000חדשאינטגרציות / חנויותminorאישופ — שידור יזום מתוך החנות, עם דיווח תוצאה חזרה להזמנה
לקוחות ביקשו לא שנמשוך הזמנות אוטומטית אלא שהם ישדרו באופן סלקטיבי, כמו כפתור 'שדר הזמנה' שהכירו מליונוויל.
פרטים נוספים ↓הסתר ↑
לקוחות ביקשו לא שנמשוך הזמנות אוטומטית אלא שהם ישדרו באופן סלקטיבי, כמו כפתור 'שדר הזמנה' שהכירו מליונוויל. בתיאום עם הצוות הטכני של אישופ מומש בדיוק זה, בלי שאישופ נדרשו לפתח דבר: בעל החנות מעביר הזמנה לסטטוס ייעודי (למשל 'שדר לשיפנסט') — וזה מה שמפעיל אצלם webhook שדוחף אלינו את ההזמנה מיד. שיפנסט יוצרת את המשלוח ומשדרת לליונוויל, ואז מעדכנת את ההזמנה בחזרה בחנות: בהצלחה — סטטוס 'שודר בהצלחה' עם מספר המשלוח; בכישלון — סטטוס 'כישלון בשידור' עם הסיבה בהערות מנהל. כך בעל החנות רואה את התוצאה בממשק שלו, בלי להיכנס לשיפנסט. נוסף מסך הגדרות לבחירת שלושת הסטטוסים (מפעיל / הצלחה / כישלון) מתוך הרשימה האמיתית של החנות, כפתור 'רשום Webhook' שמבצע את הרישום מול אישופ, ומתג לכיבוי המשיכה האוטומטית — כך שבמצב שידור יזום לא נשרפת מכסת ה-API של החנות ולא נמשכות הזמנות ישנות. האימות נעשה בטוקן סודי אקראי שנוצר בכל רישום ונשמר מוצפן (אישופ עדיין לא תומכים ב-headers מותאמים, ולכן הטוקן עובר ב-query string) ונבדק בהשוואה עמידת-תזמון, fail-closed.
- שידור יזום: העברת הזמנה לסטטוס ייעודי דוחפת אותה לשיפנסט מיד — במקום משיכה אוטומטית עיוורת
- דיווח חזרה להזמנה: הצלחה עם מספר משלוח, או כישלון עם הסיבה בהערות מנהל
- בחירת שלושת הסטטוסים (מפעיל/הצלחה/כישלון) מתוך רשימת הסטטוסים האמיתית של החנות
- כפתור 'רשום Webhook' — רישום אוטומטי מול אישופ עם הסטטוס שנבחר
- מתג לכיבוי המשיכה האוטומטית — חוסך את מכסת ה-API של החנות
- אימות fail-closed בטוקן אקראי מוצפן, בהשוואה עמידת-תזמון
- כישלון שידור לעולם לא מוחזר כשגיאה לאישופ — כדי שלא ייווצר ניסיון חוזר וכפילות
- תיקון המשך: מניעת שורות כפולות משני webhooks מקבילים — אירוע זהה שנצפה פעמיים אינו נרשם שוב, ושתי שורות "יצירה" שנוצרו במרוץ מתאחות לאחת
v01.230.000שיפוריומן פעולות / auditminorיומן פעולות — מעקב מדויק אחרי מי ביצע כל שינוי, בלי כפילויות
יומן הפעולות של משלוח היה עמוס וחלקית שגוי.
פרטים נוספים ↓הסתר ↑
יומן הפעולות של משלוח היה עמוס וחלקית שגוי. שיבוץ שליח שהגיע מסנכרון ליונוויל לא נרשם כלל — driverId יושב על הביקור בעוד שבלוק ההשוואה בדק רק עמודות של המשלוח — ולכן השאלה 'מי שיבץ את השליח הזה' לא הייתה ניתנת למענה בלי לחפור בלוגים של Vercel. במקביל, כל מעבר סטטוס נרשם פעמיים משני מפיקים שונים: אחד בערכים קנוניים ואחד במחרוזות עברית, כשהאחרון היה גם המקום היחיד במערכת ששמר טקסט תצוגה לתוך oldData/newData ולכן שבר בשקט כל צרכן שמשווה מול enum, וגם השווה ערכים לא-מנורמלים כך שסטטוס מספרי מליונוויל מול ערך שמור יצר שורת סרק 'הושלם ← הושלם'. נוסף לכך, 6 שיבוצים מאפליקציית המנהלים נכתבו עם entityType באות גדולה וללא ברקוד ב-details, ולכן היו בלתי נראים בכל טיימליין במערכת.
- שיבוץ שליח מסנכרון ליונוויל נרשם כעת עם שם השליח, סוג הרגל (איסוף/מסירה/החזרה) והמקור — כולל שיבוץ שהגיע כבר ברגע יצירת המשלוח
- מפיק יחיד לסטטוס בערכים קנוניים; העברית מיוצרת בקריאה דרך STATUS_DISPLAY_MAPPING
- מיזוג אוטומטי של פרץ webhooks לשורה אחת (חלון 15 שניות, לפי מבצע זהה בלבד) — מעברי הביניים נשמרים במלואם ונפתחים בלחיצה
- ריצוד הסטטוס שליונוויל מייצרת בכל משימה שנוצרת ב-API מתקפל לשורה אחת במקום ארבע
- שורות ביקור מקושרות למשלוח לפי מזהה ולא לפי טקסט, ו-entityType מנורמל — שיבוצים מאפליקציית המנהלים מופיעים סוף-סוף
- מבצע הפעולה מוצג גם בשינויי סטטוס נגזרים משיבוץ, שקודם הופיעו ללא מבצע
v01.229.002תיקוןאבטחה / הרשאות סוכןאבטחה — סוכן יכול היה לפתוח משלוח של לקוח שאינו שלו לפי ברקוד
רשימת המשלוחים סיננה לסוכן לפי הלקוחות המשויכים אליו, אבל הקריאה של משלוח בודד (by-barcode, row, ו-GET לפי מזהה) סיננה לפי tenant בלבד.
פרטים נוספים ↓הסתר ↑
רשימת המשלוחים סיננה לסוכן לפי הלקוחות המשויכים אליו, אבל הקריאה של משלוח בודד (by-barcode, row, ו-GET לפי מזהה) סיננה לפי tenant בלבד. מכיוון שהברקוד הוא מונה רץ, סוכן שהדביק מספר ברקוד בכתובת יכול היה לפתוח כל משלוח ב-tenant — כולל לקוחות שאינם משויכים לאף סוכן — ולראות טלפוני נמענים, כתובות, הערות, תמונות מסירה והערות AI. שלושת הנתיבים מחילים כעת בדיוק את אותו סינון שהרשימה מחילה (customerId של לקוחות הסוכן, או התאמת שם למשלוחים ישנים ללא customerId), כך שמשלוח שהסוכן רואה ברשימה נשאר נגיש ושום דבר מעבר לכך לא. תוקן במקביל גם GET של לקוח בודד, שהיה הנתיב היחיד בלקוחות ללא סינון סוכן. עריכה לא הייתה חשופה — היא דורשת הרשאה שאין לסוכן. מסך הסריקה במחסן הושאר ללא סינון במכוון, כדי שסורק יזהה כל חבילה פיזית שמגיעה לידיו. בהמשך לכך תוקן גם המקור עצמו: התראות הזמן-אמת (SSE) שודרו לכל משתמשי ה-tenant ללא סינון, כך שסוכן קיבל התראת 'כשל משלוח' עם הברקוד על משלוח שאינו שלו — ומשם הגיע אליו בלחיצה. הזרם מסונן כעת לפי אותו היקף לקוחות, כך שסוכן מקבל התראות רק על המשלוחים שלו וכל התראה שהוא מקבל אכן נפתחת.
v01.229.001תיקוןאפליקציית שליחים / API מוביילאפליקציית שליחים — בכרטיס איסוף מוצג שם בית העסק, לא איש הקשר
המשך תיקון האיסופים: השם שהוצג בכרטיס איסוף היה איש הקשר במקום האיסוף (sourceRecipientName, למשל 'מאור') ולא בית העסק השולח.
פרטים נוספים ↓הסתר ↑
המשך תיקון האיסופים: השם שהוצג בכרטיס איסוף היה איש הקשר במקום האיסוף (sourceRecipientName, למשל 'מאור') ולא בית העסק השולח. בלוח המשימות זה השם החשוב — לכן ה-name לאיסוף מציג כעת את בית העסק (sourceName, עם נפילה ל-customerName / שם הביקור, ורק כמוצא אחרון לאיש הקשר כדי שהכרטיס לא יישאר ריק). בדף המשלוח המלא מוצגים שניהם: שם בית העסק, ומתחתיו 'איש קשר: ...' (שדה contactPerson חדש בתגובת ה-API, מוסתר כשהוא זהה לשם או ריק). מחרוזות ריקות מטופלות כחסרות. הצד השרתי (הרשימה) חי מיד; שורת 'איש קשר' בדף המשלוח מגיעה עם build המובייל v1.2.0.
v01.229.000חדשאפליקציית שליחיםminorאפליקציית שליחים — קיבוץ איסופים לעצירה אחת + סריקה לאיסוף (UI, לקראת build)
עושה סדר לשליח: כמה משימות איסוף מאותו שולח באותה כתובת מתקבצות כעת לעצירת-איסוף אחת ברשימת היום — כרטיס שמציג את הלקוח, הכתובת ומספר המשלוחים, במקום N משימות נפרדות (הקיבוץ לפי שולח+כתובת, זהה לדף /pickups, דרך pickupGr…
פרטים נוספים ↓הסתר ↑
עושה סדר לשליח: כמה משימות איסוף מאותו שולח באותה כתובת מתקבצות כעת לעצירת-איסוף אחת ברשימת היום — כרטיס שמציג את הלקוח, הכתובת ומספר המשלוחים, במקום N משימות נפרדות (הקיבוץ לפי שולח+כתובת, זהה לדף /pickups, דרך pickupGroupKey מהשרת). לחיצה על העצירה פותחת מסך פירוט: כותרת עם ניווט לכתובת האיסוף, פס התקדמות (נאספו/סה"כ), ורשימת כל המשלוחים עם הסטטוס שלהם. סגירת העצירה נעשית בסריקה: כפתור 'סרוק לאיסוף' פותח את הסורק במצב-איסוף — כל סריקה של ברקוד אוספת משלוח אחד מהקבוצה (מאמת שהוא שייך לעצירה), מציגה התקדמות (3/10), ונשארת פתוחה לחבילה הבאה. מסירות אינן מתקבצות. בנוסף, נוספה בחירה מרובה: לחיצה ארוכה על משימה ובחירת 'בחירה' נכנסת למצב בחירה עם צ'קבוקסים על הכרטיסים; אפשר לסמן כמה משימות (או עצירת-איסוף שלמה בבת אחת) ולבצע פעולה על כולן — הוספה או הסרה מהמסלול — דרך endpoint bulk יחיד. נכלל ב-build המובייל v1.2.0 (versionCode 6).
- כמה איסופים מאותו שולח+כתובת = עצירת-איסוף אחת (במקום N משימות)
- מסך עצירה: ניווט, פס התקדמות נאספו/סה"כ, ורשימת המשלוחים
- סגירה בסריקה — כל ברקוד אוסף משלוח, עם התקדמות (3/10)
- בחירה מרובה: סימון כמה משימות והוספה/הסרה מהמסלול בבת אחת
v01.228.003חדשאפליקציית שליחים / API מוביילאפליקציית שליחים — תשתית שרת לקיבוץ איסופים ולבחירה מרובה
תשתית לשני פיצ'רים חדשים באפליקציה (ה-UI יגיע ב-build הבא): (1) ה-API של 'היום' מחזיר כעת pickupGroupKey לכל משימת איסוף — מפתח קיבוץ לפי שולח+כתובת, זהה לזה של דף /pickups — כדי שהאפליקציה תקבץ מספר איסופים מאותו לקוח ב…
פרטים נוספים ↓הסתר ↑
תשתית לשני פיצ'רים חדשים באפליקציה (ה-UI יגיע ב-build הבא): (1) ה-API של 'היום' מחזיר כעת pickupGroupKey לכל משימת איסוף — מפתח קיבוץ לפי שולח+כתובת, זהה לזה של דף /pickups — כדי שהאפליקציה תקבץ מספר איסופים מאותו לקוח באותה כתובת לעצירה אחת. (2) נוסף endpoint לבחירה מרובה במסלול (route/stops/bulk) המקבל רשימת visitIds ופעולה add/remove, לביצוע פעולה על כמה משימות בבת אחת. שניהם מגובים באימות בעלות (רק ביקורים של הנהג).
v01.228.002תיקוןאפליקציית שליחים / API מובייל + geocodingאפליקציית שליחים — משימות איסוף מציגות מפה, מרחק ושם (geocoding למקור)
המשך לתיקון האיסופים: מאחר שמשלוח עבר geocoding ליעד בלבד, משימת איסוף באפליקציה נותרה ללא קואורדינטות מקור — ולכן הוצג 'אין קואורדינטות' במקום מפה, ולא חושב מרחק מהשליח.
פרטים נוספים ↓הסתר ↑
המשך לתיקון האיסופים: מאחר שמשלוח עבר geocoding ליעד בלבד, משימת איסוף באפליקציה נותרה ללא קואורדינטות מקור — ולכן הוצג 'אין קואורדינטות' במקום מפה, ולא חושב מרחק מהשליח. נוספו עמודות source_latitude/source_longitude ופונקציית geocoding לכתובת המקור (geocodeShipmentSource: קואורדינטות ביקור-האיסוף → רחוב המקור → מרכז יישוב המקור). ה-API מחזיר כעת לאיסוף את קואורדינטות המקור (ביקור → מקור, לעולם לא היעד), כך שהמפה, המרחק והניווט מצביעים על נקודת האיסוף. כמו כן, שם הלקוח בכרטיס איסוף שהיה יכול להיות ריק (כשכל שדות המקור ריקים) נופל כעת ל-customerName. הקואורדינטות מגובות אחורנית למשלוחי האיסוף הרלוונטיים (סקריפט backfill, ממוקד באיסופים פתוחים המשובצים לנהג — מה שמופיע בפועל בפיד היומי, לא בכל ההיסטוריה) ומחושבות אוטומטית למשלוחים חדשים עם רגל איסוף.
v01.228.001שיפוראחסון / אבטחהאחסון קבצים — הפסקת החשיפה של קישורים ציבוריים קבועים
דלי האחסון של המערכת משותף לכל סוגי הקבצים והיה ציבורי, כלומר כל קישור שדלף נשאר תקף לצמיתות.
פרטים נוספים ↓הסתר ↑
דלי האחסון של המערכת משותף לכל סוגי הקבצים והיה ציבורי, כלומר כל קישור שדלף נשאר תקף לצמיתות. שני צעדים ראשונים לקראת סגירתו: (1) בבירור מסירה, תמונת ההוכחה של השליח הועברה ללקוח העסקי דרך קישור ציבורי ששרתי Green API משכו בעצמם — עכשיו הבתים נשלחים אליהם ישירות. זו הייתה התלות החיצונית היחידה בכך שהדלי יישאר ציבורי. קישור חתום לא היה תחליף בטוח כאן, שכן תשובת 200 מ-Green משמעה "בתור" ולא "נשלח", והמשיכה עלולה להגיע אחרי שהקישור פג. (2) מסמכי עובדים — ת"ז, רישיונות וחוזי העסקה — הוצגו עד היום דרך קישור ציבורי קבוע שנשמר במסד הנתונים והוחזר ללקוח. כעת הם נמשכים דרך מסלול מאומת שבודק הרשאה, מסנן לפי הטננט (ובמסך העובד — גם לפי העובד עצמו מה-session), ומפנה לקישור חתום שתקף לשעה. נתיב האחסון והקישור הציבורי כבר לא מוחזרים באף תשובת API. בשני המקרים ההתנהגות למשתמש זהה, ותנאי הסינון של הבוט לא שונו.
v01.228.000שיפורשליחים / דף שליחminorדף שליח — עיצוב מחדש: מסגרת קבועה עם טאבים, כמו דף הלקוח
אותו עיצוב מחדש שיושם על דף הלקוח, עכשיו על דף השליח/קבלן.
פרטים נוספים ↓הסתר ↑
אותו עיצוב מחדש שיושם על דף הלקוח, עכשיו על דף השליח/קבלן. הדף היה מונוליט של 2,357 שורות בקובץ אחד, עם הדר של 8 כפתורים שטוחים וטור כרטיסים שנמתח הרבה מתחת לקיפול. הוא מפורק עכשיו למסגרת קבועה — זהות, פעולות, שורת טאבים ורייל מאפיינים — סביב חמישה טאבים שהם ראוטים אמיתיים: סקירה (KPI, מפת מסלול, heatmap, ערים, כשלונות), משלוחים (פעילים/כשלים, צ'קליסט, ביקורים אחרונים, גוביינא), תשלומים (רווחים, מחירון, התאמות ומשמרות לעובדים), תת-שליחים (למנהלים בלבד), והגדרות (שידור לקבלנים חיצוניים, קבוצת וואטסאפ, חשבונות). סט הטאבים משתנה לפי סוג השליח — מנהל רואה תת-שליחים, עובד מקבל משמרות והתאמות בתשלומים, קבלן חיצוני מקבל את כרטיס השידור — וכל ראוט מותנה מוגן בשרת. בניגוד לטאב 'כספים' בלקוח, טאב 'תשלומים' נשאר פתוח ללא גייטינג — דף השליח מעולם לא הסתיר רווחים ומחירון מהצוות, וסדרנים משתמשים בהם. ההדר ירד משמונה כפתורים לשניים: 'שבץ משלוחים' קודם לפעולה הראשית (הסיבה הכי נפוצה שפותחים שליח — לתת לו עבודה; קודם היה קבור בתוך טבלת המשלוחים), 'עריכה' יורד למשני, ופעולות הסטטוס והחשבונות עוברות ל-⋮. חייג ו-WhatsApp עוברים לרייל. בנוסף: המגירה שנפתחת מכל שם שליח הפכה לתצוגה מקדימה מהירה במקום עותק שני של הדף, עם endpoint רזה (/preview, ארבע שאילתות במקום עשרים) שגם סוגר פער הרשאות — הוא דורש עכשיו DRIVERS_VIEW.
- חמישה טאבים אמיתיים (ראוטים) במקום מונוליט של 2,357 שורות — כל טאב טוען רק את מה שהוא מרנדר
- סט הטאבים משתנה לפי סוג השליח (מנהל / עובד / קבלן חיצוני), עם guard בשרת לכל ראוט מותנה
- ההדר ירד מ-8 כפתורים לשניים; 'שבץ משלוחים' קודם לפעולה הראשית
- רייל מאפיינים קבוע — 6 שדות מקודמים ו'הצג הכל'; חייג ו-WhatsApp עברו לרייל
- טאב תשלומים נשאר פתוח (בלי גייטינג) — בשונה מטאב הכספים בלקוח
- המגירה הפכה לתצוגה מקדימה מהירה; ה-endpoint שמזין אותה ירד ל-4 שאילתות ודורש DRIVERS_VIEW
v01.227.001שיפורמשלוחים / מפותטופס משלוח — מפת התצוגה מציגה עכשיו את נקודת המסירה המדויקת
מפת התצוגה בטופס יצירת המשלוח הראתה עד היום את מרכז היישוב בלבד ("מרכז הישוב, לא ברמת רחוב") — כך שטעות ברחוב או במספר לא הופיעה על המפה.
פרטים נוספים ↓הסתר ↑
מפת התצוגה בטופס יצירת המשלוח הראתה עד היום את מרכז היישוב בלבד ("מרכז הישוב, לא ברמת רחוב") — כך שטעות ברחוב או במספר לא הופיעה על המפה. כעת, ברגע שמוזן רחוב, המפה נפתרת ברמת רחוב (MapTiler, מנוצל מהמנוי בתשלום) ומראה את נקודת המסירה האמיתית, כך שאפשר לתפוס כתובת שגויה לפני שמירה — הפרש טיפוסי בין מרכז-עיר לכתובת מדויקת הוא מאות מטרים עד קילומטרים. התווית מציינת "כתובת מדויקת" (ירוק) כשההתאמה ברמת רחוב, או "מרכז הישוב" כשיש רק עיר. תוקן תוך כדי גם באג בפורטל: מפת התצוגה בטופס הפורטל קראה ל-/api/geocode של הצוות ולכן קיבלה 401 והמפה לא הופיעה כלל — נוסף /api/portal/geocode עם אימות פורטל. הלוגיקה המשותפת (resolveAddressPreview) חיה במקום אחד ומשמשת את שני המסלולים.
v01.227.000תיקוןיציבות / תשתיתminorמבצע ייצוב רוחבי — סגירת מרוצים, כפילויות ואובדני עדכונים בכל צינורות הרקע
תחקור עומק של כל התהליכים האוטומטיים במערכת (webhooks, crons, שליחות WhatsApp, סנכרוני חנויות) חשף שורה של מרוצי-מקביליות ונקודות אובדן — כולן טופלו בסבב אחד.
פרטים נוספים ↓הסתר ↑
תחקור עומק של כל התהליכים האוטומטיים במערכת (webhooks, crons, שליחות WhatsApp, סנכרוני חנויות) חשף שורה של מרוצי-מקביליות ונקודות אובדן — כולן טופלו בסבב אחד. הצינור של Lionwheel קיבל הגנת עדכון-מקבילי (OCC) כך ששני webhooks על אותו משלוח לא דורסים זה את זה, ומגן רגרסיה שמונע מאירוע ישן שמגיע באיחור 'לפתוח מחדש' משלוח שכבר נמסר; דחיפות סטטוס ל-Lionwheel ושליחות מתוזמנות קיבלו retry אוטומטי ו-claim אטומי שמונע הודעה כפולה ללקוח; אישור מסירה ב-WhatsApp כבר לא יכול להירשם פעמיים או להיתקע במצב ביניים; webhooks יוצאים ללקוחות API לא יישלחו שוב על-ידי ריצות חופפות; שמירת נהג עוטפה בטרנזקציה (כשל חלקי כבר לא מוחק אזורי שיבוץ); ותוקנו שתי הפרות FK פעילות (יומן מחירון לקוח, audit מהפורטל). בנוסף: סנכרון הזמנה פגומה מחנות כבר לא תוקע את כל החנות, מסכי סטטיסטיקות כבדים רוסנו מול ה-connection pool, וטקסט עם אימוג'י חתוך כבר לא מפיל את עדכון שיחות ה-WhatsApp.
- הגנת מקביליות + מגן רגרסיית-סטטוס על צינור ה-webhook של Lionwheel
- retry אוטומטי לדחיפות סטטוס ל-Lionwheel ולשליחות WhatsApp מתוזמנות
- claim אטומי בהודעות מתוזמנות וב-webhooks יוצאים — סוף לשליחות כפולות
- אישור מסירה: תפיסה אטומית + שחזור אוטומטי ממצב ביניים תקוע
- שמירת נהג בטרנזקציה — כשל חלקי לא מוחק יותר אזורי שיבוץ
- תוקנו שתי הפרות FK פעילות ומגן מספר-דמה לפני שליחת WhatsApp
- סבב המשך: retry בטוח לכל שליחות ה-WhatsApp המיידיות (כשל רשת/429/כשלי gateway — בלי סיכון כפילות על timeout)
- עבודת רקע (התראות קבוצה, סנכרון שותפים, טריגרים) מעוגנת ל-after() — לא נקטעת יותר עם החזרת ה-response
- חלון TTL של 2 דקות לסנכרון תזרים המזומנים — דפדוף בין חודשים כבר לא מפעיל חישוב מלא כל פעם (הכפתור הידני עוקף)
- לוחות ה-crons פוזרו על דקות שונות — סוף לפרץ המסונכרן של 10 ריצות בו-זמנית כל 5 דקות
- שידור SNL/בלדר דוחף סטטוס ל-Lionwheel דרך ה-helper המשותף (כולל retry) במקום קוד קשיח
v01.226.001שיפורמפות / מעקב משלוחיםמפת דף המעקב שודרגה למפת MapTiler + דיוק קואורדינטות תוקן רטרואקטיבית
ניצול המנוי בתשלום של MapTiler (Flex Pro) בשני מקומות עם ערך אמיתי.
פרטים נוספים ↓הסתר ↑
ניצול המנוי בתשלום של MapTiler (Flex Pro) בשני מקומות עם ערך אמיתי. (1) דף המעקב הציבורי הציג עד היום iframe גנרי של OpenStreetMap עם תוויות באנגלית ומראה בסיסי. הוחלף בתמונת Static Map של MapTiler — תוויות עברית, marker על נקודת המסירה, מודעת theme (בהיר/כהה), ועטופה בקישור "פתח במפות" שפותח את המיקום ב-Google Maps / אפליקציית המפות של הנמען. אם התמונה נכשלת (תקלת MapTiler) יש נפילה חזרה ל-iframe של OSM, כך שהמפה אף פעם לא נעלמת. (2) גיבוי דיוק: בזמן שחשבון MapTiler היה מושהה על חריגת מכסה, ~1,100 משלוחים מהחודש האחרון קיבלו קואורדינטות בדיוק נמוך (fallback ל-Nominatim, מרכז-יישוב, או ללא) — כעת שהחשבון בתשלום, הם עברו re-geocoding ברמת רחוב דרך MapTiler. שיעור הדיוק הגבוה עלה מ-86% ל-90%.
v01.226.000חדשפיננסים / מחירוניםminorמתג בסיס ייחוס חיוב בהגדרות + היגיינת מחירונים
השלמת חבילת יישור-החיוב לליונוויל: (1) מסך הגדרות ← העדפות קיבל סקציית 'בסיס ייחוס חיוב' — בחירה בין ייחוס לפי תאריך האיסוף בפועל (ברירת מחדל) לבין תאריך האיסוף המתוכנן (תואם לדוח החיוב של ליונוויל); ההגדרה נשמרת פר-טננט…
פרטים נוספים ↓הסתר ↑
השלמת חבילת יישור-החיוב לליונוויל: (1) מסך הגדרות ← העדפות קיבל סקציית 'בסיס ייחוס חיוב' — בחירה בין ייחוס לפי תאריך האיסוף בפועל (ברירת מחדל) לבין תאריך האיסוף המתוכנן (תואם לדוח החיוב של ליונוויל); ההגדרה נשמרת פר-טננט וכל מנועי החיוב מכבדים אותה. (2) מדיניות הכפולה נאכפת אוטומטית: בכל שמירת מחירון של לקוח ללא סוכן, תוספת הכפולה נצמדת למחיר הבסיס האפקטיבי (רגל שנייה במחיר מלא) — כך ששינוי מחיר בסיס עתידי לא ישאיר תוספת כפולה ישנה; לקוחות של סוכנים (₪5) לא נדרסים. (3) שדה 'החזרה' — שריד שאינו מחויב באף מסלול — הוסר מדיאלוג המחירון ומרשימת סוגי הכללים.
- מתג 'בסיס ייחוס חיוב' בהעדפות — בפועל / מתוכנן (תואם ליונוויל)
- כפולה=מחיר בסיס נאכף אוטומטית בכל שמירת מחירון (לקוחות ללא סוכן)
- שדה 'החזרה' הוסר מהמחירון — לא חויב מעולם באף מסלול
v01.225.001תיקוןמפותמפות — נפילה אוטומטית ל-OSM כשמפתח MapTiler נדחה
כל המפות במערכת הציגו אריחי "Invalid key" אחרי שחשבון MapTiler הושהה זמנית על חריגה מהמכסה החודשית (100 אלף אריחים בתוכנית החינמית).
פרטים נוספים ↓הסתר ↑
כל המפות במערכת הציגו אריחי "Invalid key" אחרי שחשבון MapTiler הושהה זמנית על חריגה מהמכסה החודשית (100 אלף אריחים בתוכנית החינמית). השורש: הקוד הניח שמפתח מוגדר הוא מפתח עובד — getTileConfig בחר ב-MapTiler בכל פעם שהמשתנה קיים, וחמש תצוגות הווקטור (useVector) עשו את אותה הנחה. מפתח חסר תמיד נפל ל-OSM/Carto ועבד; מפתח שנדחה היה גרוע מזה — מפות שבורות על המסך. כעת שכבת בסיס משותפת אחת (BaseTileLayer) משרתת את כל 10 תצוגות ה-raster: כשאריח נכשל, בדיקה יחידה מול MapTiler קובעת אם המפתח באמת נדחה (401/403/429) — ורק אז MapTiler מנוטרל לכל המפות בסשן, כולל החלפת תצוגות הווקטור ל-raster, והכל עובר ל-OSM/Carto אוטומטית. תקלת רשת רגעית לא מנטרלת (אריח בודד שנכשל אינו פסק דין). רענון דף מנסה את MapTiler מחדש, כך שהתאוששות (איפוס מכסה / שדרוג תוכנית) לא דורשת deploy. ה-geocoding לא נפגע מהתקלה — היה לו כבר fallback ל-Nominatim. 10 בדיקות מכסות את התרחיש.
v01.225.000חדשמחירון לקוחות ושליחיםminorמחירון — עורך תעריפים מהיר, ותיקון "מחיר נוכחי" שהציג מחיר שאיש לא חויב בו
עורך תעריפים מהיר (QuickRateEditor) בדיאלוגי המחירון של הלקוחות והשליחים: כל התעריפים שיכולים לשאת כלל מוצגים בגריד אחד, ומילוי תא הופך אותו לכלל רגיל — עם תוקף, מצב (החלפה/תוספת), תווית והערה — במקום לפתוח דיאלוג נפרד ל…
פרטים נוספים ↓הסתר ↑
עורך תעריפים מהיר (QuickRateEditor) בדיאלוגי המחירון של הלקוחות והשליחים: כל התעריפים שיכולים לשאת כלל מוצגים בגריד אחד, ומילוי תא הופך אותו לכלל רגיל — עם תוקף, מצב (החלפה/תוספת), תווית והערה — במקום לפתוח דיאלוג נפרד לכל תעריף. בנוסף תוקן באג בעמודת "מחיר נוכחי": כשהיו כמה כללי REPLACE חופפים, החישוב בצד הלקוח שבר את השוויון לפי validFrom — בעוד שמנוע החיוב עצמו שובר אותו לפי createdAt (האחרון שנוצר מנצח). כלומר העמודה יכלה להציג מחיר שהלקוח בפועל לעולם לא חויב בו. שני הצדדים משתמשים עכשיו באותו קריטריון, וכלל חדש שטרם נשמר נחשב לחדש ביותר — כפי שהוא. חולצו גם עוזרי תמחור משותפים (parse-rate-input, money) עם 12 בדיקות.
- עורך תעריפים מהיר — כל התעריפים בגריד אחד במקום דיאלוג לכל תעריף
- "מחיר נוכחי" הציג מחיר שגוי כשהיו כללי REPLACE חופפים — תוקן ליישר עם מנוע החיוב
- עוזרי תמחור משותפים לדיאלוג הלקוחות והשליחים, עם 12 בדיקות
v01.224.000שיפורלקוחות / דף לקוחminorדף לקוח — עיצוב מחדש: מסגרת קבועה עם טאבים במקום דף אחד עמוס
דף הלקוח נבנה בשלבים, וכל פיצ'ר הוסיף עוד כרטיסייה — עד שהוא הגיע ל-1,954 שורות בקובץ אחד, הדר עם 13 פעולות, וטור שמאלי של 10 כרטיסים שנמתח הרבה מתחת לקיפול.
פרטים נוספים ↓הסתר ↑
דף הלקוח נבנה בשלבים, וכל פיצ'ר הוסיף עוד כרטיסייה — עד שהוא הגיע ל-1,954 שורות בקובץ אחד, הדר עם 13 פעולות, וטור שמאלי של 10 כרטיסים שנמתח הרבה מתחת לקיפול. הכל נטען בכל כניסה, כולל ההגדרות שנוגעים בהן פעם בחיי הלקוח. הדף מפורק עכשיו למסגרת קבועה — זהות, פעולות, שורת טאבים ורייל מאפיינים — סביב חמישה טאבים שהם ראוטים אמיתיים: סקירה (KPI, מפה, משלוחים אחרונים, יומן פעילות), משלוחים (הטבלה המלאה, שהייתה דיאלוג), כספים (רווחיות, חיובים, גוביינא, סאמיט) מחירון (עורך התעריפים, שהיה דיאלוג של 1,400 שורות) והגדרות (כל שמונה ההגדרות הפר-לקוחיות). כרטסת וזיכויים שומרים על הכתובות שלהן ונקראים כ"כספים". כל טאב הוא קובץ נפרד עם שליפה משלו, אז הוא טוען רק את מה שהוא מרנדר; ומכיוון ש-Next לא מרנדר layout מחדש בניווט בין ילדיו, שאילתת הזהות של המסגרת רצה פעם אחת ושורדת כל החלפת טאב. ההדר ירד לשתי פקדים: ארבע מהפעולות (משלוחים, מחירון, כרטסת, זיכויים) היו ניווט שהתחזה לפעולה והפכו לטאבים, והשאר הן פעולות מחזור-חיים שיושבות מאחורי ⋮. "בטל השעיה" הופיע פעמיים כשלקוח מושעה (באנר + סרגל) ומופיע עכשיו פעם אחת. פרטי הקשר עברו לרייל במקום להיות משוכפלים בכותרת. טאב "כספים" מוגן בשרת ומוסתר משורת הטאבים למי שאין לו הרשאת FINANCE_VIEW — ההרשאות נפתרות פעם אחת בשרת מתפקיד הדייר, ולא מהצד הלקוח (שקורא את תפקיד הפלטפורמה; השניים יכולים לא להסכים, ואז נוצר טאב שמוביל ל-404). בנוסף: המגירה שנפתחת מכל שם לקוח באפליקציה הפכה לתצוגה מקדימה במקום עותק שני של הדף, ו-endpoint שמזין אותה ירד משליפה של כל ספריית הלקוחות ויתרת הקבוצה לשלוש שאילתות.
- חמישה טאבים אמיתיים (ראוטים) במקום דף אחד עמוס — כל טאב טוען רק את מה שהוא מרנדר
- כפתור "משלוח חדש" בראש הדף — הפעולה הראשית, נפתח עם הלקוח כבר מסומן
- המחירון הפך מדיאלוג של 1,400 שורות לטאב עם URL — והדיאלוג נשאר דק לשאר הקוראים
- ההדר ירד מ-13 פעולות לשתיים; ניווט שהתחזה לפעולות הפך לטאבים
- רייל מאפיינים קבוע — 6 שדות מקודמים ו"הצג הכל"; מצב הקיפול נשמר בין טאבים
- כל ההגדרות הפר-לקוחיות עברו לטאב ייעודי במקום להיטען בכל כניסה
- המגירה הפכה לתצוגה מקדימה מהירה עם קישור לכרטיס המלא
- "בטל השעיה" הופיע פעמיים כשלקוח מושעה — תוקן
- טאב כספים מוגן בשרת, לא רק מוסתר
v01.223.002שיפורתיעודמילון מונחים — הוסר הערך "אגורות" שסתר את תיעוד ה-API
הערך "אגורות" במילון המונחים תיאר פרט מימוש פנימי (המערכת שומרת כסף כמספרים שלמים באגורות) וקבע "חשוב לזכור בעבודה מול ה-API" — בדיוק ההפך ממה שתיעוד ה-API אומר: "סכומי כסף ב-API נשלחים בשקלים (decimal) — המערכת ממירה אג…
פרטים נוספים ↓הסתר ↑
הערך "אגורות" במילון המונחים תיאר פרט מימוש פנימי (המערכת שומרת כסף כמספרים שלמים באגורות) וקבע "חשוב לזכור בעבודה מול ה-API" — בדיוק ההפך ממה שתיעוד ה-API אומר: "סכומי כסף ב-API נשלחים בשקלים (decimal) — המערכת ממירה אגורות פנימית, כך שלא צריך לדאוג לכך מצדכם". הקוד מאשר: הקלט מוכפל ב-100 והפלט מחולק ב-100, כך שה-API כולו בשקלים ולקוח לעולם לא נתקל באגורות. הערך גם סתר את הגדרת המילון עצמו ("כל המונחים שתפגשו ב-Shipnest"). הוסר; אין קישורים נכנסים אליו, והסבר הכסף נשאר בתיעוד ה-API במקום הרלוונטי.
v01.223.002תיקוןAI / בוט WhatsAppסיווג WhatsApp נכשל כשהמודל הוסיף טקסט אחרי ה-JSON
שגיאה חוזרת בפרודקשן: [ai-delivery-cron] Session processing failed — "Unexpected non-whitespace character after JSON at position 290".
פרטים נוספים ↓הסתר ↑
שגיאה חוזרת בפרודקשן: [ai-delivery-cron] Session processing failed — "Unexpected non-whitespace character after JSON at position 290". השורש: הניקוי של תשובת המודל חילץ את ה-{...} רק אם הטקסט *לא* התחיל ב-{. gemini מחזיר בדרך כלל JSON נקי, אבל לעיתים מוסיף שורת סיום אחרי הסוגר — ואז הטקסט כן מתחיל ב-{, השומר דילג על הניקוי, ו-JSON.parse נחנק על הזבל שאחרי. התוצאה: ה-session כולו נכשל ונשלחה התראת וואטסאפ למנהל, למרות שהסיווג עצמו היה תקין. הוחלף בחילוץ שרץ תמיד, עם סריקת סוגריים מאוזנת מודעת-מחרוזות שעוצרת בסוגר הסוגר של האובייקט הראשון — עמיד לזבל לפני ואחרי, ל-code fences, לשני אובייקטים (מקרה שחיתוך פשוט מהסוגר הראשון לאחרון היה נכשל בו), ולסוגריים בתוך טקסט עברי. פלט קטוע מחזיר null מסודר עם הודעה ברורה במקום להיחנק. נבדק ש-4 מסלולי ה-AI האחרים אינם חולים בבאג. 11 בדיקות רגרסיה.
v01.223.000שיפורתיעודminorתיעוד — הדגשת תחביר בקוד ותוכן עניינים במובייל
הסבב השני בליטוש התיעוד, שסוגר את שני הפריטים שנשארו.
פרטים נוספים ↓הסתר ↑
הסבב השני בליטוש התיעוד, שסוגר את שני הפריטים שנשארו. (1) הדגשת תחביר: בלוקי הקוד היו טקסט אפור אחיד. נוספה הדגשה מלאה (Shiki, ערכות github-light/github-dark) — אבל בצד השרת בלבד: הדפדפן מקבל HTML מוכן ו-Shiki לא נכנס ל-bundle של הלקוח כלל, וזו בדיוק הסיבה שנמנענו מזה עד היום. הגבול נאכף ב-import server-only, כך שדליפה עתידית לצד לקוח תישבר בזמן build ולא בשקט. ההדגשה עוקבת אחרי מתג ה-theme דרך משתני CSS כפולים — בלי JS ובלי הבהוב. חשוב: 19 מתוך 37 הבלוקים מתויגים text — אלה דיאגרמות זרימה בעברית ולא קוד, והם נשארים רגילים במכוון. תוך כדי התגלה שדפי התיעוד אינם סטטיים (ה-layout הראשי קורא cookies()+auth(), מה שמכריח רינדור דינמי לכל הדפים), כך שההדגשה הייתה רצה מחדש בכל צפייה; נוסף cache שממפה קוד+שפה ל-HTML, ומכיוון שבלוקי הקוד הם ליטרלים סטטיים כל בלוק מחושב פעם אחת לכל תהליך שרת. כפתור ההעתקה ממשיך להעתיק את המקור הגולמי, לא את ה-HTML המודגש. (2) תוכן עניינים במובייל: פס ה"בעמוד הזה" היה זמין רק ב-lg ומעלה, כך שבמובייל ובטאבלט לא הייתה שום דרך לנווט בתוך עמוד ארוך. נוסף אקורדיון מתקפל בראש התוכן שנסגר אוטומטית בבחירת סעיף; לוגיקת סריקת הכותרות חולצה ל-hook משותף כדי שהפס והאקורדיון לא ייפרדו.
- הדגשת תחביר בבלוקי קוד (Shiki) — בצד השרת בלבד, אפס תוספת ל-bundle של הלקוח
- ההדגשה עוקבת אחרי ה-theme דרך משתני CSS כפולים — בלי JS ובלי הבהוב
- דיאגרמות הזרימה בעברית (lang=text) נשארות ללא הדגשה במכוון
- cache להדגשה — הדפים דינמיים, אז בלי זה כל צפייה הייתה מחשבת מחדש
- תוכן עניינים מתקפל במובייל/טאבלט (עד היום היה זמין רק בדסקטופ)
v01.222.000חדשפיננסים / חיובminorבסיס ייחוס חיוב פר-טננט — התאמה מלאה לדוח החיוב של ליונוויל
חקירת הפערים מול דוחות ליונוויל הוכיחה שדוח החיוב שלהם מסנן לפי תאריך האיסוף המתוכנן (עמודת 'איסוף'), בעוד שאצלנו הייחוס היה לפי האיסוף בפועל — ומכאן פערי גבול-חודש (משלוח ערב סוף-חודש שמבוצע אחרי חצות).
פרטים נוספים ↓הסתר ↑
חקירת הפערים מול דוחות ליונוויל הוכיחה שדוח החיוב שלהם מסנן לפי תאריך האיסוף המתוכנן (עמודת 'איסוף'), בעוד שאצלנו הייחוס היה לפי האיסוף בפועל — ומכאן פערי גבול-חודש (משלוח ערב סוף-חודש שמבוצע אחרי חצות). נוספה עמודה pickupScheduledAt שלוכדת את התאריך המתוכנן מה-webhook (מתעדכנת בכל שינוי שיבוץ עד הביצוע, ואז קופאת — ליונוויל דורסים את השדה בזמן הביצוע), והגדרה חדשה פר-טננט (tenant.settings.billingAttributionBasis) שבוחרת את בסיס הייחוס: 'איסוף בפועל' (ברירת מחדל, המצב הקיים) או 'איסוף מתוכנן' (תואם ליונוויל). כל מנועי החיוב — דוח פירוט חיובים, טבלת חיוב לקוחות, עמלות סוכן ו-P&L — עוברים דרך helper משותף אחד כך שכולם תמיד באותו בסיס. ההיסטוריה אותחלה מתאריך הביצוע (125,744 משלוחים); התאריכים המתוכננים האמיתיים נצברים מרגע הפריסה.
- pickupScheduledAt — לכידת תאריך האיסוף המתוכנן לפני שליונוויל דורסים אותו בביצוע
- הגדרה פר-טננט: ייחוס לפי איסוף בפועל (ברירת מחדל) או מתוכנן (תואם ליונוויל)
- helper משותף (lib/billing-attribution) — דוח לקוח, טבלת חיוב, עמלות סוכן ו-P&L תמיד על אותו בסיס (חיווט מנוע העמלות הושלם ב-17.7)
- אותחלו 125,744 משלוחים היסטוריים; דיוק מלא נצבר מהפריסה והלאה
v01.221.003ייעוללקוחות / דף לקוחדף לקוח — פיצול שכבת הנתונים לשולפים ממוקדים
הכנה לעיצוב מחדש של דף הלקוח.
פרטים נוספים ↓הסתר ↑
הכנה לעיצוב מחדש של דף הלקוח. getCustomerDetailData היה שולף אחד ענק שכל טעינה שילמה עליו במלואו: פרטי הלקוח, ספירות, 5 משלוחים אחרונים, כל לקוחות הדייר, שאילתת SQL גולמית של עד 500 יעדים עם LATERAL join, מעבר geocoding, ויתרת סאמיט. פוצל לשולפים ממוקדים — getCustomerIdentity (הרשומה עצמה, ממוסמנת ב-React.cache כך שכמה רכיבי שרת באותה בקשה חולקים שאילתה אחת), getCustomerOverview (ספירות, אחרונים, יתרה), getCustomerDestinations (מפה) ו-getTenantCustomers (ספריית הלקוחות, לדיאלוגים בלבד) — כך שכל טאב בעיצוב החדש ישלם רק על מה שהוא מרנדר. getCustomerDetailData נשאר כ-shim שמרכיב את כולם, אז אף קורא לא השתנה וההתנהגות זהה; הוא ייעלם כשהדף יעבור לטאבים. בנוסף: הופרדו בוני ה-WHERE לפונקציות טהורות וכוסו בבדיקה שמקבעת את ההשוואה הקריטית — שספירת המשלוחים שנמסרו לא יכולה לדלוף ולהפוך לכלל-דיירית (אומת במוטציה: הזרקת הרגרסיה מכשילה את הבדיקה). ההערה שהזהירה מפני התנגשות OR עודכנה — היא תיארה מימוש שקדם למיגרציית עמודת ה-status.
v01.221.002תיקוןשליחים / דף שליחדף שליח — בידוד דיירים בכותרת הטאב
אותה דליפה שתוקנה בדף הלקוח, גם בדף השליח: כותרת הטאב (generateMetadata) שלפה את שם השליח לפי מזהה בלבד, ללא סינון לפי דייר — בעוד שגוף אותו עמוד סינן נכון והחזיר 404.
פרטים נוספים ↓הסתר ↑
אותה דליפה שתוקנה בדף הלקוח, גם בדף השליח: כותרת הטאב (generateMetadata) שלפה את שם השליח לפי מזהה בלבד, ללא סינון לפי דייר — בעוד שגוף אותו עמוד סינן נכון והחזיר 404. משתמש מחובר של דייר אחד יכול היה לקבל שם פרטי ומשפחה של שליח מדייר אחר בכותרת. הסינון עכשיו לפי ה-tenantId שב-session.
v01.221.001תיקוןלקוחות / דף לקוחדף לקוח — בידוד דיירים בכותרת, כרטיס גוביינא בכשל, ושמירת שם קבוצת האיסוף
שלושה תיקונים בדף הלקוח, כהכנה לעיצוב מחדש של הדף.
פרטים נוספים ↓הסתר ↑
שלושה תיקונים בדף הלקוח, כהכנה לעיצוב מחדש של הדף. (1) בידוד דיירים: כותרת הטאב (generateMetadata) שלפה את שם הלקוח ישירות לפי מזהה, ללא סינון לפי דייר — בעוד שגוף אותו עמוד סינן נכון והחזיר 404. כלומר משתמש מחובר של דייר אחד יכול היה לקבל שם לקוח של דייר אחר בכותרת. הסינון עכשיו לפי ה-tenantId שב-session, בדיוק כמו הקריאה הקנונית ב-getCustomerDetailData. (2) כרטיס "גוביינא" הציג כותרת עם גוף ריק לחלוטין כשטעינת הנתונים נכשלה — ללא הודעת שגיאה וללא דרך לנסות שוב; הודעת "אין נתוני גוביינא" הייתה מקוננת בתוך ענף ההצלחה ולכן לא נורתה אף פעם בכשל. נוסף מצב שגיאה עם כפתור "נסה שוב", בדפוס של כרטיס סאמיט הסמוך, וגם תשובת 200 עם success:false נחשבת כעת ככשל. (3) בכרטיס "תיאום איסוף יומי", שם קבוצת הוואטסאפ נשלח בשמירה אך לא נכלל בזיהוי השינויים — ולכן שינוי שם של קבוצה קיימת (אותו מזהה, שם חדש) לא הפעיל את כפתור השמירה, והשם המעודכן לא ניתן היה לשמירה כלל.
v01.221.000שיפורתיעודminorתיעוד — ליטוש עיצובי: ניווט בין עמודים, פירורי לחם, ואיזון הכותרת
סבב ליטוש בתיעוד הציבורי (/docs) שמקרב אותו לסטנדרט של תיעוד מוצר מקצועי.
פרטים נוספים ↓הסתר ↑
סבב ליטוש בתיעוד הציבורי (/docs) שמקרב אותו לסטנדרט של תיעוד מוצר מקצועי. (1) שורת הכותרת בדסקטופ הייתה לא מאוזנת — תיבת החיפוש נתקעה בצד עם רווח מת גדול עד הניווט; כעת החיפוש ממלא את המרכז הגמיש (ממורכז, רחב יותר) וה-theme toggle מעגן את הקצה. (2) נוסף ניווט הקודם/הבא בתחתית כל עמוד תיעוד — פיצ׳ר סטנדרטי שהיה חסר, שמאפשר לקרוא את התיעוד ברצף במקום לחזור לסיידבר בכל פעם. (3) נוספו פירורי לחם בראש כל עמוד (תיעוד ← סקציה ← עמוד). שניהם נגזרים מרצף עמודים חדש שנבנה אוטומטית מסדר הסיידבר (DOCS_PAGE_SEQUENCE), כך שהם לא יכולים להיפרד ממנו — עוגנים בתוך-עמוד מתקפלים לעמוד שלהם, ועמודי stub ולינקים משפטיים מסוננים. (4) תוקן פורמט התאריך: "Updated: 13 2026 ביולי" נרנדר הפוך בגלל dir=ltr על תאריך עברי — כעת "עודכן: 13 ביולי 2026". (5) סבב עקביות ריווח לפי רשת 8px: הריווח האנכי בין בלוקי תוכן היה מעורב (12/16/20 פיקסלים לפי סוג הבלוק) ואוחד ל-16px אחיד; ריווח פריטי ניווט, TOK ווידג׳ט מה-חדש יושרו לרשת. אומת ויזואלית בדסקטופ/טאבלט/מובייל, וכן נמדד ב-CDP ברוחב 390px שאין גלישה אופקית.
- ניווט הקודם/הבא בתחתית כל עמוד תיעוד — נגזר אוטומטית מסדר הסיידבר
- פירורי לחם בראש כל עמוד (תיעוד ← סקציה ← עמוד)
- שורת הכותרת אוזנה — חיפוש ממורכז ורחב יותר, בלי רווח מת
- תאריך העדכון נרנדר הפוך (dir=ltr על תאריך עברי) — תוקן
- ריווח אנכי אחיד בין בלוקי תוכן (16px) לפי רשת 8px
v01.220.001חדשבוט תפעולי / מנוע התרחישיםminorאישור גורף להשארה ליד הדלת — הבוט עונה לשליח מיד
הגדרה חדשה בכרטיס הלקוח: "אישור גורף להשארה ליד הדלת".
פרטים נוספים ↓הסתר ↑
הגדרה חדשה בכרטיס הלקוח: "אישור גורף להשארה ליד הדלת". כשהיא פעילה, ושליח מדווח "אין מענה" על משלוח של אותו לקוח — הבוט משיב לו מיד להניח ליד הדלת ולצלם תיעוד, במקום לפתוח בירור מול השולח ולהמתין לתשובה שידועה מראש. חוסך לשליח המתנה ולנציגות סבב פניות. גם אישור של הנמען עצמו (שנקלט אוטומטית מהשיחה איתו — "תשאירו ליד הדלת") מקצר את התהליך באותה דרך. שני חריגים שהאישור לעולם אינו גובר עליהם, כי אי אפשר להשלים אותם מול דלת סגורה: משלוח גוביינא (יש לגבות תשלום) ומשלוח כפולה (יש איסוף חזרה) — במקרים אלה הבוט מיידע את השליח מיד מדוע אי אפשר להניח, ופונה ללקוח כרגיל. משימות איסוף אינן רלוונטיות ומדולגות.
- מתג בכרטיס הלקוח (כבוי כברירת מחדל) — כשהוא פעיל הבוט עונה לשליח מיד ולא מפריע ללקוח
- גם "תשאירו ליד הדלת" של הנמען עצמו מקצר את התהליך
- גוביינא וכפולה — חריגים קשיחים שהאישור אינו גובר עליהם; השליח מקבל הסבר מיידי למה, כדי שלא יניח בכל זאת
- שני אותות בלתי-תלויים לזיהוי גוביינא (additionalData + CodTracking) — אומת על 30 יום: 176 משלוחי גוביינא, אפס פערים
- חידוד לאחר ביקורת אדוורסרית: המענה האוטומטי יורה רק על דיווח של אי-מענה טהור (דיווח מורכב כמו "אמ ולא מוצא את הכתובת" חוזר לשאלה לשולח, אחרת בעיית הכתובת הייתה נעלמת); לא יורה כשהמשלוח נוחש ולא זוהה במפורש; לא חוזר על עצמו בדיווח נוסף; וכשלא ניתן לאמת את פרטי המשלוח — נסוג לשאלה לשולח במקום להניח שבטוח.
v01.219.003תיקוןשידורים / בלדרבלדר — שיבוץ מדף המשלוח מציג 'השידור נכשל' במקום 'שובץ בהצלחה' כשהשידור נכשל
בשיבוץ נהג בלדר מדף המשלוח, הטוסט הציג 'השליח עודכן בהצלחה' גם כשהשידור לקבלן נכשל בפועל — כי ה-route החזיר הצלחה על עדכון הביקור בלי לשקף את תוצאת השידור.
פרטים נוספים ↓הסתר ↑
בשיבוץ נהג בלדר מדף המשלוח, הטוסט הציג 'השליח עודכן בהצלחה' גם כשהשידור לקבלן נכשל בפועל — כי ה-route החזיר הצלחה על עדכון הביקור בלי לשקף את תוצאת השידור. מעכשיו ה-route מחזיר את תוצאת השידור (broadcastFailed), וה-UI מבטל את השיבוץ האופטימי ומציג את סיבת הכשל האמיתית ('השידור לקבלן נכשל — המשלוח לא שובץ' או הודעת השגיאה מבלדר). חל גם על נהגי SNL. משלים את ביטול-השיבוץ בצד השרת שכבר קיים.
v01.219.002תיקוןשידורים / בלדרבלדר — כשל שידור מבטל את השיבוץ המקומי (לא נשאר משובץ באופן מטעה)
כשמשבצים נהג בלדר, השיבוץ נכתב מקומית לפני השידור בפועל.
פרטים נוספים ↓הסתר ↑
כשמשבצים נהג בלדר, השיבוץ נכתב מקומית לפני השידור בפועל. עד היום, אם השידור נכשל (למשל 'fetch failed' מול שרת הקבלן), המשלוח נשאר משובץ על נהג הבלדר גם אחרי רענון — למרות ששום דבר לא הגיע לקבלן, ובניגוד ל-SNL גם לא נדחף נהג לליונוויל. זה הטעה את הסדרנים. מעכשיו, כל כשל שידור לבלדר (כשל רשת, דחיית פרמטרים, ספק לא מוגדר, או חוסר כתובת מחסן) מבטל אוטומטית את שיבוץ נהג הבלדר על ביקור המסירה/האיסוף — כך שהמשלוח חוזר להיות 'לא משובץ' ואפשר לנסות שוב או לבחור שליח אחר. הביטול מרוכז בפונקציית השידור, כך שהוא חל בכל מסלולי השיבוץ (דף המשלוח, שיוך מרובה, סריקה, פעולת AI ובוט קבוצתי), ובטוח: הוא נוגע רק בביקור שעדיין משובץ על נהג בלדר ושלא שודר בהצלחה (יש הגנה מפני מחיקת שיבוץ של שידור שכן הצליח). בשיוך מרובה הטבלה מתרעננת אוטומטית בסיום השידור כדי לשקף את הביטול.
v01.219.001תיקוןשידורים / בלדרבלדר — שידור דרך פרוקסי יציאה קבוע, לעקיפת חסימת IP של שרתי הקבלנים
שידור הניסיון הראשון לזיפ נכשל עם 'fetch failed' — השרתים שלנו ב-Vercel לא הצליחו לפתוח חיבור לשרת של זיפ (http://zip.king2k.com:58090), למרות שהכתובת תקינה והגיבה בבדיקה מקומית.
פרטים נוספים ↓הסתר ↑
שידור הניסיון הראשון לזיפ נכשל עם 'fetch failed' — השרתים שלנו ב-Vercel לא הצליחו לפתוח חיבור לשרת של זיפ (http://zip.king2k.com:58090), למרות שהכתובת תקינה והגיבה בבדיקה מקומית. הסיבה: שרתי בלדר הם מכונות on-prem ישראליות מאחורי חומת אש שמתירה רק כתובות IP מוכרות, ו-Vercel יוצא ממאגר כתובות ענן מתחלף (בנוסף, זיפ פרסמו רשומת DNS פגומה מסוג IPv6 — fe80::1 — שמפילה את happy-eyeballs של Node). הפתרון: כל קריאות בלדר (שידור ובדיקת סטטוסים) עוברות מעכשיו דרך פרוקסי היציאה הקבוע שכבר משמש את אינטגרציית אישופ (EGRESS_PROXY_URL), שמספק כתובת IP אחת יציבה שחברת השליחים יכולה להתיר, וגם פותר את רשומת ה-DNS הפגומה כיוון שהוא מבצע resolve נכון ל-IPv4. אין השפעה כשהפרוקסי לא מוגדר (נפילה חזרה ל-fetch רגיל).
v01.219.000חדשיעד אקספרסminorיעד אקספרס — הוספת משלוחים לפי לקוח, לא רק לפי מספרי משלוח
עד היום מודל 'הוספת משלוחים' בעמוד יעד אקספרס ידע לקבל רק רשימת מספרי משלוח מודבקת — מי שרצה לסמן את המשלוחים של לקוח מסוים היה צריך קודם לאסוף את המספרים שלו ממקום אחר.
פרטים נוספים ↓הסתר ↑
עד היום מודל 'הוספת משלוחים' בעמוד יעד אקספרס ידע לקבל רק רשימת מספרי משלוח מודבקת — מי שרצה לסמן את המשלוחים של לקוח מסוים היה צריך קודם לאסוף את המספרים שלו ממקום אחר. כעת יש במודל שני מצבים: 'לפי מספרי משלוח' (הקיים) ו'לפי לקוח' — מצב חדש שפותח רשימה של כל הלקוחות הפעילים עם חיפוש (שם, טלפון או כתובת), וליד כל לקוח כפתור 'משלוחים' שפותח את כל המשלוחים שלו. משם מסמנים את המשלוחים הרצויים ובוחרים תאריך יעד אקספרס מסרגל הפעולות — בדיוק כמו הזרימה המוכרת מהצ'ק ליסט של יעד שבת. עם סגירת חלון המשלוחים טבלת האקספרס מתרעננת אוטומטית.
- מצב חדש 'לפי לקוח' במודל הוספת המשלוחים, לצד המצב הקיים של הדבקת מספרים
- רשימת כל הלקוחות הפעילים עם חיפוש לפי שם, טלפון או כתובת
- כפתור 'משלוחים' לכל לקוח — פותח את כל משלוחיו וסימון יעד אקספרס מסרגל הפעולות
- אותה זרימה מוכרת מהצ'ק ליסט של יעד שבת; טבלת האקספרס מתרעננת עם הסגירה
v01.218.002תיקוןבוט תפעולי / מנוע התרחישיםהבוט מצטט נכון — אישור על התשובה, ומספר משלוח מתוך הציטוט
שני תיקונים לקריאת ההקשר בקבוצות: (1) כשלקוח עונה על שאלת הבוט (למשל מוסר מספר טלפון), האישור "קיבלנו, העברנו לשליח שמטפל ✅" הוצמד לשאלה של הבוט עצמו במקום לתשובת הלקוח — נראה כאילו הבוט עונה לעצמו, ובקבוצה עמוסה האישור …
פרטים נוספים ↓הסתר ↑
שני תיקונים לקריאת ההקשר בקבוצות: (1) כשלקוח עונה על שאלת הבוט (למשל מוסר מספר טלפון), האישור "קיבלנו, העברנו לשליח שמטפל ✅" הוצמד לשאלה של הבוט עצמו במקום לתשובת הלקוח — נראה כאילו הבוט עונה לעצמו, ובקבוצה עמוסה האישור התנתק מההודעה שאליה התייחס. כעת הוא מצטט את התשובה. (2) בתרחיש השידור, כששליח מבקש "תשימו עליי" בתגובה להודעה שכבר מכילה את מספר המשלוח (לרוב הודעת השיבוץ שלנו עצמה) — הבוט ביקש ממנו את המספר שהוא בדיוק מצטט. כעת הוא מחלץ את המספר מההודעה המצוטטת, כמוצא אחרון בלבד (בלי לדרוס מספרים שכבר זוהו בהודעות עצמן).
v01.218.000חדשעוזר AI פנימיminorעוזר AI — פתיחת משלוח חדש מהצ'אט, עם אכיפת פרטים מלאים ואישור הנציג
לבקשת נחמה מהשיחות ('אתה יכול לפתוח משלוח חדש?...
פרטים נוספים ↓הסתר ↑
לבקשת נחמה מהשיחות ('אתה יכול לפתוח משלוח חדש?... כדאי שתלמד לעשות זאת') — העוזר הפנימי יודע כעת לפתוח משלוח חדש, דרך אותה צנרת קליטה של טופס יצירת המשלוח (ברקוד ליונוויל אמיתי). הדרישה המרכזית — שהעוזר יוודא שיש לו פרטים מלאים מהנציג — נאכפת **בתוך הכלי עצמו ולא בהנחיות בלבד**, בהמשך ללקח שהנחיות לחוד ומעשים לחוד: כל עוד חסר ולו שדה חובה אחד (הלקוח השולח, שם הנמען, טלפון, עיר, רחוב, מספר בית) הכלי מסרב ליצור ומחזיר במפורש אילו שדות חסרים, כדי שהעוזר יבקש אותם מהנציג ולא ישלים אותם בעצמו. בנוסף: שם לקוח שמתאים לכמה לקוחות מחזיר רשימת מועמדים במקום ניחוש; טלפון לא תקין נדחה; ולפני היצירה בפועל הכלי מחזיר תצוגה מקדימה של כל הפרטים ומחייב אישור מפורש של הנציג — בלי האישור לא נוצר דבר. יצירה כפולה נחסמת (idempotency), הפעולה מוגנת בהרשאת יצירת משלוחים, סוכן יכול לפתוח רק ללקוחות שלו, והמשלוח נרשם על שם מי שפתח אותו. 19 טסטים מאמתים שאף מסלול לא יוצר משלוח בלי פרטים מלאים ואישור.
- העוזר פותח משלוח חדש מהצ'אט — ברקוד ליונוויל אמיתי, דרך צנרת הקליטה הקיימת
- הכלי מסרב ליצור כל עוד חסר שדה חובה, ומפרט לנציג בדיוק מה חסר — בלי השלמות מהדמיון
- תצוגה מקדימה + אישור מפורש של הנציג לפני היצירה בפועל
- שם לקוח מעורפל מחזיר מועמדים לבחירה; טלפון לא תקין נדחה; יצירה כפולה נחסמת
- מוגן בהרשאת יצירת משלוחים; סוכן מוגבל ללקוחותיו; המשלוח נרשם על שם הפותח
v01.217.000חדשבוט תפעולי / מנוע התרחישיםminorתרחיש חדש: טענת אי-מסירה — הבוט מנהל בירור מול הנמען, השליח והשולח
נבנה תרחיש בוט חדש (ניתן להפעלה ב-/settings/bot-scenarios, כבוי כברירת מחדל): כשלקוח מדווח בקבוצתו שהנמען טוען שלא קיבל משלוח שמסומן כנמסר — הבוט לעולם אינו עונה 'המשלוח כבר נמסר' (תשובה מבטלת ושגויה), אלא פותח בירור פעי…
פרטים נוספים ↓הסתר ↑
נבנה תרחיש בוט חדש (ניתן להפעלה ב-/settings/bot-scenarios, כבוי כברירת מחדל): כשלקוח מדווח בקבוצתו שהנמען טוען שלא קיבל משלוח שמסומן כנמסר — הבוט לעולם אינו עונה 'המשלוח כבר נמסר' (תשובה מבטלת ושגויה), אלא פותח בירור פעיל מול שלושת הצדדים: שולח לנמען בקשת אישור קבלה בתבנית Meta מאושרת, מבקש מהשליח לברר דחוף, ומאשר לשולח. תשובת השליח מועברת לשולח בניסוח מדוד ולא כציטוט — בתרחיש רגיש כזה העברת טקסט גולמית עלולה להעביר האשמות. הנמען הוא המכריע: אישר שקיבל — הפניה נסגרת אוטומטית מול השולח והשליח; הכחיש — הבירור מול השליח נמשך. תמונת הוכחת מסירה שהשליח שולח מועברת לשולח, ולנמען אם הצ'אט איתו פעיל. הזיהוי דטרמיניסטי ונבנה מ-12 דוגמאות חיות שהצוות תייג דרך כפתור 'שייך לתרחיש' (12/12 זיהוי, 0 שגיאות-שווא). להפעלה נדרשת תבנית Meta מאושרת המסומנת 'תבנית בדיקת מסירה' בהגדרות → הודעות → תבניות.
- תרחיש רשום עם toggle, כבוי כברירת מחדל (opt-in per-tenant)
- זיהוי דטרמיניסטי שנבנה מ-12 דוגמאות חיות מתויגות — 12/12 recall, 0 false-positives; תלונת-איחור בגוף ראשון/שני ('אמרתי שלא הגיע') וייחוס עם 'עדיין' מנותבים לצפי ולא לטענת אי-מסירה
- לעולם לא עונה 'כבר נמסר' — הנמען מוכרע ישירות מול עצמו בתבנית Meta מאושרת
- תשובת השליח מועברת לשולח בניסוח מדוד ומסונן (לא ציטוט) — ללא האשמות וללא מידע פנימי
- אישור הנמען סוגר את הפניה אוטומטית מול השולח והשליח; הכחשה ממשיכה את הבירור
- העברת הוכחת מסירה חוצת-ספקים: לשולח תמיד, ולנמען אם הוא בתוך חלון 24 השעות של Meta
- תמונה מועברת ללקוח רק כשהיא משויכת חד-משמעית למשלוח (ציטוט השאלה או ברקוד בכיתוב) — בקבוצת שליח יש תמונות של לקוחות אחרים, והעברה שגויה הייתה חושפת משלוח של לקוח אחר
- כשאין צ'אט לשליח (קבלן חיצוני) או תבנית מאושרת — שאר הרגליים עדיין רצות והצוות מקבל פתק מפורש
v01.215.000חדשעוזר AI פנימיminorעוזר AI — דירוג רווחיות לקוחות אמיתי (כל הלקוחות, לא מדגם)
בשיחת אמת (15/07) נשאל העוזר 'מי הלקוח הכי רווחי שלנו?' וענה 'בוודאות' על סמך דגימה של 10 לקוחות שרירותיים (מתוך 423) — והכריז על לקוח שהרווח האמיתי ממנו נמוך פי 13 מהלקוח הרווחי באמת.
פרטים נוספים ↓הסתר ↑
בשיחת אמת (15/07) נשאל העוזר 'מי הלקוח הכי רווחי שלנו?' וענה 'בוודאות' על סמך דגימה של 10 לקוחות שרירותיים (מתוך 423) — והכריז על לקוח שהרווח האמיתי ממנו נמוך פי 13 מהלקוח הרווחי באמת. נוסף כלי getCustomerProfitability: דירוג מצרפי אחד (GROUP BY) של כל הלקוחות לפי רווח מוערך / הכנסה / כמות משלוחים, עם סינון תאריכים ו-top-N, באותה סמנטיקה פיננסית של הסיכום הקיים (הכנסה על כל המשלוחים לפי קליטה; רווח על שהושלמו ותומחרו בלבד). ההנחיות אוסרות במפורש דירוג ע"י דגימת לקוחות בודדים, ונוספה תזכורת להשוות תאריך אירוע לתאריך הנוכחי לפני תיוג 'היום'/'אתמול' (מסירה מהבוקר תויגה 'אתמול'). מוגן בהרשאת פיננסים. אומת מול נתוני הפרודקשן.
- כלי חדש getCustomerProfitability — 'מי הלקוח הכי רווחי' נענה מדירוג כל הלקוחות, לא ממדגם
- מיון לפי רווח / הכנסה / כמות משלוחים + סינון תאריכים + top-N
- איסור מפורש על דירוג באמצעות דגימת לקוחות בודדים
- תיוג 'היום'/'אתמול' מושווה לתאריך הנוכחי לפני שנכתב
v01.214.000חדשבוט תפעולי / תיבת הודעות עסקיתminorשיוך הודעות לתרחישים — צבירת דאטהסט מתויג לבניית תרחישי בוט חדשים
בנוסף לכפתור 'דיווח על כשל בוט', נוסף בתיבת ההודעות כפתור 'שייך לתרחיש' על כל הודעה.
פרטים נוספים ↓הסתר ↑
בנוסף לכפתור 'דיווח על כשל בוט', נוסף בתיבת ההודעות כפתור 'שייך לתרחיש' על כל הודעה. הצוות מתייג הודעה כדוגמה של תרחיש — קיים או 'מוצע' (כזה שעדיין לא נבנה) — וכך נצבר דאטהסט מתויג של מקרים אמיתיים. זה נחוץ לתרחישים 'רכים' שאי-אפשר לזהות במילות-מפתח (למשל 'טוען שלא הגיע למרות שמסומן הושלם'): צוברים דוגמאות חיות ומאפיינים על בסיסן. התיוגים נאספים בלבד — הם אינם משנים את התנהגות הבוט אוטומטית. הסקירה, ניהול קטלוג התרחישים המוצעים, וייצוא הדאטהסט מתבצעים בקונסולת הפלטפורמה (/admin/דוגמאות תרחישים), פלטפורמה-רחב כמו דיווחי-הכשל. תפריט הלחיצה-הארוכה על הודעה שופר למובייל: לחיצה ארוכה כבר לא מסמנת את טקסט ההודעה (חסימת בחירה/callout במובייל בלבד), והתפריט לא נחתך כשההודעה נמוכה בצ'אט (collisionPadding — נדחף למעלה במקום להיחתך).
- כפתור 'שייך לתרחיש' פר-הודעה בתיבה, עם קטלוג מחופש (תרחישים קיימים + מוצעים) והערה חופשית
- קטלוג תרחישים מוצעים מנוהל בקונסולה (שם + מזהה + תיאור), בלי לגעת בקוד
- מסך סקירה פלטפורמה-רחב עם ספירת דוגמאות לכל תרחיש, אישור/דחייה, וייצוא JSON של הדאטהסט
- התיוגים נצברים בלבד — אין שינוי התנהגות אוטומטי של הבוט
v01.213.003תיקוןבוט תפעולי / מנוע התרחישיםתשובת לקוח בציטוט שאינה תשובה אמיתית כבר לא מועברת לקבלן כ"כתובת/הנחיה"
בקבוצת טאצ' הבוט שאל את הלקוח על כתובת נכונה, והלקוח ענה בציטוט "@מזכירה בדיקה מחר בבקשה" (האצלה, לא כתובת) — והבוט העביר את זה לקבלן כ"כתובת מתוקנת" והשיב "קיבלנו, מטפלים".
פרטים נוספים ↓הסתר ↑
בקבוצת טאצ' הבוט שאל את הלקוח על כתובת נכונה, והלקוח ענה בציטוט "@מזכירה בדיקה מחר בבקשה" (האצלה, לא כתובת) — והבוט העביר את זה לקבלן כ"כתובת מתוקנת" והשיב "קיבלנו, מטפלים". השורש: תשובה בציטוט (swipe-reply) זיהתה נכון את הגישור אך עקפה את שער הרלוונטיות, ולכן כל טקסט הועבר מילולית. מעכשיו תשובה מצוטטת לגישור שממתין ללקוח (אין-מענה/טלפון/כתובת) עוברת גם את שער הרלוונטיות; אישור-מספר-טלפון דטרמיניסטי ב-wrong_phone עדיין מדלג, וכשאין תקציב LLM נשמרת ההתנהגות החינמית הישנה. תוקן גם ה-ack המטעה (נדחה לפני העברת ההודעה).
v01.213.002חדשמשלוחים / סריקהחלון תצוגה גדול בקליטה במחסן (דסקטופ) — אזור הפצה בענק וסיווג יעד
בדף הסריקה, במצב קליטה במחסן בדסקטופ (סורק USB), כל סריקה פותחת חלון תצוגה גדול עם ברקוד המשלוח, שם הלקוח והכתובת, אזור ההפצה באותיות ענק ותג סיווג היעד (רגיל/חריג לפי סיווג הישובים כולל התאמות פר-חברה).
פרטים נוספים ↓הסתר ↑
בדף הסריקה, במצב קליטה במחסן בדסקטופ (סורק USB), כל סריקה פותחת חלון תצוגה גדול עם ברקוד המשלוח, שם הלקוח והכתובת, אזור ההפצה באותיות ענק ותג סיווג היעד (רגיל/חריג לפי סיווג הישובים כולל התאמות פר-חברה). החלון לא עוצר את רצף הסריקות — הקלט נשאר בסורק, וכל סריקה חדשה מחליפה את התוכן. סריקה שנכשלה מציגה את השגיאה בגדול באותו חלון. סגירה ב-Esc, בכפתור או בקליק מחוץ לחלון. במובייל (סריקת מצלמה) ההתנהגות ללא שינוי. בנוסף, גזירת אזור ההפצה בכל דף הסריקה (קליטה, שיבוץ ופעולות מרובות) יושרה למנגנון של התראות טעויות המיון: זיהוי ישוב מודע ל-aliases (resolveSettlement), קריאת האזור מהשדה החי שנערך ב-UI (ולא מטבלת מיפוי שלא מתעדכנת), region_str מליונוויל כ-fallback לישוב לא ממופה, ובדיקת טעות מיון בסריקת שיבוץ עם אותו כלל החלטה בדיוק (evaluateDriverZoneAllowance) — כך שסריקה, אזהרת שיבוץ מקדימה והתראות חיות מסכימים תמיד. כמו כן, סריקה במצב 'חיפוש משלוח' מזהה עכשיו גם מזהה חיצוני ומזהה משוגר (מספרי משימה של קבלן/שותף) — כמו בחיפוש הגלובלי: דף המשלוח פותר קוד שלא נמצא כברקוד גם מול הסיומת של חבילה וגם מול המזהים החיצוניים.
v01.213.001תיקוןבוט תפעולי / מנוע התרחישיםהעברת עדכון-לקוח לשליח לא מצטטת עוד הודעה על משלוח אחר כשהמשלוח זוהה בניחוש
בקבוצת יצחק הפצה השליח כתב "26157230 לא זמין", אך 26157230 אינו משלוח שלו — ולכן הבוט זיהה את המשלוח הפתוח הבודד שלו (26133284) בניחוש.
פרטים נוספים ↓הסתר ↑
בקבוצת יצחק הפצה השליח כתב "26157230 לא זמין", אך 26157230 אינו משלוח שלו — ולכן הבוט זיהה את המשלוח הפתוח הבודד שלו (26133284) בניחוש. התשובה הייתה נכונה, אבל הודעת ההעברה-חזרה לשליח ("לגבי משלוח 26133284, הלקוחה מאשרת להשאיר מחוץ לבית") ציטטה את הודעת ה-"26157230" — שנוקבת במספר אחר ומבלבלת. מעכשיו הציטוט של דיווח-המקור מושמט כשהמשלוח זוהה בניחוש (הדיווח נקב במספר שונה מזה שנפתר); דיווח ללא מספר או עם מספר תואם עדיין מצטט כרגיל. חל על אין-מענה וטלפון-שגוי (צפי דורש ברקוד מפורש, לא מושפע).
v01.213.000שיפורסוכנים / פיננסיםminorיישור חישוב חיוב לקוחות ועמלות סוכן לדוח החיוב של ליונוויל
בעקבות השוואה ברמת הברקוד מול דוחות חיוב אמיתיים של ליונוויל, שיטת החישוב של דוח עמלות הסוכן ושל רווחיות הלקוח (P&L) יושרה לשיטה של ליונוויל בשלושה מישורים: (1) הספירה היא חבילות ולא משימות — משלוח דו-חבילתי נספר פעמיים …
פרטים נוספים ↓הסתר ↑
בעקבות השוואה ברמת הברקוד מול דוחות חיוב אמיתיים של ליונוויל, שיטת החישוב של דוח עמלות הסוכן ושל רווחיות הלקוח (P&L) יושרה לשיטה של ליונוויל בשלושה מישורים: (1) הספירה היא חבילות ולא משימות — משלוח דו-חבילתי נספר פעמיים בעמודת 'כמות חבילות', והעמלה הקבועה/מרווח מוכפלת במספר החבילות; (2) משלוחים שבוטלו או נכשלו (ולא נמסרו) אינם מחויבים ואינם מזכים בעמלה — כמו בליונוויל; (3) הייחוס לחודש הוא לפי תאריך האיסוף בפועל שליונוויל מדווח (delivered_at של ביקור האיסוף) במקום זמן עיבוד ה-webhook — משלוח שנאסף ב-30 בחודש בערב וה-webhook שלו התעבד אחרי חצות מיוחס לחודש הנכון. בוצע backfill היסטורי: 393 חותמות יושרו לתאריך האיסוף, ו-66,764 משלוחים ותיקים שנעדרו לגמרי מהדוחות (חסרה להם חותמת commissionableAt מלפני שהעמודה נוספה) קיבלו חותמת מתאריך המסירה. הכרת ההכנסה ב-P&L עברה מ'תאריך קליטה' (delayClockStartedAt) לאותו בסיס איסוף — כך הכנסה, עמלת סוכן וחיוב ליונוויל נופלים כולם באותו חודש.
- 'כמות חבילות' בדוח הסוכן = Σ חבילות, זהה ל'מספר חבילות' בדוח ליונוויל
- עמלה לחבילה כפשוטה: משלוח דו-חבילתי מזכה בעמלה כפולה
- משלוחים שבוטלו/נכשלו ולא נמסרו — לא מחויבים ולא מזכים בעמלה
- ייחוס לחודש לפי תאריך האיסוף של ליונוויל — נפתרו פערי חצות בגבול חודש
- backfill: 393 תיקוני ייחוס + 66,764 משלוחים היסטוריים שחזרו לדוחות
- P&L רווחיות לקוח מוכר הכנסה לפי אותו בסיס — עקביות מלאה מול ליונוויל
- תוקן: התוספות האוטומטיות (יעד חריג / גוביינא) מתעלמות מכללי המחירון — תיקון תעריף שהוגדר ככלל מתאריך (למשל יעד חריג ₪35→₪3) לא הגיע לתוספת המוחתמת והמשלוח חויב בתעריף הישן; מעכשיו התעריף נפתר דרך הכללים לפי תאריך האיסוף, ו-30 משלוחים ב-5 לקוחות תוקנו רטרואקטיבית
- חדש: כרטיס 'פירוט חיובים' בדף הלקוח — שורה לכל משלוח מחויב בחודש (תאריך איסוף, נמען, יעד, חבילות, מחיר עם פירוק תוספות) וסיכום עם מע"מ; הורדה כ-Excel ושליחה ללקוח במייל ממותג עם הקובץ מצורף — אותה שיטת ספירה של דוח ליונוויל, מאחורי הרשאת פיננסים
- חדש: טאב 'חיוב לקוחות' בפיננסים — טבלה חודשית עם שורה לכל לקוח (משלוחים, חבילות, לפני מע"מ, מע"מ, סה"כ), פירוט נפתח לכל לקוח, הורדת אקסל ושליחת המייל ישירות מהשורה, שורת סיכום, חיפוש, והתראה על לקוחות עם משלוחים ללא פרופיל מחירון שהחיוב שלהם אינו מוכר
- זיכויים בדוחות החיוב: תעודות זיכוי מאושרות (לפי חודש החיוב שלהן) מופיעות כשורות שליליות בדוח הפר-לקוח (כרטיס, אקסל ומייל) ובעמודת 'זיכויים' בטבלת חיוב הלקוחות — הסיכום הוא חיובים − זיכויים לפני מע"מ; זיכוי גדול מהחיוב מציג סכום שלילי, ולקוח עם זיכוי בלבד מקבל שורה גם ללא משלוחים
v01.212.001חדשמשלוחים / פורטל / סוכניםעמודת "סוג יעד" (רגיל/חריג) וסינון לפי מועדי הפצה — בכל טבלאות המשלוחים
בכל טבלאות המשלוחים במערכת נוספה עמודת "סוג יעד" שמציגה לכל משלוח האם עיר היעד היא יעד רגיל (עד 3 ימי הפצה, תג ירוק) או יעד חריג (עד 7 ימי הפצה, תג כתום) — לפי אותו סיווג ישובים שמשמש את בודק היעדים ואת תמחור תוספת יעד ח…
פרטים נוספים ↓הסתר ↑
בכל טבלאות המשלוחים במערכת נוספה עמודת "סוג יעד" שמציגה לכל משלוח האם עיר היעד היא יעד רגיל (עד 3 ימי הפצה, תג ירוק) או יעד חריג (עד 7 ימי הפצה, תג כתום) — לפי אותו סיווג ישובים שמשמש את בודק היעדים ואת תמחור תוספת יעד חריג, כולל התאמות פר-חברה. לצידה נוסף ציר סינון "סוג יעד" (יעד רגיל / יעד חריג) שרץ בצד השרת וחל על כל התוצאות והייצוא לאקסל. הפריסה: פורטל הלקוחות (עמודה + בורר בסרגל), טבלת המשלוחים הראשית (עמודה ליד עיר היעד + קטגוריה בפילטרים, כולל התאמת ספירות ה-facets והכנסת שורות חיות מ-SSE), יעד שבת ויעד אקספרס (אותה טבלה משותפת + סינון מקומי + עמודה בייצוא לאקסל), ודוח עמלות הסוכן (תג ליד כל משלוח בכרטיס העמלות — גם בתצוגת האדמין וגם בדשבורד הסוכן — ועמודה בגיליון המשלוחים של ייצוא האקסל). עיר שלא זוהתה ברשימת הישובים מוצגת עם "—" ואינה נכללת באף אחד מהסינונים.
- תג ירוק "רגיל" (עד 3 ימי הפצה) / כתום "חריג" (עד 7) בכל טבלאות המשלוחים
- סינון שרת לפי סוג יעד — חל על עימוד, ספירות ותוצאות הייצוא
- פרוס בפורטל הלקוחות, בטבלה הראשית, ביעד שבת, ביעד אקספרס ובדוח עמלות הסוכן
- עיר לא מזוהה מוצגת "—" ולא נכללת באף סינון — בלי ניחושים
v01.212.000חדשאינטגרציות / חנויותminorייבוא הזמנות אישופ — משלוחים אמיתיים בליונוויל + בורר סטטוסים ידידותי
ייבוא ההזמנות מחנויות אישופ שוכתב מהיסוד כך שהוא עובד כמו האינטגרציה של WooCommerce.
פרטים נוספים ↓הסתר ↑
ייבוא ההזמנות מחנויות אישופ שוכתב מהיסוד כך שהוא עובד כמו האינטגרציה של WooCommerce. שתי בעיות תוקנו: (1) הפרטים אבדו — מבנה התשובה האמיתי של getorder עוטף כל סקציה במערך ({Order:[..], ShippingAddress:[..], BillingAddress:[..], Products:[..]}), והקוד קרא רק את כותרת ההזמנה. כעת הקליינט מנרמל את המבנה נכון, וה-mapper מחלץ שם נמען, טלפון (עם נפילה חכמה לכתובת החיוב כשכתובת המשלוח ריקה), כתובת מלאה, מייל ופריטים — כולל ניקוי HTML משמות מוצרים וסינון שורות הנחה/משלוח. (2) לא היה שידור לליונוויל — ההזמנות נשמרו כשורות מקומיות מתות עם ברקוד מזויף. כעת הייבוא עובר דרך אותו צינור משותף של יצירת משלוח (createShipmentForTenant): שידור אמיתי לליונוויל, ברקוד אמיתי, פריטים עם מחירים, ודדופ אטומי כמו ב-WooCommerce. בנוסף נוסף בורר סטטוסים ידידותי: במקום להקליד קודים מספריים, המשתמש טוען את רשימת הסטטוסים האמיתית של החנות (עם השמות בעברית ומספר ההזמנות בכל סטטוס) ומסמן בצ'קבוקסים אילו ייובאו — רק הזמנות בסטטוסים שנבחרו יישלחו לליונוויל. הסינון נעשה בצד שיפנסט (קריאת API אחת ללא תלות במספר הסטטוסים) כדי לחסוך במכסת ה-API של החנות. גם סטטוס 'נמסר' לעדכון חזרה נבחר כעת מרשימה במקום קוד.
- getorder מנורמל נכון — נמען, טלפון, כתובת, מייל ופריטים נחלצים סוף-סוף
- טלפון נופל אוטומטית לכתובת החיוב כשכתובת המשלוח ריקה
- ניקוי HTML משמות מוצרים + סינון שורות הנחה (מחיר שלילי)
- שידור אמיתי לליונוויל דרך createShipmentForTenant — ברקוד אמיתי + פריטים, כמו WooCommerce
- דדופ אטומי (claim row) מונע יצירת שתי משימות ליונוויל לאותה הזמנה
- בורר סטטוסים בצ'קבוקסים עם השמות בעברית ומספרי ההזמנות — במקום קודים
- סינון סטטוסים בצד שיפנסט — קריאת API אחת בלבד, חוסך במכסת החנות
v01.211.001תיקוןאינטגרציות / חנויותסנכרון אישופ — פתיחת מעטפת התשובה של ה-API
הדיווח המפורט שנוסף אתמול חשף את הצורה האמיתית של תשובות אישופ: רשימת ההזמנות לא מגיעה כמערך אלא עטופה באובייקט מעטפת ({"Order":[...]}).
פרטים נוספים ↓הסתר ↑
הדיווח המפורט שנוסף אתמול חשף את הצורה האמיתית של תשובות אישופ: רשימת ההזמנות לא מגיעה כמערך אלא עטופה באובייקט מעטפת ({"Order":[...]}). הקליינט פותח כעת את המעטפת בכל נקודות הקצה (רשימת הזמנות, הזמנה בודדת, רשימת סטטוסים) — גם בצורות המקבילות האפשריות — וייבוא ההזמנות מחנויות אישופ יוצא סוף-סוף לדרך. בהמשך התגלה שהייבוא עדיין חלקי (חסרים פרטי נמען/כתובת/פריטים ואין שידור לליונוויל) — נוסף route אבחון פנימי (platform-only, קריאה בלבד) לשליפת המבנה הגולמי האמיתי של getorder כדי לתקן את המיפוי נכון, וחיבור אישופ של חנות 'שליח' הוקפא זמנית עד שהייבוא יותאם למודל של WooCommerce.
v01.211.000חדשפורטל לקוחות / חנויותminorחיבורי חנויות בקבוצת לקוחות — בחירה לאיזה לקוח ישויכו ההזמנות
עד היום חיבור חנות (WooCommerce, קונימבו, אישופ וכו') נקשר אוטומטית וללא בחירה ללקוח-הבית של המשתמש שיצר אותו — בקבוצת לקוחות מקושרים (לקוח-אב עם לקוחות-בנים) לא הייתה שום דרך לקבוע שההזמנות ייכנסו ללקוח אחר בקבוצה, וכל …
פרטים נוספים ↓הסתר ↑
עד היום חיבור חנות (WooCommerce, קונימבו, אישופ וכו') נקשר אוטומטית וללא בחירה ללקוח-הבית של המשתמש שיצר אותו — בקבוצת לקוחות מקושרים (לקוח-אב עם לקוחות-בנים) לא הייתה שום דרך לקבוע שההזמנות ייכנסו ללקוח אחר בקבוצה, וכל ההזמנות זרמו ללקוח-האב. כעת, כשלמשתמש יש גישה ליותר מלקוח אחד: דיאלוג חיבור חנות חדשה כולל בורר "ההזמנות ישויכו ללקוח" (ברירת מחדל: הלקוח הנוכחי), עריכת חיבור קיים מאפשרת להעביר אותו ללקוח אחר בקבוצה (משפיע על הזמנות חדשות בלבד — משלוחים קיימים נשארים אצל הלקוח הקודם), כרטיס כל חנות מציג תג עם שם הלקוח שאליו היא משויכת, ורשימת החנויות מציגה את כל חיבורי הקבוצה שהמשתמש מורשה להם — לא רק את של לקוח-הבית שלו. הבחירה נאכפת גם בשרת: שיוך מותר רק ללקוח בתוך הקבוצה המקושרת של המשתמש ובכפוף להגבלות הצפייה שלו (scopedCustomerIds), וכל פעולות החנות (עריכה, מחיקה, בדיקת חיבור, רישום webhook, גילוי שיטות משלוח) כובדו את אותה הרשאה קבוצתית.
- בורר לקוח בחיבור חנות חדשה — ההזמנות נכנסות ללקוח שנבחר, לא אוטומטית ללקוח-האב
- עריכת חיבור מאפשרת להעביר חנות ללקוח אחר בקבוצה (הזמנות חדשות בלבד)
- תג שם הלקוח על כל כרטיס חנות כשיש יותר מלקוח אחד בקבוצה
- רשימת החנויות כוללת את כל חיבורי הקבוצה שהמשתמש מורשה להם
- אכיפה בשרת: שיוך רק בתוך הקבוצה המקושרת ובכפוף ל-scopedCustomerIds
v01.210.007תיקוןאינטגרציות / חנויותסנכרון אישופ — פענוח סובלני לתשובות ה-API אחרי הסרת חסימת Cloudflare
אחרי שאישופ הסירו את חסימת ה-Cloudflare (הלבנת ה-IP הושלמה מולם ב-14.7), הסנכרון האוטומטי הגיע לראשונה לתשובות אמיתיות מה-API שלהם — ונפל על צורת המענה: השרת שלהם (ASP קלאסי) עשוי להחזיר JSON עטוף בתוך מחרוזת (קידוד כפול…
פרטים נוספים ↓הסתר ↑
אחרי שאישופ הסירו את חסימת ה-Cloudflare (הלבנת ה-IP הושלמה מולם ב-14.7), הסנכרון האוטומטי הגיע לראשונה לתשובות אמיתיות מה-API שלהם — ונפל על צורת המענה: השרת שלהם (ASP קלאסי) עשוי להחזיר JSON עטוף בתוך מחרוזת (קידוד כפול), והקוד ציפה למערך ישירות ('t.map is not a function'). מעכשיו הקליינט פותח עטיפת קידוד-כפול אוטומטית, ורשימות (getorderlist / getstatuslist) שמגיעות בצורה לא-צפויה מדווחות שגיאה עם קטע מהתוכן האמיתי שחזר — כך שהלוג הבא יגיד בדיוק מה השרת שלח במקום שגיאת JavaScript אטומה.
v01.210.006תיקוןבוט תפעולי / מנוע התרחישיםכתובת שגויה — הבוט שואל את השליח על איזה משלוח מדובר במקום לנחש
תרחיש "כתובת שגויה" מעדכן כתובת ומסנכרן לליונוויל — ולכן ניחוש שגוי משחית משלוח אמיתי.
פרטים נוספים ↓הסתר ↑
תרחיש "כתובת שגויה" מעדכן כתובת ומסנכרן לליונוויל — ולכן ניחוש שגוי משחית משלוח אמיתי. באירוע (אלעזר צדוק) השליח דיווח על כתובת שגויה בלי לנקוב במספר משלוח, המדבקה נשלחה 18 דקות קודם (מעבר לחלון השחזור), והבוט ניחש את המשלוח הפתוח הבודד של השליח (26051512) במקום זה שעליו דיבר (26164296). מעכשיו התרחיש לעולם לא מנחש: כשהדיווח אינו נוקב במשלוח מזוהה, הבוט שואל את השליח "לגבי איזה משלוח מדובר? שלחו מספר", וכשהשליח עונה בברקוד — הבוט מזהה אותו (מוודא שהוא של השליח) וממשיך לשאול את הלקוח על הכתובת. אם נוקב בברקוד סגור/לא-שלו — נשאר שקט כמו קודם. שאר התרחישים (אין מענה/טלפון/צפי) ללא שינוי. עבר ביקורת אדוורסרית (הוסר מסלול דטרמיניסטי שחשף את broadcast לשידור-שווא; חוזק שער הרלוונטיות להבחין בין מספר-משלוח-כתשובה לבין דיווח סטטוס).
v01.210.005שיפורלקוחות / תיאום איסופיםתיאום איסופים — גישה לסוכני לקוחות (תצוגה בלבד) ופילטר סטטוס
עמוד 'תיאום איסופים' נפתח כעת גם לסוכני לקוחות, מסונן אוטומטית ללקוחות המשויכים אליהם בלבד (כמו בטבלת הלקוחות).
פרטים נוספים ↓הסתר ↑
עמוד 'תיאום איסופים' נפתח כעת גם לסוכני לקוחות, מסונן אוטומטית ללקוחות המשויכים אליהם בלבד (כמו בטבלת הלקוחות). לסוכן זו תצוגה בלבד — כפתורי שליחת שאלת הבוקר (לכולם ולשורה בודדת) והגדרות התזמון מוסתרים ממנו. בנוסף, כרטיסי הסיכום בראש הדף הפכו לפילטר סטטוס: לחיצה על כרטיס מסננת את הטבלה לאותו סטטוס (לחיצה חוזרת או 'הכל' מבטלת). הפילטר מאותחל אוטומטית ל'יש איסוף' — הסטטוס שהכי רלוונטי בבוקר. בנוסף עוצב הדף מחדש למובייל כך שהטבלה תופסת את מרבית גובה המסך: הוסרו הכותרת והתיאור, כרטיסי הסיכום הפכו לצ'יפים דקים בשורה אחת (גלילה אופקית), הכפתורים צומצמו לשורה אחת (הגדרות כאייקון בלבד), ובורר התאריך הפך לסגמנט מחובר 'אתמול | היום | מחר' (מאותחל להיום) עם אייקון לוח-שנה מחובר לבחירת תאריך אחר, בסגנון בוררי התאריכים במערכת. תוקן גם שהדף הופיע לסוכן בסיידבר אך לא נפתח — ה-middleware חסם את הנתיב (לא היה ברשימת ההרשאות של תפקיד הסוכן); כעת הנתיב מורשה, בעוד פעולות השליחה נשארות חסומות ברמת ה-API.
v01.210.004תיקוןבוט תפעולי / תיבת הודעות עסקיתתשובת צפי בציטוט של בוקר-אחרי מגיעה ללקוח; תוקנה שחיתות שהציגה ציטוטים על הערות פנימיות
קבלן ענה בבוקר "צפוי היום" בציטוט לשאלת צפי מהערב הקודם — והלקוח לא עודכן, כי גישור הצפי פג אחרי 6 שעות.
פרטים נוספים ↓הסתר ↑
קבלן ענה בבוקר "צפוי היום" בציטוט לשאלת צפי מהערב הקודם — והלקוח לא עודכן, כי גישור הצפי פג אחרי 6 שעות. שני תיקונים: פקיעת גישור צפי הוארכה ל-24 שעות (כמו כל אחיו), וציטוט מפורש של שאלה מחייה גם גישור שכבר פג (עד 3 ימים; רק EXPIRED — לעולם לא כפל-העברה). בנוסף תוקנה שחיתות דאטה: מנגנון ההשלמה של הודעות יוצאות חתם מזהי-ספק על הערות פנימיות (שלעולם לא נשלחות) — ולכן תשובת הקבלן הוצגה ב-inbox כמצטטת הערה פנימית על משלוח אחר. הסינון תוקן (הערות פנימיות מוחרגות + חלון-טריות של 15 דקות), ו-15 הערות שכבר נפגעו נוקו.
v01.210.003תיקוןתיבת הודעות עסקיתתיבת הודעות עסקית — בועות ההודעות שלנו כבר לא נחתכות במובייל בצ'אטים עם תמונות
בהמשך לתיקון הכותרת: בחלק גדול מהצ'אטים ההודעות היוצאות (הירוקות) גלשו מהמסך או נחתכו במובייל.
פרטים נוספים ↓הסתר ↑
בהמשך לתיקון הכותרת: בחלק גדול מהצ'אטים ההודעות היוצאות (הירוקות) גלשו מהמסך או נחתכו במובייל. השורש — רכיב הגלילה של Radix עוטף את התוכן ב-div עם display:table שנמתח לפי רוחב התוכן: תמונה אחת (למשל צילום מדבקה) ברוחבה הטבעי הרחיבה את כל קנבס הצ'אט מעבר למסך, וההודעות היוצאות — המיושרות לקצה הנגדי — נדחפו החוצה, בעוד הודעות הלקוח נראו תקינות. הוחל אותו תיקון שכבר קיים ברשימת הצ'אטים (block במקום table) גם על אזור ההודעות.
v01.210.002שיפורלקוחות / תיאום איסופיםתיאום איסוף יומי — אזהרה בולטת בהפעלה מרובה כשאין קבוצת תשובות
בעקבות מקרה אמיתי: התכונה הופעלה ל-108 לקוחות בלי לבחור קבוצת תשובות — השאלות נשלחו והלקוחות ענו, אבל התשובות הגיעו רק לטבלת תיאום האיסופים ואף אחת מהן לא הופיעה בוואטסאפ, מה שנראה כאילו 'לא נשלחו הודעות'.
פרטים נוספים ↓הסתר ↑
בעקבות מקרה אמיתי: התכונה הופעלה ל-108 לקוחות בלי לבחור קבוצת תשובות — השאלות נשלחו והלקוחות ענו, אבל התשובות הגיעו רק לטבלת תיאום האיסופים ואף אחת מהן לא הופיעה בוואטסאפ, מה שנראה כאילו 'לא נשלחו הודעות'. דיאלוג ההפעלה המרובה מציג כעת אזהרה כתומה בולטת כשלא נבחרה קבוצה ולחלק מהלקוחות שנבחרו אין קבוצת תשובות קיימת, עם הסבר מפורש שהתשובות יגיעו רק לטבלה. בנוסף תוקן דף תיאום האיסופים: הטבלה לא הייתה נגללת — התוכן נחתך בגובה המסך בלי אפשרות לראות את שאר הלקוחות; כעת הכותרת וכרטיסי הסיכום קבועים והטבלה גוללת בפנים, עם בר עמודים תחתון סטנדרטי כמו בשאר הטבלאות. בנוסף, בתיבת ההודעות של לקוחות הקצה, שאלת הבוקר שיצאה בתבנית Meta הופיעה עד היום כטקסט טכני ('[תבנית Meta: …]') במקום תוכן השאלה — מעכשיו מוצג טקסט השאלה האמיתי (עם שם הלקוח), וכפתורי ה'כן'/'לא' מוצגים כצ'יפים ויזואליים מתחת להודעה (לתצוגה בלבד, ללא אפשרות לחיצה).
v01.210.001תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — דחיית משלוח של שולח אחד כבר לא חוסמת בקשת שידור של שולח אחר באותה קבוצה
בקבוצת בזק, "26134634 לשדר" לא שודר ונדרשה התערבות אנושית: חלון ה-burst של השידור איחד את ההודעה עם "בבקשה להחזיר אלינו" ששלח משתתף אחר רגע קודם, ושומר-הדחייה (שנוסף אתמול כדי שהודעות החזרה לא יפעילו שידור) פסל את הטקסט …
פרטים נוספים ↓הסתר ↑
בקבוצת בזק, "26134634 לשדר" לא שודר ונדרשה התערבות אנושית: חלון ה-burst של השידור איחד את ההודעה עם "בבקשה להחזיר אלינו" ששלח משתתף אחר רגע קודם, ושומר-הדחייה (שנוסף אתמול כדי שהודעות החזרה לא יפעילו שידור) פסל את הטקסט המאוחד כולו. מעכשיו שער השידור שופט כל הודעה בנפרד: דחייה של שולח אחד לא מבטלת בקשה לגיטימית של אחר, הודעה שמכילה בעצמה מילת-שידור לצד ביטול ("אמרתם לבטל שידור") עדיין מושתקת, ומספר מתוך הודעת-החזרה לעולם לא משודר (איסוף המטרות היה פר-הודעה עוד קודם). מכוסה בטסטים עם טקסטי האירוע.
v01.210.000חדשעוזר AI פנימיminorעוזר AI — שומר אמינות אוטומטי, סינון נהג-איסוף ולקוח עסקי, וזיהוי מזהה-ספק
סבב תיקונים בעקבות ניתוח 4 שיחות אמת (07-13/07) שחשפו כשל אמינות חמור: העוזר 'אישר' פעולות שלא ביצע ("✅ ההודעה נשלחה" בלי שום קריאת כלי), הציג טבלת פרטים מומצאת למשלוח, ומיחזר נתוני משלוח קודם על פני חמישה תורות בטענה שק…
פרטים נוספים ↓הסתר ↑
סבב תיקונים בעקבות ניתוח 4 שיחות אמת (07-13/07) שחשפו כשל אמינות חמור: העוזר 'אישר' פעולות שלא ביצע ("✅ ההודעה נשלחה" בלי שום קריאת כלי), הציג טבלת פרטים מומצאת למשלוח, ומיחזר נתוני משלוח קודם על פני חמישה תורות בטענה שקרא מהמערכת. שבעה תיקונים: (1) שומר אמינות דטרמיניסטי בלולאת הסוכן — תשובה שמדווחת ביצוע (✅/נשלח/עודכן) בלי שכלי פעולה רץ באותו תור, או שמציגה נתוני משלוח בלי שום קריאת כלי, נדחית אוטומטית ומוחזרת למודל לתיקון (עם ניקוי הטקסט שכבר הוזרם למסך); כולל סוללת טסטים על ההודעות האמיתיות מהשיחה. (2) סינון חדש לפי נהג איסוף (pickupDriverName) — עד כה driverName תפס רק נהגי מסירה, ולכן על נהג שרק אוסף העוזר ענה בטעות "לא עבד אתמול" ודיווח 10 איסופים כשבפועל היו 88. (3) סינון חדש לפי שם לקוח עסקי (customerName) — חיפוש לקוח דרך query (שמחפש נמענים) החזיר אפסים שגויים. (4) איתור משלוח לפי מזהה-ספק מגלה זאת כעת במפורש (identifierNote) — מספר ספק שהחזיר משלוח עם ברקוד אחר גרם לבלבול קשה בשיחה. (5) רזולוציית מזהים ב-getShipmentDetails/getShipmentCost עברה לעדיפות-ברקוד (מיגור החזרת משלוח שרירותי בהתנגשות ברקוד/מזהה-ספק). (6) הוספת הערת AI למשלוח לפי ברקוד תוקנה (נכשלה בעבר על ברקוד תקין). (7) getCostSummary מחזיר גם עלות ממוצעת לחבילה, ומצהיר במפורש כשהסיכום מכסה את כל התקופה — נגד המצאת "טווח ברירת מחדל". הנחיות עודכנו בהתאם (נהג איסוף/לקוח עסקי, איסור המצאת מדיניות חברה).
- שומר אמינות אוטומטי: דיווח ביצוע ללא פעולה אמיתית או הצגת נתונים ללא קריאת כלי — נדחים ומתוקנים אוטומטית
- סינון נהג איסוף (pickupDriverName) — "מה אסף נהג X אתמול" עובד סוף-סוף (88 איסופים שדווחו כ-10)
- סינון לקוח עסקי ישיר (customerName) — בלי לעבור דרך חיפוש נמענים
- מספר ספק שמאתר משלוח מזוהה ומוצהר (identifierNote) — סוף לבלבול בין מזהה ספק לברקוד
- עלות ממוצעת לחבילה ב-getCostSummary + הצהרה מפורשת של הטווח המכוסה
v01.209.002שיפורתיעודתיעוד: רוחב עמוד רחב יותר וטבלאות שלא נחתכות
שיפור פריסת התיעוד (/docs) במסכי דסקטופ.
פרטים נוספים ↓הסתר ↑
שיפור פריסת התיעוד (/docs) במסכי דסקטופ. עד כה כל מאמר היה כלוא ב-max-w-68ch (~550px) — כך שגם בתוך עמודת התוכן נותר שטח מבוזבז רב, והטבלאות נחנקו ל-550px ואז נחתכו (במיוחד טבלאות פרמטרים עם שם ארוך כמו destinationFloor / destinationApartment / ...). שלושה תיקונים: (1) ה-container הראשי של התיעוד הורחב מ-1400px ל-1600px, מה שמצמצם את השוליים המתים בקצוות ומרחיב את עמודת התוכן. (2) המאמר כבר לא כלוא ב-68ch — הוא ממלא את עמודת התוכן, כך שטבלאות, בלוקי קוד וכרטיסי endpoint מקבלים את מלוא הרוחב; פסקאות הטקסט עצמן נשארות ברוחב קריא (74ch) דרך רכיב ה-Prose. (3) בטבלאות: בוטל ה-white-space:nowrap על שם הפרמטר (שם ארוך עובר שורה במקום להרחיב את העמודה ולחתוך את התיאור), ונוספה גלילה אופקית פנימית בתוך מסגרת הטבלה כרשת ביטחון לטבלאות רחבות במיוחד.
v01.209.001תיקוןרווחיות / עלויות משלוחעלויות משלוח — רשת ביטחון לילית + תיקון שחזור שליח מסירה
המשך לתיקון של היום (עלות מסירה ₪0 בסאב-שליחים אחרי תיוג היסטורי).
פרטים נוספים ↓הסתר ↑
המשך לתיקון של היום (עלות מסירה ₪0 בסאב-שליחים אחרי תיוג היסטורי). נסקרו כל המסלולים שכותבים את שליח-החיוב של ביקור: מסלולי השיבוץ (שיבוץ מרוכז, סריקה, מובייל, AI, broadcast) נוגעים רק בביקורים פתוחים ולכן תקינים, אבל שחזור שליח המסירה מ-POD של ליונוויל — שרץ דווקא על ביקורים שכבר הושלמו — מילא את השליח בלי לחשב את עלות המשלוח מחדש, והמשלוח נשאר בלי עלות לתמיד. תוקן. בנוסף נוספה רשת ביטחון: cron לילי (02:45) שסורק 45 יום אחורה ומאתר כל סנאפשוט עלות שלא תואם את שליח-החיוב של הביקור (או חסר לגמרי) ומחשב אותו מחדש — כך שגם אם מסלול עתידי ישכח לחשב מחדש, המערכת תרפא את עצמה תוך יממה במקום לשקר בדוחות הרווחיות.
v01.209.000שיפורמחירון לקוחות ושליחיםminorעריכה מהירה של מחירון — כל התעריפים במסך אחד, תאריך אחד
עד היום, שינוי מחיר ללקוח או לשליח שכבר יש לו מחירון חייב לעבור דרך מודל נפרד לכל שדה: בחירת סוג פעולה, הקלדת סכום, הקלדת שם כלל (חובה), ובחירת שני תאריכים — ואז שוב מהתחלה לשדה הבא.
פרטים נוספים ↓הסתר ↑
עד היום, שינוי מחיר ללקוח או לשליח שכבר יש לו מחירון חייב לעבור דרך מודל נפרד לכל שדה: בחירת סוג פעולה, הקלדת סכום, הקלדת שם כלל (חובה), ובחירת שני תאריכים — ואז שוב מהתחלה לשדה הבא. שינוי של מסירה + איסוף + גוביינא עלה שלושה מודלים, שלושה שמות ושישה בוררי תאריך. נוסף עורך מהיר בראש סקציית "מחיר נוכחי" בשני הדיאלוגים: טבלה אחת עם כל התעריפים, תאריך תחולה אחד לכל השינויים, ושם שינוי שנוצר אוטומטית מהתאריך (וניתן לעריכה). ממלאים רק את התעריפים שהשתנו ולוחצים "החל שינויים". תא בודד מכסה את כל סוגי הפעולה: 25 = תעריף חדש, +2 = תוספת, -1.5 = הפחתה, +5% = העלאה באחוזים — עם תצוגה מקדימה חיה של המחיר המתקבל. המודל הישן, הכללים לפי לקוח/אזור, מטריצת האזורים, התבניות והייבוא מ-Excel נשארו כפי שהם.
- כל התעריפים בטבלה אחת — במקום מודל נפרד לכל שדה
- תאריך תחולה אחד לכל השינויים, ושם כלל שנוצר אוטומטית
- תא אחד לכל סוגי הפעולה: 25 / +2 / -1.5 / +5%, עם תצוגה מקדימה חיה
- "החל על הכל" — עדכון רוחבי של כל התעריפים בבת אחת (למשל +5%)
- מצב "תיקון בסיס" לתיקון תעריף שהוקלד בטעות — עד היום היה אפשר רק לכסות עליו בכלל
- תיקון: עמודת המחיר הנוכחי שברה שוויון בין כללים חופפים אחרת מהחיוב בפועל, ויכלה להציג מחיר שאינו מחויב
v01.208.003תיקוןתיעודתיקון: כפתור ההעתקה בקטעי קוד בתיעוד דרס את השורה הראשונה
בכל קטעי הקוד בתיעוד (/docs) כפתור "העתק" הצף בפינה העליונה חפף את תחילת השורה הראשונה של הקוד.
פרטים נוספים ↓הסתר ↑
בכל קטעי הקוד בתיעוד (/docs) כפתור "העתק" הצף בפינה העליונה חפף את תחילת השורה הראשונה של הקוד. הסיבה: הדף RTL בעוד שהקוד עצמו dir=ltr, כך שהכפתור (ממוקם לוגית ב-end) נפל בצד שמאל — בדיוק היכן שהקוד מתחיל — וה-<pre> לא שמר מספיק מרווח עליון. נוסף gutter עליון קבוע (pt-9) שמבטיח שהשורה הראשונה תמיד מתחת לכפתור ולתווית השפה, ללא תלות באורך השורה או בכיוון הטקסט.
v01.208.002תיקוןרווחיות / שליחים מנוהליםעלות מסירה ₪0 במשלוחים של סאב-שליחים אחרי תיוג היסטורי
משלוחים שבוצעו בפועל בידי סאב-שליח הציגו בדוח הרווחיות עלות מסירה ₪0 (או עלות לפי המחירון הישן של הסאב) למרות שהמנהל שלו מתומחר כראוי.
פרטים נוספים ↓הסתר ↑
משלוחים שבוצעו בפועל בידי סאב-שליח הציגו בדוח הרווחיות עלות מסירה ₪0 (או עלות לפי המחירון הישן של הסאב) למרות שהמנהל שלו מתומחר כראוי. הסיבה: כפתור 'תיוג היסטורי' בדף מנהל-השליחים שייך למנהל ביקורים ישנים של הסאבים שלו, אבל לא חישב מחדש את סנאפשוט עלות המשלוח — הסנאפשוט נשאר כפי שנשמר ברגע המסירה, כלומר לפי מחירון הסאב (ולסאב לרוב אין מחירון בכלל → ₪0). דוח המנהל החודשי, שמחושב חי מהביקורים, כבר הציג את הסכום הנכון — ולכן שני המספרים סתרו זה את זה. מעכשיו התיוג ההיסטורי מחשב מחדש את העלויות של כל היום/שליח המושפעים, בדיוק כפי שכבר עושה מסלול הניתוק. בנוסף הורצה תיקון נתונים חד-פעמי: 2,017 ביקורים שכבר תויגו בעבר תומחרו מחדש לפי מחירון המנהל הנכון.
v01.208.001שיפורAPI ציבורי / תיעודמדריך: שליפת קישור מעקב לפי מספר משלוח דרך ה-API
המשך לחשיפת קישורי המעקב ב-API.
פרטים נוספים ↓הסתר ↑
המשך לחשיפת קישורי המעקב ב-API. עד כה השליפה הבודדת GET /api/v1/shipments/{barcode} — ה-endpoint הטבעי ל"תן לי את הלינק לפי מספר המשלוח" — לא החזירה את קישור המעקב (רק שליפת הרשימה עשתה זאת). כעת גם היא מחזירה publicId, trackingUrl ו-validationUrl. בנוסף נכתב מדריך מהיר בתיעוד הציבורי (/docs/api) שמראה בשלושה צעדים איך לשלוף את trackingUrl של משלוח לפי הברקוד ולשלוח ללקוח הקצה, עם אזהרה מפורשת לא להרכיב את הקישור מהברקוד ידנית (קישור-ברקוד מצומצם בכוונה). בפורטל, בעמוד הגדרות ה-API, נוסף כרטיס הבלטה שמקשר ישירות למדריך, וקישור אינליין על שורת ה-endpoint הרלוונטי.
- GET /api/v1/shipments/{barcode} מחזיר עכשיו גם publicId/trackingUrl/validationUrl
- מדריך מהיר ב-/docs/api: קישור מעקב לפי מספר משלוח
- קישור למדריך בעמוד הגדרות ה-API בפורטל
v01.208.000תיקוןאבטחה / API ציבוריminorמפתח API של הפורטל יורש את היקף ההרשאה של יוצרו
סגירת פער הרשאות שהתגלה בבדיקת החשיפה החדשה של קישורי המעקב ב-API.
פרטים נוספים ↓הסתר ↑
סגירת פער הרשאות שהתגלה בבדיקת החשיפה החדשה של קישורי המעקב ב-API. משתמש פורטל יכול להיות מוגבל ל-subset מהקבוצה המקושרת (CustomerUser.scopedCustomerIds) — למשל לראות רק שניים מתוך חמישה סאב-לקוחות. עד כה, כשמשתמש כזה יצר מפתח API, המפתח קיבל גישה ל*כל* הקבוצה המקושרת, כי authenticateApiKey בנה את היקף המפתח מ-getAllowedCustomerIds עם scope ריק והתעלם מההגבלה של המשתמש. כלומר משתמש מוגבל יכול היה להרחיב את ההרשאה של עצמו דרך ה-API (בתוך אותו tenant — לא דליפה חוצה-לקוחות, אבל עקיפה של הגבלה מכוונת). כעת ה-scope של היוצר מוקפא על המפתח בזמן היצירה (עמודה חדשה api_keys.scoped_customer_ids), ו-authenticateApiKey מצליב אותו מול הקבוצה המקושרת החיה — כך שהמפתח רואה לכל היותר את מה שיוצרו יכול, ומצטמצם עוד אם לקוח עוזב את הקבוצה. מפתחות קיימים וכן מפתחות של הצוות/tenant נשארים עם scope ריק = גישה מלאה לקבוצה, בדיוק כמו קודם. אומת מקצה לקצה מול קבוצה מקושרת אמיתית: מפתח מלא ראה את כל 4 הלקוחות, מפתח מוגבל ראה רק את הלקוח היחיד שהוגדר לו.
- עמודה חדשה api_keys.scoped_customer_ids — צילום ה-scope של יוצר המפתח
- authenticateApiKey מצליב את ה-scope מול הקבוצה המקושרת החיה — מצמצם, לעולם לא מרחיב
- משתמש פורטל מוגבל כבר לא יכול לייצר מפתח רחב ממנו
- מפתחות קיימים + מפתחות צוות/tenant ללא שינוי (scope ריק = גישה מלאה)
v01.207.003תיקוןתיבת הודעות עסקיתתיבת הודעות עסקית — כותרת הצ'אט במובייל אורגנה מחדש והתוכן כבר לא גולש מהמסך
במובייל, שורת הכותרת של צ'אט פתוח הכילה חמישה צ'יפים בשורה אחת ללא עטיפה (סטטוס טיפול, דף לקוח, ארכיון, "קבוצה", ישויות מקושרות) — הרוחב המינימלי שלהם עלה על רוחב המסך וכל הפאנל נדחף החוצה.
פרטים נוספים ↓הסתר ↑
במובייל, שורת הכותרת של צ'אט פתוח הכילה חמישה צ'יפים בשורה אחת ללא עטיפה (סטטוס טיפול, דף לקוח, ארכיון, "קבוצה", ישויות מקושרות) — הרוחב המינימלי שלהם עלה על רוחב המסך וכל הפאנל נדחף החוצה. מעכשיו במובייל נשארת שורה אחת נקייה בסגנון WhatsApp: חזרה, אווטאר, שם, סטטוס טיפול ותפריט ⋮ שמרכז את הפעולות המשניות (דף לקוח, ארכיון, קישור קבוצה); השליח והלקוח המקושרים עברו לשורת-המשנה מתחת לשם (לחיצה פותחת את דיאלוג הקישור). בדסקטופ הפריסה ללא שינוי. בנוסף נוספה שבירת-מילים לבאנר ההצעות כך שטקסט ארוך ללא רווחים לא ירחיב את הפאנל.
v01.207.002תיקוןמחירון שליחיםמחירון שליח — שמירה נחסמה בגלל כלל ישן שלא נגעו בו
עריכת מחירון של שליח נכשלה בשגיאה 'תאריך ישן מהמותר (45 ימים אחורה)' גם כשהתאריך שנבחר היה לפני ימים ספורים בלבד.
פרטים נוספים ↓הסתר ↑
עריכת מחירון של שליח נכשלה בשגיאה 'תאריך ישן מהמותר (45 ימים אחורה)' גם כשהתאריך שנבחר היה לפני ימים ספורים בלבד. הסיבה: בשמירה נשלחים כל כללי המחירון של השליח, והשרת אכף את מגבלת הרטרואקטיביות על כולם — כולל כללים ותיקים ששמורים במערכת ושלא נגעו בהם. ברגע שכלל קיים 'הזדקן' מעבר לחלון של 45 יום, המחירון של אותו שליח הפך לבלתי-ניתן-לשמירה. מעכשיו המגבלה נאכפת רק על כלל חדש או על כלל שתאריך התחולה שלו שונה בפועל — בדיוק כפי שכבר עובד במחירון הלקוחות.
v01.207.001ייעולוואטסאפ / Meta Cloud APIגרסת ה-Graph API של Meta רוכזה למקום אחד
מספר הגרסה של ה-Graph API של Meta (v21.0) היה כתוב בקשיחות בשמונה קבצים נפרדים — בשליחת ההודעות, בהורדת מדיה, בתמלול הקלטות, בניהול התבניות, בבדיקת התקינות ובבדיקת החיבור — ותחת שני שמות שונים לאותו קבוע.
פרטים נוספים ↓הסתר ↑
מספר הגרסה של ה-Graph API של Meta (v21.0) היה כתוב בקשיחות בשמונה קבצים נפרדים — בשליחת ההודעות, בהורדת מדיה, בתמלול הקלטות, בניהול התבניות, בבדיקת התקינות ובבדיקת החיבור — ותחת שני שמות שונים לאותו קבוע. Meta מוציאה כל גרסת Graph משימוש כשנתיים לאחר יציאתה, כך שביום שבו נצטרך לעלות גרסה היה צריך לרדוף אחרי שמונה מקומות, ומספיק לפספס אחד כדי ששליחות או הורדת מדיה ייפלו בשקט. הכל רוכז ל-lib/messaging/meta-graph.ts שמחזיק את הקבוע היחיד ופונקציית metaGraphUrl לבניית הכתובת; כל אחת מ-11 הקריאות ל-Meta עוברת דרכו. שינוי פנימי בלבד — הכתובות שנשלחות בפועל זהות לחלוטין לקודמות, ואין שינוי בהתנהגות המערכת.
v01.207.000חדשAPI ציבורי / מעקב משלוחיםminorהלינק האישי של הנמען — עכשיו ב-API, ב-webhook ובייצוא לאקסל
המשך ישיר לקישור המעקב לפי ברקוד שנכנס אתמול.
פרטים נוספים ↓הסתר ↑
המשך ישיר לקישור המעקב לפי ברקוד שנכנס אתמול. בבדיקה התברר שהסיבה שלקוחות ביקשו לינק מבוסס-ברקוד לא הייתה שהם רוצים תצוגה מצומצמת — אלא שהברקוד הוא פשוט המזהה היחיד שהיה להם ביד: התשובה של /api/v1/shipments לא החזירה את מזהה המעקב האישי בכלל, ולכן אי אפשר היה לבנות ממנה את הקישור המלא. כעת כל משלוח בתשובת ה-API מחזיר publicId, trackingUrl ו-validationUrl מוכנים לשימוש; אירוע ה-webhook shipment.created מחזיר trackingUrl; ובטבלת המשלוחים נוספה עמודת "לינק מעקב" (מוסתרת כברירת מחדל, מופעלת מתפריט העמודות) שנכללת גם בייצוא לאקסל. כך אפשר לשלוח ללקוח הקצה במייל או ב-SMS את הקישור האישי המלא — עם הכתובת, המפה ואפשרות עדכון פרטי המסירה — במקום להסתפק בקישור הברקוד המצומצם. במקביל, לוגיקת בניית הקישורים (איזה מזהה פותח איזה עמוד) רוכזה ל-lib/shipments/public-links.ts אחרי שהתגלה שהיא שוכפלה בשלושה מקומות שכבר הספיקו להיפרד זה מזה — אחד מהם בנה קישור עדכון-פרטים מהברקוד, קישור שהמערכת לא יכולה לפתוח. התיעוד הציבורי עודכן בהתאם.
- GET /api/v1/shipments מחזיר publicId, trackingUrl ו-validationUrl לכל משלוח
- webhook shipment.created מחזיר trackingUrl — לשליחה ישירה במייל "ההזמנה נשלחה"
- עמודת "לינק מעקב" בטבלת המשלוחים, נכללת בייצוא לאקסל (למיזוג-דואר)
- לוגיקת הקישורים רוכזה למקום אחד — היא הייתה משוכפלת בשלושה מקומות ונפרדה
- תיעוד /docs/api ו-/docs/shipments עודכנו
v01.206.006שיפורוואטסאפ / תיבת הודעותתיבת ההודעות — העברת הודעה בבחירה מרובה, כמו בוואטסאפ
חלון העברת ההודעה עוצב מחדש בסגנון וואטסאפ: לחיצה על צ'אט ברשימה מסמנת אותו (במקום להעביר מיד), אפשר לבחור כמה צ'אטים ואז ללחוץ 'העברה' פעם אחת לכולם; הרשימה מציגה עכשיו תמונת פרופיל, שם ומספר טלפון (או 'קבוצה') לכל צ'אט…
פרטים נוספים ↓הסתר ↑
חלון העברת ההודעה עוצב מחדש בסגנון וואטסאפ: לחיצה על צ'אט ברשימה מסמנת אותו (במקום להעביר מיד), אפשר לבחור כמה צ'אטים ואז ללחוץ 'העברה' פעם אחת לכולם; הרשימה מציגה עכשיו תמונת פרופיל, שם ומספר טלפון (או 'קבוצה') לכל צ'אט, והצ'אטים שנבחרו מוצגים בתחתית החלון. בנוסף, העברה של הודעה מצוטטת (תשובת swipe) כבר לא גוררת איתה את הציטוט המקורי — עד היום הנמען ראה ציטוט של הודעה מצ'אט אחר שלחיצה עליו לא הובילה לשום מקום; מעכשיו התוכן נשלח נקי, בלי הציטוט. והנמען רואה עכשיו סימון '↪️ הודעה שהועברה' בראש כל הודעה שהועברה אליו — כמו תווית ההעברה של וואטסאפ, שמנגנון ההעברה של ספק ה-WhatsApp לא מציג בפועל; הודעות קוליות ומדבקות, שלא יכולות לשאת כיתוב, מועברות כפי שהן.
v01.206.005תיקוןשידורים / בלדרבלדר — התאמות מבדיקה חיה מול השרת של זיפ, לקראת שידור ראשון
בדיקת היתכנות לקריאה-בלבד מול שרת הבלדר של זיפ (הקבלן הראשון שמחובר) חשפה שלושה פערים בין התיעוד למציאות, ותוקנו לפני שידור ראשון: (1) הפונקציה GetCustomerRecords דורשת פרמטר בשם pCustomer ולא pParam — אומת ישירות מהשרת …
פרטים נוספים ↓הסתר ↑
בדיקת היתכנות לקריאה-בלבד מול שרת הבלדר של זיפ (הקבלן הראשון שמחובר) חשפה שלושה פערים בין התיעוד למציאות, ותוקנו לפני שידור ראשון: (1) הפונקציה GetCustomerRecords דורשת פרמטר בשם pCustomer ולא pParam — אומת ישירות מהשרת (SaveData ו-GetDeliveryDetails כן משתמשים ב-pParam כמתועד). (2) התשובות החיות כוללות שדה StatusName עם שם הסטטוס בעברית של חברת השליחים — נקלט ומשמש גם כתווית תצוגה וגם כמיפוי-גיבוי לקודי סטטוס שלא מופיעים בתיעוד (אצל זיפ: קוד 22 = 'נכשל', שממופה כעת לכשל מסירה כולל סימון הביקור בציר הזמן ועדכון ליונוויל), עם הגנת שלילה ('לא בוצע' לעולם לא ימופה כהצלחה). (3) השרת של זיפ לא תומך ב-HTTPS על פורט 58090 — הכתובת הנכונה לשידור היא http. בנוסף — מניעת כפל שידור: לזיפ יש אינטגרציית בלדר גם בצד של ליונוויל, כך שעדכון הנהג בליונוויל היה גורם לה לשדר שוב את אותו משלוח. מעכשיו שיבוץ נהג בלדר לא דוחף את הנהג לליונוויל (כל שאר הסנכרון — סטטוס, כתובת, הערות — ממשיך כרגיל), בכל מסלולי השיבוץ: טבלת משלוחים, דף משלוח, סריקה, אפליקציית מנהלים, פעולת AI ובוט קבוצתי. במקביל, סנכרון נכנס מליונוויל (שמעתה לעולם לא מכיר את נהג הבלדר) לא דורס את השיבוץ המקומי.
v01.206.004שיפורבוט קבוצתי / איסופיםיידוע שיבוץ איסוף — נשלח גם בהחלפת שליח מתוך המערכת
נציגות דיווחו שכשמשימת איסוף שכבר הייתה משובצת לשליח הועברה לשליח אחר — לא נשלחה הודעת 'שיבצתי עליך איסוף' לקבוצת הקבלן החדש.
פרטים נוספים ↓הסתר ↑
נציגות דיווחו שכשמשימת איסוף שכבר הייתה משובצת לשליח הועברה לשליח אחר — לא נשלחה הודעת 'שיבצתי עליך איסוף' לקבוצת הקבלן החדש. הסיבה: התרחיש הופעל רק במעבר הסטטוס מ'משלוח חדש' ל'שובץ לשליח איסוף', ובהחלפה הסטטוס כבר 'שובץ' ולא משתנה. מעכשיו, החלפת שליח איסוף שמבוצעת מתוך המערכת (דף משלוח, שיבוץ איסופים, שיבוץ מרובה, אפליקציית מנהלים, פעולת AI) שולחת את ההודעה לקבוצת הקבלן החדש — בתנאי שהשליח באמת הוחלף (שמירה חוזרת של אותו שליח לא שולחת דבר) ושהשליח החדש אינו שכיר. החלפה שמבוצעת בליונוויל עצמה במכוון לא שולחת הודעה.
v01.206.003שיפורפיננסים / תזרים מזומניםתזרים משולב — יתרת פתיחה לא צוברת יותר חובות היסטוריים
יתרת הפתיחה בתזרים המשולב נצברה מכל ההיסטוריה — חודשים ישנים (מלפני תזרים ההכנסות) מכילים רק הוצאות, ולכן הוצג 'חוב' ענק חסר משמעות.
פרטים נוספים ↓הסתר ↑
יתרת הפתיחה בתזרים המשולב נצברה מכל ההיסטוריה — חודשים ישנים (מלפני תזרים ההכנסות) מכילים רק הוצאות, ולכן הוצג 'חוב' ענק חסר משמעות. מעכשיו הצבירה מתחילה רק מעוגן שנקבע ידנית: כל עוד לא נקבעה יתרת פתיחה — היתרה מתחילה מ-0 ומוצג באנר עם כפתור לקביעתה; אחרי קביעת עוגן, היתרה מתגלגלת ממנו קדימה בלבד (פתיחת חודש = סגירת החודש הקודם). העריכה הפכה בולטת: כפתור 'עריכה' על כרטיס יתרת הפתיחה, אייקון עריכה גם על שורת הפתיחה בטבלה, תגית 'ידנית' על חודש מעוגן, וכפתור 'איפוס' שמוחק את העוגן של החודש.
v01.206.002תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — דחיית משלוח ('תחזירו, זה לא שלכם') לא מזוהה כבקשת שידור, ותשובת צפי 'היום' מועברת ללקוח
שני כשלים מהקבוצות.
פרטים נוספים ↓הסתר ↑
שני כשלים מהקבוצות. (1) בקבוצת בזק קבלן ענה 'תחזירו אליי בבקשה זה לא שלכם' (דחיית משלוח), והבוט הפעיל את תרחיש השידור ושאל למזהה משלוח. השורש: הטננט הוסיף ביטוי-שידור מותאם רחב מדי — 'שלכם' — שנמצא כתת-מחרוזת ב'זה לא שלכם'. שער הביטול של תרחיש השידור הורחב לזהות גם דחייה/החזרה ('תחזירו', 'להחזיר', 'לא שלי/שלכם/שלנו', 'לא שייך') — כך שהודעת דחייה משתיקה את הבוט, בעוד השימוש המכוון ('המשלוח שלכם, תשדרו', בלי 'לא') ממשיך לשדר. (2) בקבוצת יצחק הפצה הבוט שאל צפי מסירה, השליח ענה 'היום', ושער הרלוונטיות דחה זאת ולא העביר ללקוח — למרות ש'מחר'/'עד הערב' כן עברו. חוזק ה-prompt: יום או שעה בודדים ('היום', 'מחר', 'בערב', 'עד הערב', שעה) הם תשובת צפי תקינה מלאה. תחום לשאלות צפי בלבד — 'היום' לשאלת טלפון/כתובת עדיין נדחה. שני התיקונים אומתו חי; #1 מכוסה בטסט. (3) המשך של (1): שאלת 'אצטרך את מזהה המשלוח' של הבוט פתחה גישור שחי 6 שעות ותפס כל ברקוד ערום שנשלח בקבוצה — כך שברקוד שקבלן שלח 3 שעות אחר כך (בהקשר של דיווח על איסוף) שודר בטעות. קוצר ל-15 דקות: תשובת ברקוד אמיתית מגיעה תוך רגעים. (4) המשך עומק של (1+3): כשקבלן מדווח על תקלה (מס'לא תקין, אין מענה) והברקוד יושב בהודעה הקודמת — צילום מדבקה (OCR) או מספר ערום שנשלח רגע לפני — הבוט לא זיהה את המשלוח והדיווח לא הגיע ללקוח. נוסף שחזור ברקוד מההודעה שמיד-לפני, תחת כללים קשיחים כדי שלעולם לא ייצמד דיווח למשלוח לא-נכון: רק תרחישי תקלה, רק אותו שולח, רק ההודעה היחידה שמיד-לפני (בהפרש קטן מדקה, ללא סריקה אחורה — זיהוי הטריגר לפי מזהה ההודעה, חסין-כפילויות), ורק אם הברקוד נפתר למשלוח פעיל המשויך לאותו שליח. אומת מול נתוני הפרודקשן של האירוע ועבר ביקורת אדוורסרית. (5) סבב שני של היום — שבעה שורשים מ-9 דיווחי כשל נוספים: תשובת טלפון ללקוח (מספר ערום או אישור שהמספר נכון) מגיעה עכשיו לקבלן — מסלול דטרמיניסטי כשגישור-לקוח יחיד פתוח + יישור ה-handler לאחיו כך שכל תשובה מאושרת מועברת; הנחיית לקוח (החזרה/ביטול) על משימת איסוף כבר לא נשלחת לקבלן (אין מה להחזיר) אלא נפתחת כפתק פנימי לצוות; מניעת שאלה כפולה ללקוח — יצירת הגישור הפכה לתפיסה אטומית (אינדקס ייחודי חלקי ב-DB) ונוצרת לפני השליחה בכל ארבעת התרחישים; תשובת לקוח שמדווחת שהעניין כבר הסתדר ('לקוח קיבל את המשלוח') מקבלת 'תודה על העדכון' במקום 'העברנו לשליח שמטפל'; נעץ מיקום ב-WhatsApp כבר לא נעלם — מומר לקישור Google Maps, נשמר ומועבר בגישורים; אוצר-מילים של מספר-חסר ('אין טלפון') סווג עד היום כ'אין מענה' — נוסף לביטויי טלפון-שגוי; ותוקן template פגום של טננט ששכפל את מספר המשלוח ומחק את השאלה מהודעת הבירור. (6) שאלת צפי על משימת איסוף — שאלה כמו "מתי צפי לאספקה?" על משלוח-איסוף היא דו-משמעית (האספקה = ההחזרה אל הלקוח; ייתכן שהכוונה למועד האיסוף), והפתק הפנימי אף טען בטעות "שטרם שובץ לשליח" כששליח האיסוף דווקא משובץ (חבד/26035468 — החיפוש בדק רק את ביקור המסירה). מעכשיו נכתב פתק פנימי מדויק לצוות שמציין שמדובר באיסוף, נוקב בשם שליח האיסוף המשובץ, ומבקש לברר מול הלקוח למה התכוון; משימות מסירה — התנהגות זהה לחלוטין. (7) שאלת-לקוח של הבוט נשלחה לצ'אט הפרטי של בעל העסק במקום לקבוצת הלקוח (משכן שילה): המשלוח ישב על רשומת לקוח-אב בלי קבוצה, בעוד קבוצת ה-WhatsApp האמיתית רשומה על לקוח-בן — וה-fallback נפל לטלפון. מעכשיו, לפני נפילה ל-1:1, הבוט מזהה את קבוצת-המשפחה — ורק כשיש בדיוק קבוצה אחת בין האב וכל ילדיו (שתי קבוצות שונות = שני תתי-עסקים, לא מנחשים). (8) לקוח שחולק על מסירה שנרשמה ("מופיע שסופק והמשלוח לא סופק", "קיבלו חבילה 1 מתוך 2") כבר לא מקבל את התשובה המבטלת "המשלוח כבר נמסר" — הבוט שותק, ופתק פנימי ייעודי נפתח לצוות ("לקוח חולק על מסירה שנרשמה — נדרש בירור") עם ההודעה המקורית; שאלת צפי רגילה על משלוח שנמסר ממשיכה לקבל את התשובה הישירה. (9) הודעת "אין מענה" ללקוח — תוקנה הסתירה שבה סיכום דיווח השליח ביקש "מס' דירה וקומה" בעוד פירוט המשלוח שמעליו כבר מציג אותם: המסכם מקבל עכשיו את רשימת השדות שכבר מוצגים ומתבקש לציין רק פרטים שבאמת חסרים (כמו קוד כניסה); בנוסף קוצרה תבנית ההודעה לטננט — הוסר בלוק 4 הדוגמאות, נשמרה שאלה קצרה אחת כדי ששיוך התשובות ימשיך לעבוד.
v01.206.001תיקוןאינטגרציות / חנויותבדיקת חיבור לחנות אישופ — אבחון אמיתי של חסימת Cloudflare במקום הודעת 'טוקן שגוי' מטעה
כשה-API של אישופ חוסם את הבקשה ברמת Cloudflare (challenge לפני שהבקשה מגיעה בכלל לשרת), כפתור 'בדיקת חיבור' הציג עד היום 'e-shop דחה את הטוקן (403)' — הודעה מטעה ששלחה את המשתמש לבדוק טוקן תקין לחלוטין.
פרטים נוספים ↓הסתר ↑
כשה-API של אישופ חוסם את הבקשה ברמת Cloudflare (challenge לפני שהבקשה מגיעה בכלל לשרת), כפתור 'בדיקת חיבור' הציג עד היום 'e-shop דחה את הטוקן (403)' — הודעה מטעה ששלחה את המשתמש לבדוק טוקן תקין לחלוטין. כעת הבדיקה מזהה את חתימת ה-challenge של Cloudflare ומציגה הודעה נכונה: החסימה היא ברמת IP/WAF בצד אישופ ולא בעיית טוקן, כולל מזהה ה-CF-RAY של הבקשה — המספר שצוות אישופ צריך כדי לאתר את החסימה ב-Security Events של Cloudflare שלהם ולהגדיר חריגה. בנוסף, כל הקריאות ל-API של אישופ נשלחות כעת עם User-Agent מזהה (Shipnest-Integration/1.0) במקום זהות אנונימית — לבקשת הצוות הטכני של אישופ וכנוהג מקובל מול WAF.
v01.206.000חדשסוכנים / דוח עמלותminorדוח עמלות הסוכן: טבלת פירוט לפי לקוח — בפורמט של הדוח הידני
בדף הסוכן היה אזור צדדי שהציג את רשימת הלקוחות ולידם את העמלה, אבל בפועל הוא היה חסר ערך: אצל רוב הלקוחות הוא הראה את המילה "ברירת מחדל" במקום סכום, ולא הייתה בו שום דרך לראות כמה חבילות נשלחו או כמה הסוכן מרוויח מכל לקו…
פרטים נוספים ↓הסתר ↑
בדף הסוכן היה אזור צדדי שהציג את רשימת הלקוחות ולידם את העמלה, אבל בפועל הוא היה חסר ערך: אצל רוב הלקוחות הוא הראה את המילה "ברירת מחדל" במקום סכום, ולא הייתה בו שום דרך לראות כמה חבילות נשלחו או כמה הסוכן מרוויח מכל לקוח בחודש. את התמונה האמיתית הרכיבו ידנית באקסל חיצוני. במקום אותו אזור נכנסה עכשיו טבלת "פירוט לפי לקוח" בתוך דוח העמלות החודשי, בדיוק במבנה של אותו אקסל: לקוח, מחיר גבייה, עמלה לחבילה, כמות חבילות וסה"כ עמלה לחודש — שורה לכל לקוח של הסוכן, ממוינת מהמכניס ביותר, עם שורת סיכום. מחיר הגבייה נלקח מפרופיל התמחור של הלקוח, כך שהוא מוצג כמספר נקי כמו באקסל; כשהחיוב בפועל גבוה ממנו בגלל תוספות (חבילה נוספת וכו') הממוצע האמיתי נחשף ב-tooltip במקום לזהם את העמודה. לקוח בלי משלוחים החודש עדיין מופיע — עם מחיר הגבייה והעמלה לחבילה שלו — כי גם באקסל הוא נספר. לקוח שאין לו פרופיל תמחור מסומן בבירור בכתום במקום להציג ₪0 שקרי, וכך התגלה שלעשרות לקוחות פעילים חסר מחירון במערכת. עריכת העמלה הקבועה לחבילה עברה לתוך הטבלה עצמה, והטבלה גם נוספה כגיליון נפרד בייצוא לאקסל ומופיעה גם בפורטל הסוכן עצמו. בהמשך היום נוסף גם פילוח החבילות: הכותרת הישנה הכריזה "עמלה על 4299 מתוך 4299 משלוחים" — משפט חסר משמעות, כי גם לקוח בתעריף ₪0 נספר כ"מזכה בעמלה". במקומו נכנס פילוח אמיתי לשלושה מספרים — חבילות שעברו דרך הסוכן, חבילות שהניבו לו עמלה בפועל, וחבילות שלא הניבו כלום (תעריף ₪0, ללא מודל עמלה, או עמלה שלילית). הפילוח מופיע גם פר-לקוח בטבלה וגם בייצוא לאקסל. אצל הסוכן הראשון שנבדק זה חשף שמתוך 4,299 חבילות ביוני, 1,040 לא הניבו לו שקל — כולן מארבעה לקוחות בתעריף ₪0, כשלקוח אחד לבדו אחראי ל-830 מהן.
- טבלת פירוט לפי לקוח בפורמט הדוח הידני: לקוח | מחיר גבייה | עמלה לחבילה | כמות חבילות | סה"כ לחודש
- מחיר הגבייה מוצג נקי מהמחירון; חיוב ממוצע בפועל (עם תוספות) נחשף ב-tooltip
- לקוח ללא משלוחים בחודש עדיין מופיע עם התעריף והעמלה שלו
- לקוח ללא פרופיל תמחור מסומן בכתום במקום להציג ₪0 שקרי
- עריכת העמלה לחבילה עברה לתוך הטבלה; האזור הצדדי הישן הוסר
- הטבלה נוספה כגיליון "לפי לקוח" בייצוא לאקסל, ומוצגת גם בפורטל הסוכן
- פילוח חבילות בראש הדוח: עברו דרכו / הניבו עמלה / ללא עמלה — במקום "4299 מתוך 4299"
- לקוחות בתעריף ₪0 מופיעים בדוח עם כמות החבילות שלהם ועם ₪0 — לא נעלמים
- הפילוח יורד גם לרמת הלקוח (tooltip על כמות החבילות) וגם לגיליון האקסל
- רשימת הלקוחות בטור הצדדי גוללת בתוך עצמה — היא כבר לא נמתחת הרחק מעבר לסוף הדף
- טבלת הפירוט ממוינת אלפביתית A→Z (לטינית ואז עברית) במקום לפי גובה העמלה
- בורר הלקוח בכללי עמלה הוחלף ב-combobox עם חיפוש — במקום רשימה שנפתחה מהתקרה עד הרצפה
- דף הסוכן רץ מקצה לקצה כמו שאר דפי הפירוט — הוסרה הגבלת הרוחב שהייתה ייחודית לו
- שורת חיפוש לקוח בכותרת טבלת הפירוט; שורת הסיכום מסכמת את התוצאות המסוננות
- עמודת "מחירון" בטבלה — "ערוך מחירון" / "הוסף מחירון", פותחת את אותו dialog של טבלת הלקוחות הראשית
- פריסת דף הסוכן יושרה לדף הלקוח: אין כפתור "חזרה" (הניווט דרך ה-breadcrumb), כפתור העריכה עבר לתוך הבאנר, וכל המרווחים — גם הפנימיים — על רשת 8 פיקסלים
v01.205.000חדשמעקב משלוחים / דפים ציבורייםminorקישור מעקב לפי ברקוד — לינק גנרי לדיוור, בלי לחשוף את פרטי הנמען
עד היום דף המעקב הציבורי ודף עדכון פרטי המסירה נפתחו שניהם רק לפי מזהה פנימי (public_id) — מפתח אקראי שמגיע מליונוויל.
פרטים נוספים ↓הסתר ↑
עד היום דף המעקב הציבורי ודף עדכון פרטי המסירה נפתחו שניהם רק לפי מזהה פנימי (public_id) — מפתח אקראי שמגיע מליונוויל. לקוחות ביקשו שהקישור יסתיים בברקוד של המשלוח, כדי שיוכלו להרכיב אותו בעצמם במיזוג-דואר (למשל במייל ללקוח הקצה) מתוך מספר ההזמנה שכבר יש להם. הבקשה מולאה — אבל רק על אחד משני הדפים, וזה מכוון: הברקוד הוא מספר רץ, כך שמי שמחזיק ברקוד אחד יכול לנחש ברקודים סמוכים. לכן דף המעקב נפתח כעת גם לפי ברקוד, אך במצב מצומצם — מצב המשלוח, עיר היעד וצפי ההגעה בלבד, בלי שם הנמען, בלי הכתובת המלאה, בלי המפה, בלי המזהה האישי (שהיה בעצמו מדליף את הגישה לדף העדכון), ובלי סיבת הכשל — טקסט חופשי שהשליח מקליד, שנמצא בפועל מכיל קוד דלת או הפניה לשכן. דף עדכון פרטי המסירה — שכותב את הכתובת ומסנכרן אותה חזרה לליונוויל — ממשיך להיפתח אך ורק לפי המזהה האישי, כך שאיש לא יוכל לרוץ על ברקודים ולשנות הוראות מסירה של חבילות של אחרים. בכרטיס המשלוח ובפורטל הלקוחות נוסף פריט חדש בתפריט הקישורים: לינק מעקב לפי ברקוד. במהלך העבודה התגלה גם פער שקט — כל נתיב יצירת משלוח שאינו עובר דרך ליונוויל (WooCommerce, קוניבו, אישופ, CashCow, nopCommerce, ייבוא מחסן, שידור בין שותפים וה-API הציבורי) יצר משלוחים ללא מזהה ציבורי כלל, כלומר בלי שום קישור מעקב או עדכון שעובד. כעת כל נתיב יצירה מנפיק מזהה משלו (10 תווים אקראיים, אותה צורה שליונוויל מנפיק), 75 המשלוחים הקיימים שחסרו מזהה מולאו רטרואקטיבית, והעמודה קיבלה אילוץ ייחודיות בבסיס הנתונים. בנוסף, דף המעקב קיבל הגבלת קצב שלא הייתה לו קודם, ומשתנה התבנית validation_url הפסיק ליפול חזרה לברקוד — נפילה שייצרה עד היום קישור שבור.
- דף המעקב נפתח גם לפי ברקוד — לינק גנרי שאפשר להרכיב לבד במיזוג-דואר
- גישה לפי ברקוד מציגה מצב, עיר וצפי בלבד — בלי שם נמען, כתובת, מפה, סיבת כשל או המזהה האישי
- דף עדכון פרטי המסירה נשאר נעול למזהה האישי בלבד — ברקוד לא פותח אותו
- פריט חדש בתפריט הקישורים: לינק מעקב לפי ברקוד — בכרטיס המשלוח ובפורטל הלקוחות
- תוקן: משלוחים מחנויות, ממחסן, משידור-שותפים ומה-API נוצרו ללא מזהה ציבורי — ולכן בלי קישור מעקב שעובד
- 75 משלוחים קיימים מולאו רטרואקטיבית; העמודה קיבלה אילוץ ייחודיות
- הגבלת קצב על דף המעקב הציבורי; משתנה validation_url לא נופל יותר לברקוד (קישור שבור)
v01.204.000חדשפיננסים / תזרים מזומניםminorתזרים מזומנים אמיתי — הוצאות, הכנסות ותזרים משולב
דף התזרים חולק לשלוש תצוגות.
פרטים נוספים ↓הסתר ↑
דף התזרים חולק לשלוש תצוגות. תזרים הוצאות — הטבלה הקיימת (תשלומים לשליחים/קבלנים וספקים), בתוספת ניהול הוצאות קבועות: מודל ייעודי (כפתור 'הוצאות קבועות') לעריכת רשימת ההוצאות החוזרות של החודש — שכירות, ביטוח, תוכנות וכו' — והרשימה מועתקת אוטומטית לכל חודש חדש מהחודש האחרון שנערך, כל עוד לא שונתה. תזרים הכנסות — שורה נעולה לכל לקוח עם צפי התקבול מהדוח החודשי של חודש העבודה הקודם (שילוח + מחסן − זיכויים, כולל מע"מ), בתאריך יעד לפי יום התשלום של הלקוח (ברירת מחדל: 3 לחודש; ניתן לקבוע יום קבוע פר לקוח מתוך הטבלה). תזרים משולב — טבלה לפי תאריכים: לכל יום סך הכנסות, סך הוצאות ויתרה רצה (יתרת אתמול + הכנסות − הוצאות); יתרת הפתיחה של חודש נגזרת אוטומטית מיתרת הסגירה של החודש הקודם, וניתן לקבוע אותה ידנית כעוגן (למשל יתרת עו"ש בפועל). בנוסף: העמודות המחושבות (יתרה לתשלום, ללא מע"מ, סטטוס תשלום) הפכו לתצוגה בלבד — סטטוס מוצג כתגית צבעונית, ויתרה שעבר תאריך היעד שלה מודגשת באדום.
- שלוש תצוגות בדף התזרים: הוצאות, הכנסות ומשולב — מעבר מהיר ביניהן
- הוצאות קבועות עוברות אוטומטית מחודש לחודש וניתנות לעריכה במודל ייעודי
- צפי תקבולים אוטומטי פר לקוח מהדוח החודשי, לפי יום התשלום של הלקוח (ברירת מחדל 3 לחודש)
- תזרים משולב עם יתרה רצה יומית ויתרת פתיחה שנגזרת מסגירת החודש הקודם (או נקבעת ידנית)
- סטטוס תשלום כתגית צבעונית ויתרות בפיגור מודגשות באדום
v01.202.000חדשפורטל לקוחות / מעקב משלוחminorפורטל לקוחות — ציר זמן מלא במעקב המשלוח + כרטיס המסרונים שנשלחו לנמען
לקוחות הפורטל ביקשו לראות במעקב המשלוח יותר ממה שהוצג עד היום.
פרטים נוספים ↓הסתר ↑
לקוחות הפורטל ביקשו לראות במעקב המשלוח יותר ממה שהוצג עד היום. ציר הזמן הציג רק את רשומות הביקור (איסוף מהשולח / מסירה לנמען), כך שבין האיסוף למסירה המשלוח 'נעלם' מהתצוגה לימים שלמים — כל השלב במחסן לא הופיע כלל. כעת הציר מאחד את רשומות הביקור עם חותמות מחזור-החיים שכבר קיימות על המשלוח (in_inventory_at / in_transfer_at / out_inventory_at / canceled_at — נקבעות במעבר הראשון לכל סטטוס ואינן מתאפסות) ומציג את כולן ממוינות כרונולוגית: המשלוח נוצר → איסוף מהשולח → נקלט במרכז המיון → הועבר בין מרכזי מיון → יצא להפצה → מסירה לנמען / כשל / ביטול. כשל מסירה מציג גם את סיבת הכשל, ואירוע שטרם קרה מוצג כ'מתוכנן' בתחתית הציר. בנוסף נוסף כרטיס 'מסרונים שנשלחו לנמען' — הלקוח רואה אילו הודעות נשלחו בפועל לנמען שלו (סוג הטריגר, מועד, טלפון היעד, תוכן ההודעה, והאם נשלחה או נכשלה). האיחוד של שלושת מקורות ההודעות (יומן ביקורת, הודעות מתוזמנות, ועמודות ה-legacy על המשלוח) חולץ ל-lib/shipment-messages ומשמש גם את כרטיס המסרונים בצד הניהול, כדי ששני המשטחים לא ייפרדו. הפרויקציה לפורטל חושפת ללקוח רק את מה ששייך לו: ללא ספק ההודעות (Green API / Meta), ללא שגיאת הספק הגולמית, וללא הודעות מתוזמנות שטרם נשלחו. הגישה מוגבלת להרשאת 'צפייה במשלוחים' ולסט הלקוחות המקושרים של המשתמש, כמו יתר דף המשלוח.
- ציר הזמן במעקב המשלוח כולל כעת גם קליטה במחסן, העברה בין מרכזי מיון ויציאה להפצה — עם מועד לכל שלב
- כשל מסירה מוצג עם מועד הכשל וסיבת הכשל; ביטול מוצג כאירוע בפני עצמו
- כרטיס חדש 'מסרונים שנשלחו לנמען' — כל ההודעות שנשלחו ללקוח הקצה, עם מועד, תוכן וסטטוס שליחה
- לוגיקת איחוד ההודעות שותפה בין הפורטל לצד הניהול (lib/shipment-messages) כדי למנוע פער בין המשטחים
v01.203.000שיפוראפליקציית שליחיםminorאפליקציית שליחים — סבב שיפורי חוויה (לקראת שחרור מאוגד)
אצווה של שיפורי חוויה באפליקציית השליחים, מיועדת לשחרור בנייה יחיד (אין OTA).
פרטים נוספים ↓הסתר ↑
אצווה של שיפורי חוויה באפליקציית השליחים, מיועדת לשחרור בנייה יחיד (אין OTA). כפתורים מתים: 'שכחתי סיסמה' פותח כעת את דף איפוס הסיסמה (shipnest.io/forgot-password, אותה טבלת משתמשים); כפתור 'שלח קבלה ללקוח' שלא היה מחובר — הוסר; ההצעה 'חפש בכל המשלוחים' בסורק (שהובילה להודעת 'בקרוב') הוחלפה בהודעה ישירה. מסך ההזדכות: כשל טעינת רשת כבר לא מוצג כמצב הצלחה 'אין חובות פתוחות' — מוצג מצב שגיאה עם כפתור 'נסה שוב'. מודעות לאיסוף: מסך הביקור מנסח 'איסוף' במקום 'מסירה' לאורך הזרימה (סטטוס, כותרת כתובת, הוכחה, CTA 'סמן כנאסף', דיאלוג אישור, toast) כשהמשימה היא PICKUP — משלים את תיקוני השרת. סיכום משלוח שהושלם: ניתן כעת לצרף תמונת הוכחה גם אחרי הסימון (תרחיש 'שכחתי לצלם'), והתווית הקשיחה 'היום' הוחלפה בתאריך אמיתי ('היום'/'אתמול'/תאריך מלא). WhatsApp: נפתח עם הודעת 'אני בדרך אליך' מוכנה + fallback ל-wa.me כשאינו מותקן; ניווט Google עבר מנעיצת-פין (q=) להכוונת-נסיעה (dir/). שקיפות רווחים: כל שורת משלוח בפירוט מציגה כעת את התעריף שממנו חושבה — תעריף בסיס, האזור שקבע אותו, ותוספת חבילות (הנתונים כבר הגיעו מהשרת ולא הוצגו); שורה שתומחרה ל-₪0 כבר לא נעלמת (סכום מוצג תמיד כשיש מחירון, כדי שהפירוט יסתכם לסך); 'התאמות ידניות' ו'ניכויי זיכוי' נפתחות עכשיו לפירוט (סוג/כמות להתאמות; סיבה/לקוח/מספר-זיכוי לניכויים, מוצגים כשליליים); נוסף רענון-במשיכה, ומעבר בין תקופות שומר על הנתונים הקודמים במקום להבהב. מיקום חי: 'המרחק ממני', מיון 'הקרוב ראשון' ו'התחל מהמיקום שלי' רצו על דגימת GPS חד-פעמית שלא התעדכנה — עכשיו הם משתמשים ב-watchPositionAsync ומתעדכנים תוך כדי תנועה. אמינות: מפתח ה-Idempotency בקריאות הוכחת-מסירה/גוביינא/חתימה הפך לפרמטר חובה (הגנת קומפילציה מפני קורא עתידי שישמיט אותו ויכפיל שורות/אחסון בניסיון חוזר). נראות רשימת היום: נוסף חיפוש חופשי (שם/רחוב/עיר/ברקוד) וכל כרטיס מציג כעת את הברקוד — כדי למצוא משלוח מסוים מבין עשרות; תווית התאריך הפכה ל'חזרה להיום' בלחיצה כשלא צופים בהיום; והטאב כבר לא קופץ מתחת ליד המשתמש כשמסלול נהיה פעיל ברקע (ברירת-המחדל החכמה חלה פעם אחת ליום, לא בכל poll).
- כפתורים מתים תוקנו/הוסרו: 'שכחתי סיסמה', 'שלח קבלה', וסטאב חיפוש הסריקה
- שגיאת רשת בהזדכות כבר לא נראית כ'הכל הוזדכה'
- ניסוח 'איסוף' לאורך מסך הביקור למשימות PICKUP
- צירוף הוכחת מסירה אחרי הסימון + תאריך אמיתי בסיכום
- WhatsApp עם הודעה מוכנה + fallback ל-wa.me; ניווט Google בהכוונה
- שקיפות רווחים: תעריף/אזור/תוספת לכל שורה, פירוט התאמות וניכויים, רענון-במשיכה
- מיקום חי (watchPositionAsync) למרחקים/מיון/נקודת-התחלה
- חיפוש + ברקוד ברשימת היום, 'חזרה להיום', ותיקון קפיצת הטאבים
v01.201.003תיקוןאפליקציית שליחים / אימות + API מוביילאפליקציית שליחים — קשיחות שרת: אבטחת התחברות + תיקון ניווט לאיסופים
סבב תיקוני שרת לאפליקציית השליחים (עצמאי מהאפליקציה — חלקם מתקנים גם את הגרסה המותקנת בשטח, ללא שחרור).
פרטים נוספים ↓הסתר ↑
סבב תיקוני שרת לאפליקציית השליחים (עצמאי מהאפליקציה — חלקם מתקנים גם את הגרסה המותקנת בשטח, ללא שחרור). קשיחות התחברות: (1) ה-hash הדמה שנועד למנוע timing-attack היה פגום — 61 תווים, bcrypt לא-תקין — וגרם ל-bcrypt.compare להתקצר ל-0ms, מה שיצר timing-oracle לזיהוי קיום כתובות אימייל; הוחלף ב-hash תקין בן 60 תווים. (2) נתיב התחברות הלקוח (CustomerUser) במובייל לא נעל חשבון אחרי ניסיונות כושלים — נוספה נעילה זהה למדיניות הצוות (5 ניסיונות → נעילה ל-15 דק', איפוס בהצלחה) מעל העמודות הקיימות, ללא migration. (3) נוסף rate-limit לכל שלושת נתיבי ההתחברות (login/refresh/google) כבלם משני מעל הנעילה הפר-חשבונית. (4) השוואת ה-hash של ה-refresh token עברה מ-'!==' ל-timingSafeEqual. תיקון איסופים (PICKUP): (5) עד כה משימת איסוף באפליקציה ניווטה את השליח לכתובת הנמען במקום לנקודת האיסוף (הקואורדינטות והכתובת נבנו מהיעד בלבד); כעת ה-API מזהה kind=PICKUP ומחזיר את הקואורדינטות/כתובת/איש-קשר של המקור (source*), עם נפילה ל-null במקום ליעד כשאין קואורדינטות מדויקות — כך שהניווט נעשה לפי כתובת המקור ולא לנקודה שגויה. מסירות נותרו זהות לחלוטין. (6) סימון איסוף כ'הושלם' הפסיק לירות webhook כוזב 'shipment.delivered' ואת התראות ה'delivered' לחנויות (Woo/Konimbo/CashCow/Shopify/NopCommerce) — הזמנה שרק נאספה כבר לא תדווח כנמסרה. הלוגיקה חולצה ל-lib/mobile-visit-fields עם כיסוי טסטים. ניקוי משטח תקיפה: (7) הוסרו שלושה endpoints יתומים ולא-בשימוש מה-API המובייל — /inbox (שהחזיר בקריאה אחת ביקורים, טלפונים וסכומי גוביינא מכל ה-tenants שאליהם ה-Person מקושר, משטח דליפה חוצה-tenant ללא שום צרכן באפליקציה), personal-stops (CRUD מלא לא-מחובר), ו-location/ping (הוחלף מזמן ב-location/batch). git-reversible אם ה-UI התואם ייבנה בעתיד. קשיחות נוספת: (8) פינגי המיקום (location/batch) קיבלו recordedAt מהלקוח ללא בדיקה — ping עתידי היה גורם לשליח להיראות 'במשמרת' ללא הגבלה (הדשבורד מסיק זאת מפינגים בשעה האחרונה); ה-timestamp נחסם כעת ל-'עכשיו' (pings ישנים מה-offline queue נותרים לגיטימיים). (9) גביית גוביינא (COD) חדלה להוסיף רשומת היסטוריה כפולה כשהרשומה כבר WITH_DRIVER — הגנת-עומק ל-retry ללא Idempotency-Key.
v01.201.002תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — עדכון קבלן על משלוח אחד לא מועבר בטעות ללקוח של משלוח אחר
כשל שדווח בקבוצת פיל ביי אבי: היה גישור 'אין מענה' פתוח על משלוח 25885959 (ממתין לתשובת הלקוח).
פרטים נוספים ↓הסתר ↑
כשל שדווח בקבוצת פיל ביי אבי: היה גישור 'אין מענה' פתוח על משלוח 25885959 (ממתין לתשובת הלקוח). בקבוצת זיפ נציג שאל 'למה נכשל 25917396?', והקבלן ענה בתשובת swipe (ציטוט) 'זה נמסר, נשלח עם כפולה, הכפולה צריכה לחזור'. הבוט זיהה במילה 'נמסר' עדכון-פתרון של קבלן, ומכיוון שההודעה לא נקבה בברקוד בטקסט עצמו (הברקוד היה בהודעה המצוטטת), הוא שייך אותה לגישור היחיד הפתוח — 25885959 — והעביר ללקוח הלא-נכון (feel by abby) עדכון על משלוח שכלל לא שלו. השורש: רגל ה-source-resolution לא קיבלה בכלל את מזהה ההודעה המצוטטת, וזיהתה משלוח רק לפי ברקוד בטקסט. התיקון: הרגל מקבלת עכשיו את הציטוט, מזהה ממנו את המשלוח האמיתי, ואם הוא שונה מהמשלוח של הגישור הפתוח (או שההודעה נוקבת בטקסט בברקוד של משלוח אחר) — היא לא מגשרת. עדכון-פתרון סתמי בלי ברקוד ('הסתדר', 'סופק') ממשיך להתנהג כרגיל. אומת מקצה לקצה על האירוע.
v01.201.001תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — טלפון שלקוח שולח כמספר לא נזרק יותר כ'ברכה', תיוג צוות (@) לא נקרא כטלפון, וגישור נסגר כשאדם פתר ידנית
כשל שדווח בקבוצת טאצ': לקוח עדכן מספר טלפון (053-2347485) בתגובה לשאלת 'טלפון שגוי', והבוט זרק אותו — נדרשה התערבות אנושית, ומאוחר יותר הבוט העביר לשליח הודעה בלתי קשורה כאילו הייתה המספר.
פרטים נוספים ↓הסתר ↑
כשל שדווח בקבוצת טאצ': לקוח עדכן מספר טלפון (053-2347485) בתגובה לשאלת 'טלפון שגוי', והבוט זרק אותו — נדרשה התערבות אנושית, ומאוחר יותר הבוט העביר לשליח הודעה בלתי קשורה כאילו הייתה המספר. אובחנו שלושה באגים. (1) isPureGreeting — הסינון הזול שמזהה ברכות לפני שער ה-LLM — סיווג מספר טלפון ערום כ'ברכה טהורה', כי אחרי הסרת אותיות לא נשאר בו כלום. מעכשיו הודעה שמכילה ספרה אינה ברכה, ומגיעה לשער כרגיל. (2) extractIsraeliPhone קרא תיוג @mention של איש צוות (@972556686876) כמספר טלפון, ולכן הבוט עדכן במשלוח מספר של איש צוות והעביר אותו כ'טלפון מעודכן'. מעכשיו תיוגי @ מוסרים לפני חילוץ הטלפון, כך שרק מספר שהוקלד בפועל נלקח. (3) הגישור נשאר פתוח אחרי שאיש צוות פתר ידנית ('שולח לנהג'), ולכן הבוט המשיך להחזיק אותו ותפס אליו הודעה זרה. מעכשיו הודעת צוות ברורה של טיפול/העברה-לנהג בקבוצת הלקוח סוגרת את הגישור — שמרנית: רק כשגישור אחד פתוח (לא דו-משמעי) ורק על ניסוח טיפול חד-משמעי, לא על פטפוט. שלושת התיקונים מכוסים בטסטים. תיקון (1) לבדו סוגר את האירוע — הטלפון האמיתי היה מגושר מיד והגישור היה נסגר לפני ההודעה השנייה.
v01.201.000שיפורבוט תפעולי / הגדרות AIminorבוט שיחתי 1:1 — כבוי כברירת מחדל, עם מתג הפעלה בהגדרות
הבוט השיחתי בצ׳אט 1:1 של ה-business-inbox ענה מיוזמתו לכל לקוח מוכר (התאמה לפי מספר טלפון) — כולל הצפת לקוחות אמיתיים בשיחה חופשית בקו הפרטי שלהם, ואפילו איש צוות שמספרו רשום גם כלקוח.
פרטים נוספים ↓הסתר ↑
הבוט השיחתי בצ׳אט 1:1 של ה-business-inbox ענה מיוזמתו לכל לקוח מוכר (התאמה לפי מספר טלפון) — כולל הצפת לקוחות אמיתיים בשיחה חופשית בקו הפרטי שלהם, ואפילו איש צוות שמספרו רשום גם כלקוח. מעכשיו סוכן הלקוח ה-1:1 הוא opt-in פר-טננט וכבוי כברירת מחדל: כשמכובה, הודעות נכנסות עדיין נשמרות ל-inbox לטיפול ידני אך הבוט אינו עונה מעצמו. נוסף מתג ייעודי בהגדרות > ספק AI > 'סוכן פורטל לקוחות' ('מענה אוטומטי בצ׳אט 1:1 של לקוחות'). חשוב: התרחישים המשימתיים של מנוע הקבוצות (העברת צפי, טעויות מיון, תיאום איסופים, לידים, גישור) נשלטים בנפרד דרך botScenarios ואינם מושפעים — הם ממשיכים לפעול כרגיל בקבוצות/בזרימות המקושרות.
- סוכן הלקוח ב-1:1 כבוי כברירת מחדל (opt-in פר-טננט) — סוף להצפת לקוחות בקו הפרטי
- הודעות נכנסות עדיין נשמרות ל-inbox גם כשהבוט מכובה
- מתג הפעלה חדש: הגדרות > ספק AI > סוכן פורטל לקוחות
- תרחישי הקבוצות (צפי / טעויות מיון / תיאום איסופים / לידים) לא מושפעים ונשארים פעילים
v01.200.002תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — בקשה לבטל שידור (או דיווח שכבר שודר) כבר לא מזוהה בטעות כבקשת שידור חדשה
קבלן כתב 'שודר אלי פעמיים ואמרתם לי לבטל שידור אחד', והבוט קרא את מילת 'שידור' וענה 'כדי לשדר אליך אצטרך את מזהה המשלוח' — כאילו זו בקשת שידור חדשה.
פרטים נוספים ↓הסתר ↑
קבלן כתב 'שודר אלי פעמיים ואמרתם לי לבטל שידור אחד', והבוט קרא את מילת 'שידור' וענה 'כדי לשדר אליך אצטרך את מזהה המשלוח' — כאילו זו בקשת שידור חדשה. שער זיהוי בקשת השידור (isBroadcastRequest) הוא דטרמיניסטי לפי מילות מפתח, ולא הבחין בין בקשה לשדר לבין ביטול/דיווח. נוסף שער ביטול: הודעה שמזכירה שידור אך נושאת כוונת ביטול ('לבטל שידור', 'בטל', 'תבטלו', 'ביטול'), סירוב ('אל תשדרו', 'לא לשדר'), או דיווח שכבר שודר ('שודר אלי', 'כבר משודר') — הבוט שותק במקום לבקש מזהה משלוח. בקשות שידור אמיתיות ('לשדר את X', 'שדרו לי', 'שימו עלי') ממשיכות לפעול כרגיל. מכוסה בטסט.
v01.200.001שיפורתיבת העסקתיבת העסק — אייקונים מתאימים לפילטרי 'סוג' ו'מצב'
שני הפילטרים בראש רשימת הצ'אטים קיבלו אייקונים קבועים שמתאימים למהותם: 'סוג' (לפי מי הצ'אט — לקוח/שליח/קבלן/צוות) מציג כעת אייקון אנשים, ו'מצב' (מצב הטיפול — לא נקראו/ממתינות/בטיפול/טופל) מציג את אייקון תיבת הדואר.
פרטים נוספים ↓הסתר ↑
שני הפילטרים בראש רשימת הצ'אטים קיבלו אייקונים קבועים שמתאימים למהותם: 'סוג' (לפי מי הצ'אט — לקוח/שליח/קבלן/צוות) מציג כעת אייקון אנשים, ו'מצב' (מצב הטיפול — לא נקראו/ממתינות/בטיפול/טופל) מציג את אייקון תיבת הדואר. קודם ה-trigger של כל פילטר הציג את אייקון הבחירה הנוכחית, מה שלא ייצג היטב את מהות הפילטר.
v01.200.000חדששידורים / אינטגרציותminorשידור משלוחים לבלדר — אינטגרציה מלאה עם מערכות בלדר של חברות שליחים
נוספה אינטגרציית שידור מלאה למערכת בלדר (Baldar) — התוכנה שמפעילות חברות שליחים רבות בישראל — במתכונת זהה לשידורי SNL.
פרטים נוספים ↓הסתר ↑
נוספה אינטגרציית שידור מלאה למערכת בלדר (Baldar) — התוכנה שמפעילות חברות שליחים רבות בישראל — במתכונת זהה לשידורי SNL. ההגדרה בכרטיס הנהג תחת 'שידורים': בוחרים 'בלדר', מזינים את כתובת השירות (service.asmx) ואת קוד הלקוח שקיבלתם מחברת השליחים, וכתובת מחסן (מוצא למסירות ונקודת החזרה לאיסופים). מרגע החיבור, שיוך משלוחים לנהג בלדר משדר אוטומטית: משיוך מרובה בטבלת המשלוחים (עם עדכון התקדמות חי), מדף הסריקה (שידור אוטומטי עם כל סריקה), משיוך בודד בדף המשלוח, מפעולת AI ומבקשת שידור בקבוצת וואטסאפ. השידור בונה את רצף 28 הפרמטרים של SaveData לפי מסמך התיעוד הרשמי — כולל ניקוי תווים שוברי-פורמט, המרת גוביינא מאגורות לשקלים, קידוד קומה/דירה/כניסה בשדה מספר הבית, ואבטחת כתובת: בשידור איסוף הקבלן רואה את נקודת האיסוף והמחסן בלבד, לעולם לא את כתובת לקוח הקצה. מספר המשלוח שמחזירה בלדר נשמר כמזהה היוצא של המשלוח (כולל קישור למדבקה), עם הגנת אידמפוטנטיות מפני שידור כפול — וזיהוי תשובת 'שידור כפול' של בלדר משחזר את מספר המשלוח הקיים במקום להיכשל. סטטוסים חוזרים בשני מסלולים: cron שדוגם את GetCustomerRecords כל רבע שעה וממפה את טבלת הסטטוסים של בלדר לסטטוסים שלנו (עם הגנה מפני נסיגה מסטטוס סופי), ו-webhook נכנס מוכן ב-/api/webhooks/baldar שממתין רק לאישור של בלדר — הוכן מסמך בקשה מסודר לשליחה אליהם (docs/baldar-webhook-request.md) עם מפרט ה-payload ושאלות הבהרה על התיעוד.
- שידור לבלדר מכל נקודות השיבוץ: טבלה מרובה, דף סריקה, דף משלוח, AI ובוט קבוצתי
- הגדרה פשוטה בכרטיס הנהג: כתובת שירות + קוד לקוח + כתובת מחסן — בלי טוקנים
- בניית SaveData מדויקת: 28 פרמטרים, גוביינא בשקלים, ניקוי תווים שוברי-פורמט
- הגנת כפילויות דו-שכבתית: אידמפוטנטיות אצלנו + זיהוי תשובת duplicate של בלדר
- סנכרון סטטוסים אוטומטי כל 15 דקות + webhook נכנס מוכן ומאובטח
- מסמך בקשה מוכן לשליחה לבלדר לקבלת עדכוני סטטוס בדחיפה
v01.199.002תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — הנחיית 'תחזירו/תבטלו' מהשולח מועברת לשליח, ושידור מהיר ברצף לא נבלע
שני דיווחי כשל מהקבוצות.
פרטים נוספים ↓הסתר ↑
שני דיווחי כשל מהקבוצות. (1) כביסכל: הבוט שאל את הלקוח על טלפון שגוי, והלקוח ענה 'הלקוחה לא עונה גם במיילים, תחזירו את המשלוח אלינו' — הנחיה תפעולית ברורה. שער הרלוונטיות דחה אותה בצדק ('זו לא תשובה לשאלה מה הטלפון'), ולכן היא נזרקה והשולח נשאר בלי מענה. מעכשיו, כשלקוח עונה לשאלת טלפון/כתובת בהנחיה אחרת (החזרה / ביטול / שינוי יעד), הבוט מזהה זאת דרך שער חדש (isCustomerDirective, מדויק ובטמפרטורה 0, מחזיר שלילה בכל ספק ובכל שלילה כמו 'אל תחזירו'), מעביר את דברי השולח כלשונם לשליח, פותח פתק פנימי לצוות לוודא שההחזרה/הביטול בוצע, וסוגר את הגישור. נבדק חי: 9/9 — תופס החזרה/ביטול/שינוי-יעד, ודוחה טלפון, פטפוט, שאלות, שלילה ותודה. (2) זיפ: בקשת שידור מהירה '26033294 לשדר' נבלעה בשקט כי אישור השידור של המשלוח הקודם ('✅ שידרתי אליך') נחת מיליסקונדות אחרי הבקשה החדשה, וחלון ה-burst שנחתך 'אחרי ההודעה היוצאת האחרונה' השמיט את הבקשה עצמה — burst ריק → 'אין מילת מפתח' → שתיקה. תוקן: החלון נחתך לפי ההודעה היוצאת שקדמה לבקשה המפעילה, כך שהבקשה תמיד נכללת. שידורים מהירים ברצף כבר לא נבלעים. (3) עדי אקווה: הבוט בצ׳אט 1:1 ב-business-inbox הציף איש צוות בתשובות אוטומטיות — מספרו קיים גם כרשומת לקוח וגם כמשתמש צוות (TenantUser), וסוכן הלקוח זיהה אותו כלקוח לפי הטלפון בלי לבדוק שהמספר שייך לצוות שלנו. תוקן: בצ׳אט 1:1 שהמספר שלו נמצא במפת אנשי הצוות של הטננט — ההודעה נשמרת ל-inbox אך הבוט אינו עונה.
v01.199.001תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — במשימות איסוף מוצגים פרטי המוצא (לא היעד) והניסוח הוא 'איסוף' ולא 'מסירה'
נציגה דיווחה שבמשימת איסוף הבוט הציג ללקוח את כתובת וטלפון היעד (בני ברק) במקום את המוצא (בית שמש), וכתב 'אין מענה מהנמען לבקשת המסירה' במקום איסוף.
פרטים נוספים ↓הסתר ↑
נציגה דיווחה שבמשימת איסוף הבוט הציג ללקוח את כתובת וטלפון היעד (בני ברק) במקום את המוצא (בית שמש), וכתב 'אין מענה מהנמען לבקשת המסירה' במקום איסוף. אומת בנתונים: משלוח 26119762 הוא taskType=pickup עם מוצא ויעד נפרדים, והבלוק שנשלח הראה את היעד. השורש: כל זרימת התרחישים הייתה מכוונת-מסירה בלבד. התיקון חוצה את כל התרחישים (אין מענה, כתובת שגויה, טלפון שגוי, צפי מסירה, תיאום מחדש, כשל מסירה): (1) בלוק הפרטים ושורת הכתובת מציגים כעת את שדות המוצא במשימת איסוף, עם תווית '📦 איסוף', והכתובת/טלפון של נקודת האיסוף. (2) הסיכום שנשלח ללקוח מנוסח כקושי באיסוף ('אין מענה מאיש הקשר לאיסוף') ולא כמסירה. (3) באג נסתר שנחשף ותוקן: מענה של הלקוח עם טלפון חדש עדכן את שדה טלפון היעד — כך שבמשימת איסוף הוא היה דורס את טלפון הנמען בטלפון של איש הקשר לאיסוף. מעכשיו במשימת איסוף לא נכתב שדה יעד כלל, אך התשובה עדיין מועברת לשליח. הפנייה עצמה תמיד לשולח (הלקוח המשלם), ללא שינוי. מיפוי: משלוחי 'delivery'/'transfer'/ללא-סוג נשארים מכוונים-יעד ללא שינוי.
v01.199.000חדשבוט קבוצתי / איסופיםminorתרחיש בוט חדש — יידוע הקבלן בקבוצה על שיבוץ איסוף
נוסף תרחיש בוט מסוג חדש בדף 'תרחישי הבוט': כשמשלוח עובר מ'משלוח חדש' ל'שובץ לשליח איסוף' והשליח המשובץ על משימת האיסוף הוא קבלן (פנימי או חיצוני — לא שליח שכיר), הבוט שולח לקבוצת הוואטסאפ של הקבלן הודעה עם פרטי המוצא של …
פרטים נוספים ↓הסתר ↑
נוסף תרחיש בוט מסוג חדש בדף 'תרחישי הבוט': כשמשלוח עובר מ'משלוח חדש' ל'שובץ לשליח איסוף' והשליח המשובץ על משימת האיסוף הוא קבלן (פנימי או חיצוני — לא שליח שכיר), הבוט שולח לקבוצת הוואטסאפ של הקבלן הודעה עם פרטי המוצא של האיסוף (שם, כתובת וטלפון של נקודת האיסוף — לא היעד) ומבקש לאשר שזה אזור ההפצה שלו. לקבלן פנימי הנוסח 'שיבצתי עליך איסוף... בבקשה תאשר שזה אזור הפצה שלך', ולקבלן חיצוני 'שידרתי לך איסוף... בבקשה תאשרו שזה אזור הפצה שלכם'. היידוע חד-כיווני — הבוט לא ממתין לאישור. התרחיש נתפס בכל דרכי השיבוץ: דף המשלוח, דף שיבוץ האיסופים, שיבוץ מרובה, אפליקציית המנהלים, פעולת AI, וגם שיבוץ שבוצע בליונוויל והגיע בוובהוק. זהו התרחיש הראשון שמופעל על ידי אירוע מערכת (שינוי סטטוס) ולא לפי הודעה בקבוצה — דף ההגדרות מציג עבורו תג 'אירוע מערכת' ומסתיר את עורך ביטויי ההפעלה. כמו כל תרחיש, כבוי כברירת מחדל ונוסחי ההודעות ניתנים לעריכה.
- הודעה אוטומטית לקבוצת הקבלן ברגע שיבוץ שליח איסוף — עם פרטי המוצא, לא היעד
- נוסח נפרד לקבלן פנימי ('שיבצתי עליך... תאשר') ולקבלן חיצוני ('שידרתי לך... תאשרו')
- שליח שכיר לא מקבל הודעה — התרחיש מיועד לקבלנים בלבד
- נתפס גם בשיבוץ מתוך המערכת וגם בשיבוץ שבוצע בליונוויל (וובהוק)
- תרחיש מונע-אירוע ראשון בדף תרחישי הבוט — מופעל משינוי סטטוס, לא מהודעה בקבוצה
v01.198.001שיפורלקוחות / תיאום איסופיםתיאום איסוף יומי — ברירת מחדל לטלפון העסקי והפעלה מרובה מטבלת הלקוחות
שני שיפורים לתיאום האיסוף היומי.
פרטים נוספים ↓הסתר ↑
שני שיפורים לתיאום האיסוף היומי. (1) שדה 'טלפון לבירור איסוף' כבר לא חובה: כל עוד לא הוגדר טלפון ייעודי, שאלת הבוקר נשלחת לטלפון העסקי של הלקוח. השדה בדף הלקוח מציג את הטלפון העסקי כברירת מחדל, וטבלת תיאום האיסופים מציגה את המספר שישמש בפועל. אזהרה מוצגת רק כשאין גם טלפון עסקי. (2) הפעלה מרובה: בטבלת הלקוחות הראשית, בבחירה מרובה של לקוחות נוספה פעולת 'תיאום איסוף יומי' — דיאלוג שמפעיל (או מכבה) את התכונה לכל הלקוחות שנבחרו בבת אחת, כולל אפשרות לקבוע לכולם קבוצת וואטסאפ משותפת לקבלת התשובות. אם לא נבחרת קבוצה, הקבוצה הקיימת של כל לקוח נשארת ללא שינוי, והדיאלוג מתריע כמה מהלקוחות שנבחרו חסרי טלפון עסקי. (3) בורר קבוצות הוואטסאפ המשותף (בכל המערכת) מציג כעת את שם הקבוצה שנבחרה על הכפתור עצמו, במקום הטקסט הקבוע 'בחר קבוצה'. (4) תוקן באג ותיק בייבוא לקוחות מליונוויל שהשאיר מאות לקוחות בלי טלפון עסקי: ליונוויל מחזירה את שדה הטלפון הראשי כ-null, והקוד שרץ מה-webhook פירש זאת כ'יש ערך' ודילג על הטלפון האמיתי שיושב בכתובת האיסוף הרשומה (location.default_phone). כל מסלולי הסנכרון תוקנו (כולל fallback לנייד/משרד), טלפון קיים לא נדרס יותר ב-null, ו-phoneNormalized מתעדכן יחד עם הטלפון. בוצע מילוי חד-פעמי מהנתונים שכבר היו שמורים — 295 לקוחות קיבלו טלפון עסקי רטרואקטיבית. (5) תוקן כשל שהתגלה בלוגי הפרודקשן: בוט הצ'אט העסקי (1:1) הפסיק לענות בכל שיחה שנציג ענה בה מה-inbox — תשובת נציג נשמרת בתפקיד 'staff' וההיסטוריה שנשלחה למודל לא סיננה אותה, מה שהפיל את הקריאה ל-AI (שגיאת 400). מעכשיו תשובות נציג נכללות בהקשר של הבוט כצד-העסק (שלא יענה שוב על מה שכבר נענה), ופתקים פנימיים לעולם לא נשלחים למודל. (6) דיאלוג ההפעלה המרובה מציג כעת את רשימת הלקוחות חסרי הטלפון עם שדה השלמה ליד כל אחד: המספר נשמר בלקוח כטלפון לבירור איסוף, ואם שאלת הבוקר של המחזור הנוכחי כבר יצאה — היא נשלחת אליהם מיד עם השמירה. (7) ימי שליחה פר-לקוח: בכרטיס תיאום האיסוף בדף הלקוח נוספו צ'יפים לבחירת ימים ספציפיים (למשל לקוח שאוספים ממנו רק ב' ו-ה') — כשלא נבחרו ימים, השאלה נשלחת לפי ימי השליחה של החברה; טבלת תיאום האיסופים מציגה עמודת 'ימי שליחה', ושליחה ידנית מכוונת ללקוח בודד עוקפת את ההגבלה.
v01.198.000חדשCRM / הסכמיםminorהסכמים — חתימת נגד של המוביל, ונספח הביטוח נוסח מחדש כ'אחריות מורחבת'
המשך השדרוג המשפטי של מודול ההסכמים.
פרטים נוספים ↓הסתר ↑
המשך השדרוג המשפטי של מודול ההסכמים. (1) חתימת המוביל: עד היום ההסכם נחתם רק בצד הלקוח, ושדה 'חתימת המוביל' נשאר קו ריק גם במסמך הסופי. בדף הגדרות חדש — 'הסכמים וחתימה' (מופיע רק לחברות שמודול ההסכמים פעיל אצלן) — מציירים או מעלים את חתימת העסק ומזינים את שם החותם. מרגע ההגדרה, כל הסכם שנשלח לחתימה יוצא כשהוא כבר חתום בצד המוביל: החתימה מוטבעת אוטומטית בדף החתימה הציבורי וב-PDF (טיוטה וסופי) עם שם החותם ומועד החתימה, ומועד חתימת המוביל נשמר על ההסכם. ההסכם הסופי חתום דו-צדדית. (2) נספח ג' נוסח מחדש: הנוסח הקודם ('הלקוח מצטרף לכיסוי ביטוחי...') עלול היה להתפרש כשיווק ביטוח — פעילות הטעונה רישיון לפי חוק הפיקוח על שירותים פיננסיים (ביטוח). הנספח נקרא כעת 'אחריות מורחבת לחבילות' ומנוסח כהתחייבות שיפוי חוזית של המוביל עצמו, כולל הבהרה מפורשת שאין מדובר בפוליסת ביטוח. הניסוח החדש חל על הסכמים חדשים בלבד — הסכמים קיימים שומרים את הנוסח שנחתם בהם. אגב כך אוחדו נוסחי ברירת המחדל של נספחי הערבות והאחריות למקור אחד, כך שדף החתימה וה-PDF מציגים תמיד נוסח זהה (עד עכשיו הסכם ללא נוסח מותאם הציג את ברירת המחדל ב-PDF אך כלום בדף החתימה).
- דף הגדרות חדש 'הסכמים וחתימה': ציור/העלאת חתימת המוביל + שם החותם
- כל הסכם יוצא חתום בצד המוביל — בדף החתימה הציבורי וב-PDF, עם מועד חתימה
- נספח ג' הפך ל'אחריות מורחבת לחבילות' — התחייבות שיפוי חוזית, לא 'ביטוח' (חשיפת רישוי)
- נוסחי ברירת המחדל של הנספחים מאוחדים — מה שמוצג על המסך זהה למה שנחתם ב-PDF
v01.197.000חדשCRM / הצעות מחיר והסכמיםminorהצעות מחיר והסכמים — שדרוג מקיף: אישור הצעה אונליין, חתימות ערבים, שליחה ב-WhatsApp וחיזוק משפטי
סקירת עומק של תהליך הצעות המחיר והחוזים הולידה שדרוג רוחבי בשלושה צירים.
פרטים נוספים ↓הסתר ↑
סקירת עומק של תהליך הצעות המחיר והחוזים הולידה שדרוג רוחבי בשלושה צירים. (1) חוקיות ודין: אוחדו שני דפי החתימה הציבוריים לדף קנוני אחד שמציג את מסמך ההסכם המלא — עד היום לקוח שהגיע מקישור תזכורת ראה גרסה מקוצרת בלי הצדדים, הפתיח ונספחי הערבות והביטוח, וחתם על מה שלא ראה. ערבים (נספח ב') חותמים כעת דיגיטלית בשדה נפרד לכל ערב — חתימת ההסכם נחסמת עד שכל הערבים חתמו, כי ערבות ללא חתימת הערב אינה אכיפה; הסכמים ישנים עם ערבים שלא חתמו נחסמים בהמרה עם אפשרות אישור מודע שמתועד ביומן. נוספה הוכחת שלמות ראייתית — טביעת SHA-256 של ה-PDF החתום ושל נוסח התנאים + נוסח ההסכמה המדויק (עם גרסה) נשמרים באירוע החתימה. לכידת ה-IP תוקנה כך שלא ניתן לזייף אותה מצד הלקוח, וה-PDF החתום ותמונות החתימה מוגשים כעת בקישורים מאובטחים קצובי-זמן במקום URL ציבורי קבוע (המסמכים מכילים ת"ז). (2) תהליך מול לקוח: הלקוח מאשר או דוחה הצעת מחיר ישירות מהעמוד הציבורי (בדחייה — עם סיבה), ויוצר ההצעה מקבל התראת מייל מיידית; בחתימת הסכם נשלחת התראת מייל לסוכן ששלח (בנוסף לאישור ללקוח); הצעות והסכמים נשלחים גם ב-WhatsApp דרך חיבור ה-Green API של העסק; נוספו שכפול הצעה (הדרך לתקן הצעה שנשלחה/פגה), משיכת הצעה, ביטול הסכם שנשלח (מכבה את קישור החתימה מיידית) וסיום הסכם פעיל; וקרון יומי מפקיע אוטומטית הצעות שתוקפן עבר והסכמים שתקופתם הסתיימה — סטטוסים שעד היום לא היו ניתנים להשגה כלל. (3) נוחות: תוקן כפתור 'PDF חתום' שהיה שבור לגמרי בדף ההסכם; איש הקשר בהסכם לא נמחק יותר בעריכת טיוטה; המרת הסכם שמקושר ללקוח קיים מעדכנת את הכרטיס במקום ליצור לקוח כפול; שליחה מרשימת ההסכמים עוברת דרך דיאלוג השליחה המלא במקום לדלג על כל ההגדרות; מיון העמודות ברשימות עובד כעת מול השרת; מוני הסטטוסים בפילטרים מציגים ספירה אמיתית; לוגו העסק מוטמע ב-PDF ההסכם; גיליון הליד מציג את ההצעות וההסכמים המקושרים אליו; ותוקנו רספונסיביות במובייל, מצב כהה, נגישות ו-RTL בכל מסכי המודול.
- הלקוח מאשר או דוחה הצעת מחיר אונליין מהעמוד הציבורי — עם התראה מיידית לצוות
- ערבים חותמים דיגיטלית — ההסכם לא נחתם עד שכל הערבים חתמו על נספח הערבות
- שליחת הצעות והסכמים גם ב-WhatsApp דרך חיבור העסק
- דף חתימה קנוני אחד עם מסמך ההסכם המלא + טביעת SHA-256 ונוסח הסכמה מתועד לחיזוק ראייתי
- ביטול/סיום/משיכה + פקיעה אוטומטית של הצעות והסכמים + שכפול הצעה
- PDF חתום מוגש בקישור מאובטח קצוב-זמן (לא URL ציבורי קבוע), וכפתור ההורדה בדף ההסכם תוקן
v01.196.000חדשמשלוחים / יעד אקספרסminorיעד אקספרס — גלגול יומי אוטומטי של משלוחים שלא נמסרו, עם תווית ימי פיגור
עד היום משלוח אקספרס שלא נמסר ביום היעד שלו פשוט נשאר תקוע על התאריך שעבר, וצריך היה להזיז אותו ידנית.
פרטים נוספים ↓הסתר ↑
עד היום משלוח אקספרס שלא נמסר ביום היעד שלו פשוט נשאר תקוע על התאריך שעבר, וצריך היה להזיז אותו ידנית. מעכשיו קרון לילי (00:00 שעון ישראל) בודק את כל משלוחי האקספרס: כל משלוח שיום היעד שלו כבר חלף ועדיין לא נמסר — מקודם אוטומטית ליום הנוכחי, וצובר יום פיגור. בטבלת המשלוחים (וגם בדף 'אקספרס') מופיעה לצד הסטטוס תווית אדומה 'פיגור N ימים' שמראה כמה ימים המשלוח מתעכב מעבר ליעד המקורי. מתגלגלים כל המשלוחים שלא נמסרו — כולל כאלה שנכשלה בהם מסירה (ינוסו שוב) — פרט למשלוחים שנמסרו, בוטלו, או בכשל סופי, שנשארים במקומם. הגדרה ידנית מחדש של יעד אקספרס (בדף המשלוח, בפעולה קבוצתית או ב'הוספת משלוחים') מאפסת את מונה הפיגור, כי מדובר ביעד טרי. החישוב מתבצע לפי שעון ישראל וחוצה מעברי שעון קיץ/חורף בבטחה.
- קרון לילי מגלגל אוטומטית ליום הבא כל משלוח אקספרס שלא נמסר ביום היעד שלו
- תווית אדומה 'פיגור N ימים' לצד הסטטוס, גלויה גם בטבלת המשלוחים וגם בדף אקספרס
- מתגלגלים כל מי שלא נמסר (כולל כשלים שינוסו שוב); נמסר/בוטל/כשל-סופי נשארים במקום
- הגדרה ידנית מחדש של יעד אקספרס מאפסת את מונה הפיגור
v01.195.001תיקוןבוט תפעולי / מנוע התרחישיםבוט תפעולי — החלטות הבוט הפכו דטרמיניסטיות, ושאלת צפי שלא נענתה מגיעה לצוות
סריקה של 4,000 החלטות בוט מפרודקשן.
פרטים נוספים ↓הסתר ↑
סריקה של 4,000 החלטות בוט מפרודקשן. (1) שלושת המסווגים שמפעילים את הבוט רצו ב-temperature של ברירת מחדל (1.0), בעוד שכל שאר המסווגים במערכת מקבעים 0. המשמעות: החלטות גבול הוכרעו בהטלת מטבע. מדידה על תשובת קבלן אמיתית — 'לצערי לא אספיק היום כנראה להוציא אז בראשון' — נתנה 'לא תשובה' פעמיים ו'תשובה' חמש פעמים מתוך שבע. כלומר האם הנחיה של לקוח תגיע לשליח היה תלוי בדגימה אקראית. תוקן לשלושת המסווגים ולמחלץ הכתובת. אחרי התיקון: 7 מתוך 7 זהות. (2) כשלקוח שאל על צפי מסירה של משלוח אמיתי שלו שטרם שובץ לשליח, או נקב במספר שאינו שלו, הבוט שתק ואיש לא ידע — 34 מקרים בארבעה ימים. ארבעת תרחישי השליחים כבר מעלים פתק פנימי לצוות במקרה כזה; תרחיש הצפי לא. מעכשיו נפתח פתק פנימי בשרשור של אותו לקוח (לא נשלח דבר ללקוח). (3) גישורים שפג תוקפם מעולם לא סומנו כפגי-תוקף — הפונקציה קיימת בקוד ואיש לא קרא לה, ו-152 מתוך 160 הגישורים ה'ממתינים' היו למעשה מתים (104 בני שבוע ומעלה). חוברה לקרון הקיים. (4) הצלחה של העברת תשובה לא נרשמה כלל ביומן ההחלטות, רק כישלון — מה שגרם לקריאה שגויה של היומן. נוסף תיעוד סימטרי. (5) הודעת 'המשלוח כבר נמסר' נשלחה שלוש פעמים באותה שיחה: זהו הענף היחיד שלא פותח גישור, ולכן שום דבר לא מנע ממנו לירות שוב בכל פעם שה-burst המצטבר — שעדיין נשא את מספר המשלוח — סווג מחדש. גם שאלת הלקוח, גם תשובת הנציגה וגם 'תודה' הפעילו אותו. נוספה הגנת אידמפוטנטיות של 24 שעות לכל שילוב של צ'אט ומספר משלוח. הסימון נשמר ביומן ההחלטות ולא בהודעות הצ'אט, כי ההד של Green API על הודעות הבוט מאחר בצורה בלתי צפויה — נמדד 83, 86 ו-84 דקות על שלוש ההודעות הכפולות, לעומת אפס דקות על הודעה אחרת באותו יום. (6) הודעות הבוט נשלחות כציטוט של ההודעה שהן עונות לה, וכך הן נראות ב-WhatsApp בטלפון — אבל בממשק ה-inbox הן הופיעו כבועה חשופה בלי הקשר. הנתיב ששומר הודעות יוצאות דרך ה-API היה היחיד שלא קרא את מזהה ההודעה המצוטטת. תוקן, באותה צורה שנתיב הטלפון כבר עשה.
v01.195.000חדשלקוחות / תיאום איסופיםminorתיאום איסוף יומי — שאלת "יש איסוף היום?" אוטומטית כל בוקר, עם טבלת מעקב חיה
תכונה חדשה שמחליפה את סבב הבוקר הידני בקבוצות השירות ('בוקר טוב, יש איסוף היום?').
פרטים נוספים ↓הסתר ↑
תכונה חדשה שמחליפה את סבב הבוקר הידני בקבוצות השירות ('בוקר טוב, יש איסוף היום?'). בדף הלקוח נוסף כרטיס 'תיאום איסוף יומי': מתג הפעלה, טלפון ייעודי לבירור האיסוף ובורר קבוצת וואטסאפ לקבלת התשובות. כל בוקר ב-08:00 נשלחת ללקוחות שהתכונה פעילה אצלם שאלת תיאום בוואטסאפ — תבנית Meta מאושרת עם כפתורי 'כן'/'לא' (נשלח דרך ה-API הרשמי של Meta, שתומך בכפתורים ואינו תלוי בחלון 24 השעות). כשהלקוח עונה: 'כן' — נשלחת לקבוצת הוואטסאפ שנבחרה (דרך Green API) הודעה 'ללקוח X יש איסוף היום'; 'לא' — 'ללקוח X אין איסוף היום'; תשובה מורכבת יותר (למשל 'לא לאסוף לפני 16:00' או 'אין איסופים בשבועיים הקרובים') מועברת לקבוצה כלשונה — 'הלקוח X כתב: …'. הלקוח מקבל אישור קצר ונעים על כל תשובה, ותשובת המשך באותו יום (למשל 'כן' ואז 'רק אחרי 16:00') מגיעה גם היא לקבוצה. נוסף עמוד 'תיאום איסופים' בתפריט המשלוחים: כרטיסי סיכום (יש איסוף / אין / תשובה אחרת / ממתינים / נכשל / לא נשלח) וטבלה עם תשובת כל לקוח, שעות שליחה ומענה וסטטוס ההעברה לקבוצה. הטבלה מתאפסת כל בוקר ב-08:00 (תשובה שמגיעה ב-07:30 עדיין משויכת לשאלה של אתמול), וניתן לדפדף לימים קודמים. אפשר גם לשלוח את שאלת הבוקר ידנית לכולם או ללקוח בודד ('שלח שאלה מחדש' על שורה שנכשלה). בעמוד תבניות Meta נוסף סימון 'תבנית תיאום איסוף יומי' (תבנית אחת בלבד), עם תמיכה במשתנה {{customer_name}} לפנייה אישית. השאלה לא נשלחת בשבת ומכבדת את חלון שעות השליחה של החברה.
- כרטיס חדש בדף הלקוח: מתג הפעלה, טלפון ייעודי לבירור ובורר קבוצת וואטסאפ לתשובות
- שאלת בוקר אוטומטית ב-08:00 בתבנית Meta עם כפתורי כן/לא — ללא תלות בחלון 24 השעות
- תשובת הלקוח מועברת אוטומטית לקבוצה: יש/אין איסוף, ותשובה מורכבת עוברת כלשונה
- עמוד 'תיאום איסופים' חדש עם כרטיסי סיכום וטבלה שמתאפסת כל בוקר, כולל דפדוף להיסטוריה
- שליחה ידנית לכולם או ללקוח בודד, וסימון תבנית ייעודית בעמוד תבניות Meta
- הגדרות תזמון בדף תיאום האיסופים: בחירת ימי שליחה ושעת שליחה (06:00–11:30) פר-חברה — שעת השליחה קובעת גם את רגע איפוס הטבלה
v01.194.000חדשבוט תפעולי / תרחישי גישורminorבוט תפעולי — תרחיש חדש "פרטי משלוח", אישור ללקוח שההנחיה שלו הועברה, ושני שערי בטיחות
המשך הניתוח המשותף של דיווחי כשלי הבוט, הפעם עם מדידה על נתוני פרודקשן לפני כל שינוי — ושתי מדידות הפריכו את התיקון שתכננו.
פרטים נוספים ↓הסתר ↑
המשך הניתוח המשותף של דיווחי כשלי הבוט, הפעם עם מדידה על נתוני פרודקשן לפני כל שינוי — ושתי מדידות הפריכו את התיקון שתכננו. (1) תרחיש חדש: שליח שכותב בקבוצתו 'כתובת?' / 'מי הלקוח?' / 'טלפון של הנמען' מקבל את פרטי המשלוח מהמערכת, באותו בלוק שכבר נשלח היום לקבוצות. עונה רק על משלוחים המשויכים לאותו שליח או לשליחי המשנה שלו; אם לא ברור על איזה משלוח מדובר — שותק. כבוי כברירת מחדל. (2) לקוח שעונה לשאלת הבוט קיבל עד היום שתיקה; מעכשיו, אחרי שההנחיה שלו מועברת בפועל לשליח, נשלח לו 'קיבלנו, העברנו לשליח שמטפל ✅'. האישור נשלח פעם אחת בלבד גם כשהודעה אחת עונה על כמה משלוחים, ולעולם לא נשלח אם ההעברה לשליח נכשלה. (3) תיקון בטיחות: השער שהוסף אתמול ('לא עולה לי בחיפוש מספר משלוח X') קרא גם את שורת ה-OCR שהמערכת עצמה מזריקה מצילום מדבקה. מדידה: מתוך 354 קריאות OCR, 88 אינן מספר משלוח כלל (טלפון, משקל, מחיר) — ו-14 הודעות אמיתיות היו גורמות לבוט להכריז בקבוצה שמשלוח לא קיים, על מספר שאיש לא הקליד. השער קורא מעתה רק את מה שבני אדם כתבו. (4) סגירת וקטור פרטיות: קבלן שנקב בברקוד של קבלן אחר גרם לבוט לפנות ללקוח של אותו משלוח ולהחזיר את תשובתו — לרוב כתובת או טלפון של נמען זר — לקבוצת הקבלן ששאל. מעתה מספר משלוח מפורש חייב להיות משויך לשואל, לשליחי המשנה שלו, או לאיש. מספר ששייך לקבלן אחר נחשב רעש (רוב המקרים הם שגיאות OCR של המדבקה של השואל עצמו) ולא מבטל את הדיווח.
- תרחיש חדש "בקשת פרטי משלוח" — כבוי כברירת מחדל, מוגבל לקבוצות שליחים, ועונה רק על משלוחים המשויכים לשואל
- אישור אוטומטי ללקוח לאחר שההנחיה שלו הועברה לשליח — פעם אחת להודעה, ורק אם ההעברה הצליחה
- הבוט לא יכריז יותר שמשלוח לא קיים על סמך מספר שה-OCR קרא מצילום מדבקה
- ברקוד מפורש חייב להיות של השואל — נסגר וקטור שבו פרטי נמען של לקוח אחד הוחזרו לקבוצת קבלן זר
v01.193.002תיקוןיעד שבת / משלוחיםיעד שבת — הטבלה כבר לא נמחקת ומהבהבת 'לא נמצאו משלוחים' כל כמה שניות
בדף יעד שבת הטבלה הייתה מתאפסת כל כמה שניות: למשך כשנייה וחצי הוצג 'לא נמצאו משלוחים' ואז המידע חזר.
פרטים נוספים ↓הסתר ↑
בדף יעד שבת הטבלה הייתה מתאפסת כל כמה שניות: למשך כשנייה וחצי הוצג 'לא נמצאו משלוחים' ואז המידע חזר. הסיבה: הדף מרענן את עצמו ברקע בכל אירוע עדכון משלוח (SSE), וביום עמוס לפני שבת אירועי הסטטוס מגיעים כמה פעמים בשנייה — מה שחרג ממגבלת הקצב של /api/shipments (60 בקשות לדקה) והחזיר 429. הרענון הברקעי החליף אז את שורות הטבלה במערך ריק. תוקן בשניים: (1) רענון ברקע שנכשל (כולל 429) כבר לא דורס את השורות המוצגות — הנתונים נשמרים עד שהרענון מצליח; (2) רענוני ה-SSE מקובצים ומוגבלים לאחד לכל 4 שניות לכל היותר, כדי לא לחרוג ממגבלת הקצב מלכתחילה.
v01.193.000חדשתזרים / פיננסיםminorתזרים מזומנים — עמודת 'לתשלום (מחושב)' אוטומטית ונעולה לכל שליח/קבלן
לטבלת תזרים המזומנים (/finance/cash-flow) נוספה עמודה 'לתשלום (מחושב)' — נעולה לעריכה — שמציגה את הסכום היוצא בחודש עבור כל שליח או קבלן.
פרטים נוספים ↓הסתר ↑
לטבלת תזרים המזומנים (/finance/cash-flow) נוספה עמודה 'לתשלום (מחושב)' — נעולה לעריכה — שמציגה את הסכום היוצא בחודש עבור כל שליח או קבלן. התזרים מחושב לפי *מה שיוצא בחודש*: תזרים יולי, למשל, הוא בעיקר התשלומים עבור עבודת יוני (ולשליח בשוטף+35 — עבור מאי), נגזר מתנאי התשלום של כל שליח. בכל טעינת עמוד מתבצע סנכרון אוטומטי (לפי מחירון/עמלות + התאמות, מע"מ לפי אופן התשלום). שכירים על משכורת (ללא מחירון) אינם נכללים. הסנכרון idempotent — לא מרנדר מחדש כשאין שינוי — ומואץ ע"י סינון-מוקדם של שליחים פעילים והרצה מקבילית מבוקרת.
- עמודה נעולה 'לתשלום (מחושב)' — הסכום לתשלום לכל שליח/קבלן, לא ניתן לעריכה ידנית
- סנכרון אוטומטי בכל טעינת עמוד (כמו טבלת טעויות המיון) — שורה פר-שליח נוצרת/מתעדכנת לפי העבודה בחודש
- כרטיס סיכום חדש 'לתשלום (מחושב)' לצד שאר סיכומי התזרים
- יעיל: סינון-מוקדם של שליחים פעילים בחודש + חישוב מקבילי מבוקר (מ-~77ש' ל-~10ש')
- כפתור 'סנכרון' ידני בבר הכלים (עם אנימציית טעינה) בנוסף לסנכרון האוטומטי בטעינת הדף
- הטבלה תופסת את מלוא גובה הדף (כמו שאר הטבלאות) במקום גובה קבוע
- מעבר בין חודשים מרענן את תוכן הטבלה, והסכומים המחושבים מוצגים מיד עם סיום הסנכרון
- הגדרות שליח/קבלן: 'יום תשלום בחודש' הוחלף ב'תנאי תשלום — שוטף + N' (ערכים קיימים נשמרו: 15 = שוטף+15). תאריך היעד בתזרים מחושב כסוף חודש העבודה + N
- הגדרות שליח/קבלן: שדה 'אופן תשלום' חדש (חשבונית מס / קבלה / תלוש שכר / מזומן) — הוא שקובע אם מתווסף 18% מע"מ בתזרים (במקום להיגזר מסוג השליח). לשליחים ללא הגדרה נשמרת ההתנהגות הקודמת
- ייחוס חודשים מתוקן: התזרים של חודש מייצג את התשלומים היוצאים בו — כלומר עבודה מחודשים קודמים לפי תנאי השוטף של כל שליח (יולי = יוני בד"כ, שוטף+35 = מאי)
- מצב טעינה יפה בזמן סנכרון, ומצב 'אין נתונים' ידידותי (עם הוספת שורה ידנית) לחודש ריק — במקום טבלה ריקה ומתוחה
- תיקון כפילות: סאב-שליח לא מקבל עוד שורה נפרדת בתזרים — התשלום שלו כבר כלול בסכום של המנהל (שמשלם לו). שורות סאב שגויות שנוצרו נמחקות בסנכרון
- הטבלה ממוינת כברירת מחדל לפי תאריך היעד לתשלום (הקרוב ביותר ראשון)
- כפתור מילוי אוטומטי בכותרת 'סכום כולל מע"מ' — ממלא את התאים הריקים מעמודת הסכום המחושב בלחיצה אחת
v01.192.004חדשבוט תפעולי / תרחישי גישורבוט תפעולי — כשמישהו שולח מספר משלוח שלא קיים, הבוט אומר זאת במקום לשתוק
לקוח שאל 'מה הצפי למשלוח 25880144?' והבוט שתק, כי המספר לא קיים במערכת באף מזהה.
פרטים נוספים ↓הסתר ↑
לקוח שאל 'מה הצפי למשלוח 25880144?' והבוט שתק, כי המספר לא קיים במערכת באף מזהה. מעכשיו, בכל התרחישים, כשמישהו נוקב במספר משלוח שלא נמצא — הבוט משיב 'לא עולה לי בחיפוש מספר משלוח X'. הדגש הוא על דיוק: הבוט לעולם לא יגיב כך על מספר טלפון, סכום כסף, ת.ז. או מזהה שידור. שער חדש (isConfidentShipmentNumber) דורש שלושה תנאים במצטבר: (1) צורת ברקוד אמיתית — בדיוק 8 ספרות שמתחילות ב-1 או 2, כפי שנמדד על 195,935 מתוך 195,942 הברקודים החיים (אף ברקוד לא נראה כמו טלפון ישראלי); (2) המספר הוא רצף ספרות עצמאי ולא תת-מחרוזת של מספר ארוך יותר — קריטי, כי טלפון קווי כמו 021234567 מכיל את 21234567 שהיא צורת ברקוד תקינה לחלוטין; (3) אין מילת כסף או אחוז צמודה למספר. בכל ספק — הבוט שותק כמו קודם. השער מכוסה בטסטים (טלפונים ניידים וקוויים, ת.ז., סכומים, שנים, מזהי שידור), ובקשות שידור ממשיכות להשתמש בתשובת 'לא נמצא' העשירה שלהן.
v01.192.003תיקוןבוט תפעולי / תרחישי גישורבוט תפעולי — האישור 'אני בודק' מגיע בזמן ולא אחרי התשובה, והבוט מזהה שאלות צפי בניסוח טבעי
המשך ניתוח דיווחי הכשל.
פרטים נוספים ↓הסתר ↑
המשך ניתוח דיווחי הכשל. (1) האישור ('🔎 בודק מול השליח…') הוחזק עד שה-webhook של Green API מאשר שהשאלה נמסרה. מדידה על 111 גישורים אמיתיים: 80% מתפרסמים תוך שתי דקות, אבל 17 באיחור של 10+ דקות ו-8 מעל שעה — ואף גישור לא נשאר בלי אישור בסופו של דבר. כלומר ההחזקה מעולם לא מנעה אישור, רק איחרה אותו. שתי תוצאות רעות: קבלן שדיווח 'אין מענה' חשב שהבוט מתעלם ממנו (26 דק' שתיקה), ובמקרה אחר האישור נחת 72 דקות אחרי שהתשובה כבר הועברה — ונקרא כאילו הבוט בודק שוב מהתחלה. התיקון: אישור לעולם לא מתפרסם על גישור שכבר נענה, וקרון חדש (כל שתי דקות) מפרסם אישור שממתין מעל 90 שניות גם בלי אישור מסירה. סטטוס 'failed' עדיין חוסם אותו. (2) לקוחות כמעט לא כותבים 'מתי'; הם כותבים 'מה עם 25983110?' או 'הלקוח לא קיבל, מה קורה???'. אלה סווגו כ-none והבוט שתק אף שהמשלוח היה מזוהה. נוספו ביטויי טריגר: 'מה עם', 'מה קורה עם', 'לא קיבל', 'עדיין לא הגיע', 'לא הגיע', 'איפה המשלוח', 'איפה החבילה'. בטוח: תרחיש הצפי דורש ברקוד מפורש שמאומת שהוא באמת בטקסט, ומחפש רק בין משלוחי אותו לקוח — ביטוי לבדו לא יכול לגרום לניחוש משלוח.
v01.192.002חדששליחיםמועד תשלום חודשי לכל שליח — לחישוב תזרים
נוסף לכל שליח שדה 'יום תשלום בחודש' (1–31) בטופס ההוספה/עריכה — למשל שליחים שמקבלים ב-10, ב-15 או ב-25 לחודש.
פרטים נוספים ↓הסתר ↑
נוסף לכל שליח שדה 'יום תשלום בחודש' (1–31) בטופס ההוספה/עריכה — למשל שליחים שמקבלים ב-10, ב-15 או ב-25 לחודש. הערך נשמר על רשומת השליח, מוצג בכרטיס פרטי השליח, ומהווה בסיס לחישובי תזרים המזומנים.
v01.192.001תיקוןבוט תפעולי / תרחישי גישורבוט תפעולי — לא מעביר לשליח תשובת לקוח חסרת משמעות, והשאלה ללקוח כבר לא בינארית
מניתוח דיווחי הכשל: (1) הבוט העביר לקבלן 'עדכון מהשולח: זה' — מילה חסרת משמעות.
פרטים נוספים ↓הסתר ↑
מניתוח דיווחי הכשל: (1) הבוט העביר לקבלן 'עדכון מהשולח: זה' — מילה חסרת משמעות. הסיבה: שער הרלוונטיות (Haiku) החזיר 'unknown' (או טעה), והמנוע נפל אחורה והעביר בכל זאת; ההגנה היחידה בצד ה-handler הייתה 'אורך ≥ 2 תווים'. מעכשיו רק verdict 'yes' ודאי מעביר — 'unknown' משאיר את הגישור פתוח ושותק (נרשם בלוג ההחלטות). כמו כן חודד הפרומפט של השער: מילת מילוי/כינוי רומז ('זה', 'אוקיי', 'בסדר'), או תשובה שלא ניתן להבין ממנה מה לעשות בלי לקרוא את השאלה — נדחות. (2) הבוט שאל את הלקוח שתי שאלות כן/לא בהודעה אחת ('יש טלפון נוסף?' + 'יש אישור להשאיר ליד הדלת?'), הלקוח ענה 'כן', והבוט העביר לשליח 'עדכון מהשולח: כן' — שליח אחד הבין 'להחזיר למחסן'. התבנית שוכתבה לשאלה פתוחה אחת ('מה ההנחיה שלכם למסירה?') עם דוגמאות ניסוח, כך שכל תשובה עומדת בפני עצמה גם אחרי שהיא מועברת כלשונה. שני התיקונים משלימים: 'כן' כבר לא עונה על שאלה פתוחה, ולכן השער ידחה אותו וישתוק.
v01.192.000חדשמסרוניםminorדף סטטיסטיקות עסקי — הרחבה מקיפה (טאבים, ROI של ה-AI, עומס ואיכות)
דף הסטטיסטיקות של הצ׳אט העסקי אורגן מחדש ל-4 טאבים והורחב משמעותית.
פרטים נוספים ↓הסתר ↑
דף הסטטיסטיקות של הצ׳אט העסקי אורגן מחדש ל-4 טאבים והורחב משמעותית. סקירה: כרטיסי KPI עם השוואה לתקופה קודמת (▲/▼), הגרף היומי ופילוח המשתמשים. AI: שיעור הכלה (שיחות לקוח שנסגרו ללא נציג), עלות אוטומציית ה-AI בש״ח (ממדידת AiUsageEvent), מסלול פעולות שהבוט הציע (בוצע/נדחה/ממתין), מסלול גישורים (Relay), ופעילות מפורטת לפי תרחיש (מתוך registry התרחישים). עומס: מפת חום שעה×יום, פילוח לפי קהל (קבוצות לקוחות מול קבוצות שליחים מול צ׳אטים אישיים — לפי קישור chatId ל-Customer/Driver), וזמן תגובה כ-SLA (עד 5 דק׳/30/60/מעל שעה). איכות: התיישנות ההודעות הממתינות (עד שעה/1-4/4-24/מעל יממה), שיעור כשלי AI ל-1000 הודעות עם דיווחים פתוחים אחרונים, וצ׳אטים עמוסים. נוספו טווח תאריכים מותאם, ייצוא לאקסל (RTL, רב-גיליונות), ו-deep-link מכשלים/צ׳אטים ישירות לשיחה בתיבה.
- 4 טאבים: סקירה / AI / עומס / איכות
- ROI של ה-AI: שיעור הכלה, עלות אוטומציה בש״ח, מסלולי פעולות וגישורים, ופילוח לפי תרחיש
- עומס: מפת חום שעה×יום, פילוח קבוצות לקוחות מול שליחים, וזמן תגובה כ-SLA
- איכות: התיישנות ממתינות למענה, שיעור כשלים ל-1000 הודעות, וצ׳אטים עמוסים
- השוואה לתקופה קודמת (▲/▼) על כרטיסי ה-KPI
- טווח תאריכים מותאם, ייצוא לאקסל (רב-גיליונות, RTL), ו-deep-link לשיחה בתיבה (?chat=)
v01.191.000שיפורקונטרול פאנל / בוט תפעוליminorכשלי בוט — הסקירה עברה לקונטרול פאנל (כל הטננטים), עם מודל של השיחה גלול להודעה המדווחת
דיווחי הכשל של הבוט הם מעכשיו 'כתיבה בלבד' מצד הטננט: הצוות מדווח מתיבת העסק (קליק ימני על הודעה → 'דווח על כשל בוט'), אבל הרשימה כבר לא מוצגת בטננט.
פרטים נוספים ↓הסתר ↑
דיווחי הכשל של הבוט הם מעכשיו 'כתיבה בלבד' מצד הטננט: הצוות מדווח מתיבת העסק (קליק ימני על הודעה → 'דווח על כשל בוט'), אבל הרשימה כבר לא מוצגת בטננט. הסקירה והתיקון מרוכזים בקונטרול פאנל של הפלטפורמה — /admin/bot-failures ('כשלי בוט' בסיידבר) — עם רשימה חוצת-טננטים, תג של שם הטננט לכל דיווח, סינון לפי סטטוס וספירות, וסימון נסקר/טופל/נדחה. לחיצה על 'פתח בצ׳אט' לא מנווטת יותר לדף הצ'אטים (שממילא לא אפשרי חוצה-טננט), אלא פותחת מודל עם תמליל השיחה — 25 הודעות לפני ואחרי — גלול אוטומטית להודעה המדווחת, שמסומנת בהדגשה. כל נקודות הקצה של האדמין מוגנות ב-requirePlatformRole.
- רשימת כשלי הבוט מכל הטננטים במקום אחד: /admin/bot-failures
- 'פתח בצ׳אט' פותח מודל עם תמליל השיחה, גלול להודעה המדווחת ומסומן עליה
- תג טננט לכל דיווח + סינון לפי סטטוס וספירות, וסימון נסקר / טופל / נדחה
- בטננט נשאר רק הדיווח עצמו (כתיבה בלבד) — דף הסקירה הוסר משם
v01.190.006תיקוןהתראות שגיאת מיון / ניטור Green APIהתראות שגיאת-מיון — 👍 מאשר את ההתראה הנכונה, ותור השליחה של Green API מנוטר
שלושה המשכים לתקלת תור השליחה.
פרטים נוספים ↓הסתר ↑
שלושה המשכים לתקלת תור השליחה. (1) אישור ההתראה הלא-נכונה: ה-webhook חיפש את ההודעה שעליה הגיבו לפי messageId, וכשלא מצא — נפל ל'ההתראה הלא-מאושרת האחרונה בצ'אט'. מכיוון שה-cron מחליף את messageId בכל חזרה, 👍 שהגיע אחרי חזרה לא התאים לכלום ואישר התראה אקראית: שגיאת מיון לא-קשורה סומנה RESOLVED, בעוד זו שהנציג באמת טיפל בה המשיכה לנדנד. מעכשיו כל התראה שומרת messageIds[] — כל מזהי ההודעות שתחתיהם נשלחה (נזרע ביצירה, מתווסף בכל חזרה, ומולא רטרואקטיבית ל-498 הרשומות הקיימות); ה-webhook מתאים מול הרשימה, ונפילת-הניחוש-לפי-צ'אט הוסרה. (2) 👍 שנציג מסמן מטלפון העסק לא אישר כלום — ענף התגובות יושב מתחת לבדיקת incomingMessageReceived, כך שתגובות יוצאות נזרקו; עכשיו הנתיב היוצא מריץ את אותו אישור, וגם סקר ה-getChatHistory של ה-cron בודק את כל העותקים ולא רק את האחרון. (3) לא היה שום ניטור על עומק תור השליחה — green-api-health בדק רק את מצב ה-instance, ולכן ההצפה לא זוהתה במשך ימים; עכשיו הוא מתעד את עומק התור בכל ריצה ומתריע למנהל מעל סף, עם throttle של פעם בשעה לטננט (ההתראה עצמה היא הודעת וואטסאפ שממתינה בתור שעליו היא מדווחת).
v01.190.005תיקוןהתחברותהודעת שגיאה מובנת בהתחברות (במקום "Configuration")
שני מסכי ההתחברות הציגו את קוד השגיאה הפנימי של NextAuth כמות שהוא.
פרטים נוספים ↓הסתר ↑
שני מסכי ההתחברות הציגו את קוד השגיאה הפנימי של NextAuth כמות שהוא. מכיוון ש-authorize() זורק שגיאה, @auth/core עוטף אותה ב-CallbackRouteError שאינו client-safe וממיר אותה למחרוזת 'Configuration' — כך שכל התחברות שנכשלת (סיסמה שגויה, חשבון לא פעיל, או משתמש פורטל שמנסה להיכנס למערכת הניהול) הציגה למשתמש 'Configuration' באנגלית, וההודעות העבריות ב-authorize מעולם לא הגיעו אליו. נוסף helper משותף שממפה את קודי NextAuth לעברית, והקוד הגולמי נרשם לקונסולה בלבד. בנוסף, בדף ההתחברות של הצוות נוסף קישור 'לקוח? כניסה לפורטל הלקוחות' — לקוחות הגיעו לדף הלא נכון ונתקעו בלי רמז.
v01.190.004תיקוןתיבת העסק / Green API webhookתיבת העסק — תשובה מצוטטת שנציג שולח מהטלפון מוצגת עם ההודעה המצוטטת
כשנציגה השיבה בקבוצה על הודעה מסוימת (swipe-to-reply) מהטלפון שלה, ההודעה הופיעה בתיבה כבועה בודדת בלי בלוק הציטוט — כלומר בלי ההקשר של מה היא ענתה עליו.
פרטים נוספים ↓הסתר ↑
כשנציגה השיבה בקבוצה על הודעה מסוימת (swipe-to-reply) מהטלפון שלה, ההודעה הופיעה בתיבה כבועה בודדת בלי בלוק הציטוט — כלומר בלי ההקשר של מה היא ענתה עליו. הסיבה: Green API שולח את התשובה כ-webhook יוצא מסוג quotedMessage עם quotedMessage.stanzaId של ההודעה המצוטטת, אבל handleOutgoingPhoneMessage שמר רק את הטקסט והתעלם מה-stanzaId. הנתיב הנכנס כבר עשה זאת נכון — ומכאן חוסר הסימטריה: בפרודקשן נמצאו 1,070 הודעות נכנסות עם ציטוט שנפתר כראוי, מול 1,238 הודעות נציג מהטלפון שמתוכן 0 נשאו ציטוט אי-פעם. התיקון: הנתיב היוצא מפענח עכשיו את ה-stanzaId מול ה-externalId של ההודעות שלנו באותה שיחה ומקשר replyToId, בדיוק כמו הנתיב הנכנס. אם ההודעה המצוטטת אינה מאוחסנת אצלנו (קדמה לנו) — ההודעה פשוט מוצגת בלי ציטוט, ללא שגיאה. התיקון חל קדימה בלבד; הודעות היסטוריות לא ניתנות לשחזור כי ה-stanzaId שלהן מעולם לא נשמר.
v01.190.003תיקוןתיבת העסק / Green API webhookתיבת העסק — 👍 שנציג מסמן מהטלפון נרשם כתגובה על ההודעה, לא כבועת הודעה נפרדת
תגובות (reactions) של משתתפי הצ'אט כבר הוצגו נכון בתיבה — צ'יפ לכל אימוג'י מתחת לבועה, עם מונה ורשימת המגיבים בריחוף (547 הודעות נושאות תגובות בפרודקשן).
פרטים נוספים ↓הסתר ↑
תגובות (reactions) של משתתפי הצ'אט כבר הוצגו נכון בתיבה — צ'יפ לכל אימוג'י מתחת לבועה, עם מונה ורשימת המגיבים בריחוף (547 הודעות נושאות תגובות בפרודקשן). אבל תגובה שנציג שלנו מסמן מ*טלפון העסק* דלפה: היא מגיעה כ-webhook יוצא מסוג reactionMessage, ו-handleOutgoingPhoneMessage לא סינן את הסוג הזה — extractOutgoingText קורא את אותו שדה (extendedTextMessageData.text) שבתגובה מכיל את האימוג'י עצמו, ולכן נשמרה בועת הודעה בודדת של '👍' במקום צ'יפ תגובה על ההודעה המקורית. בפרודקשן נמצאו 36 בועות '👍' ו-2 של '🙏' מסוג source=phone ב-30 הימים האחרונים. התיקון: הנתיב היוצא מזהה reactionMessage ומצמיד את האימוג'י להודעת היעד (לפי stanzaId ↔ externalId) בדיוק כמו בנתיב הנכנס; אימוג'י ריק = הסרת התגובה.
v01.190.002שיפורמשלוחיםלוג אבחון מלא כשליונוויל נכשלת ביצירת משלוח
כשליונוויל מחזירה שגיאה ביצירת משלוח, הלוג רשם רק את הסטטוס ו-500 התווים הראשונים של התשובה — שהם דף שגיאת HTML של Rails, כלומר CSS בלבד.
פרטים נוספים ↓הסתר ↑
כשליונוויל מחזירה שגיאה ביצירת משלוח, הלוג רשם רק את הסטטוס ו-500 התווים הראשונים של התשובה — שהם דף שגיאת HTML של Rails, כלומר CSS בלבד. את המטען ששלחנו לא רשמנו כלל, ולכן כשל שתלוי במטען ספציפי (נמען אחד נכשל שוב ושוב בעוד כל שאר המשלוחים באותה דקה עוברים) לא היה ניתן לאבחון מהלוגים. מעכשיו נרשם המטען המלא שנשלח ל-/tasks/create, ודף ה-HTML מסוכם לכותרת ולהודעת השגיאה במקום להיחתך באמצע ה-CSS. תגובות JSON נשארות כפי שהן.
v01.190.001תיקוןהתראות שגיאת מיון / תור Green APIתוקן: הודעות מתיבת העסק נתקעו עד חצי שעה — cron התראות שגיאת-מיון הציף את תור השליחה
נציגים דיווחו שהודעות שנשלחו מתיבת העסק הגיעו ליעד רק אחרי חצי שעה ויותר (ונשארו עם ✓ בודד), בעוד שהודעות נכנסות הגיעו מיד.
פרטים נוספים ↓הסתר ↑
נציגים דיווחו שהודעות שנשלחו מתיבת העסק הגיעו ליעד רק אחרי חצי שעה ויותר (ונשארו עם ✓ בודד), בעוד שהודעות נכנסות הגיעו מיד. הסיבה: Green API מחזיר 200 ברגע שההודעה נכנסת ל*תור היוצא* שלו (לא כששלח בפועל) — ולכן ✓ בודד פירושו 'ממתינה בתור'. את התור הציף ה-cron של התראות שגיאת-מיון: התזמון ב-vercel.json הוא כל 5 דקות, אך תנאי החזרה בקוד היה 4 דקות בלבד — כך שכל התראה שלא אושרה נשלחה מחדש בכל ריצה, ללא תקרת חזרות, עד ~96 פעמים לאורך חלון 8 השעות. בפרודקשן נמצאו 145 התראות לא-מאושרות (עד 96 חזרות כל אחת, בגיל של עד 10 ימים), כולן לאותה קבוצה — כ-180 הודעות בשעה שחסמו את התור המשותף, וההודעות האינטראקטיביות של הנציגים המתינו מאחוריהן. התיקון: backoff מדורג בין חזרות (10 → 20 → 40 → 60 → 120 דקות) ותקרה קשיחה של 5 חזרות, כך שהתראה שלא אושרה עולה לכל היותר 6 הודעות (במקום 97) ופרושה על ~4 שעות. בנוסף, בדיקת האישור היקרה (getChatHistory לכל התראה) רצה מעכשיו רק על התראות שבאמת מגיע להן לחזור. הלולאות הפעילות נעצרו ידנית בפרודקשן.
v01.190.000חדשפורטל לקוחות / ניהול לקוחותminorיצירת קישור איפוס סיסמה למשתמש פורטל — מתוך כרטיס הלקוח
עד היום איפוס סיסמה לפורטל הלקוחות היה זמין רק ביוזמת הלקוח עצמו ורק דרך מייל, והטוקן מעולם לא נחשף לצד הטננט.
פרטים נוספים ↓הסתר ↑
עד היום איפוס סיסמה לפורטל הלקוחות היה זמין רק ביוזמת הלקוח עצמו ורק דרך מייל, והטוקן מעולם לא נחשף לצד הטננט. כשהמייל לא הגיע — או שהלקוח הקליד כתובת שגויה, והמסך מציג 'נשלח' גם כשלא נמצא משתמש כדי למנוע חשיפת כתובות — לא הייתה לצוות שום דרך לעזור: הכפתורים הקיימים הוגבלו למשתמש 'ממתין' (קישור הזמנה) או לחשבון בעלים בלבד (איפוס חשבון). מעכשיו לכל משתמש פורטל פעיל יש בכרטיס הלקוח כפתור 'צור קישור איפוס סיסמה' — נוצר קישור, מוצג להעתקה ידנית (לשליחה בוואטסאפ), וגם נשלח במייל. הפעולה אינה הרסנית: הסיסמה הקיימת ממשיכה לעבוד עד שהקישור ינוצל.
- כפתור 'צור קישור איפוס סיסמה' על כל משתמש פורטל בסטטוס פעיל, בסקציית 'משתמשי פורטל הלקוח'
- הקישור מוצג להעתקה בדיאלוג וגם נשלח במקביל למייל — עובד גם כשהמייל לא מגיע
- תוקף 24 שעות (לעומת 60 דקות באיפוס העצמי), כי הקישור מועבר ידנית; טקסט המייל מציג את התוקף הנכון
- פעולה לא הרסנית — הסיסמה הקיימת תקפה עד לניצול הקישור; ניצול הקישור גם משחרר חשבון נעול
- route חדש מאובטח בהרשאת CUSTOMERS_EDIT, מוגבל למשתמשי הטננט הנוכחי בלבד
v01.189.000חדשמסרוניםminorסטטיסטיקות לצ׳אט הלקוחות העסקיים
נוסף דף סטטיסטיקות ייעודי לצ׳אט הלקוחות העסקיים (מסרונים ← לקוחות עסקיים ← סטטיסטיקות עסקי).
פרטים נוספים ↓הסתר ↑
נוסף דף סטטיסטיקות ייעודי לצ׳אט הלקוחות העסקיים (מסרונים ← לקוחות עסקיים ← סטטיסטיקות עסקי). במרכזו גרף עמודות יומי — כל עמודה היא כמות ההודעות שנשלחו באותו יום, מפולחת לפי שולח: הבוט, לקוחות/משתמשי וואטסאפ, ומשתמשי המערכת (הצוות) — עם פילוח פנימי פר-משתמש. אפשר לעבור בין תצוגת כמות לתצוגת אחוזים (עמודות מנורמלות ל-100%) ובין טווח שבוע (ברירת מחדל), חודש או 3 חודשים. הסיווג מדויק ומשקף את לוגיקת התיבה עצמה: הודעות assistant=בוט, staff=מערכת, ו-user מפולח לצוות מול לקוח חיצוני לפי התאמת מספר הטלפון למשתמשי הטננט; הודעות פנימיות אינן נספרות כ׳נשלחו׳. בנוסף מוצגים: אחוז מענה אוטומטי, שיחות הממתינות למענה כרגע, דיווחי כשל של הבוט בתקופה, פילוח משתמשי המערכת, זמן תגובה חציוני/ממוצע להודעה נכנסת, תמונת החלטות הבוט (פעל/זיהה-ללא-פעולה/שתק) וסטטוס הטיפול הנוכחי.
- גרף עמודות יומי מוערם לפי שולח (AI / לקוחות וואטסאפ / צוות), עם tooltip הכולל ספירה, אחוזים ופילוח צוות יומי
- מעבר בין תצוגת כמות לאחוזים (100%) ובין טווח שבוע/חודש/3 חודשים
- פילוח הודעות פר-משתמש מערכת — מאחד נציג ששולח מהמערכת ומוואטסאפ תחת אותו משתמש
- כרטיסי KPI: סה"כ הודעות, אחוז מענה אוטומטי, ממתינות למענה, ודיווחי כשל של ה-AI
- מדדי בונוס: זמן תגובה חציוני/ממוצע, החלטות ה-AI וסטטוס טיפול נוכחי
- API חדש GET /api/ai/business-chat/stats מגודר בהרשאת messages:view
- תיקון סיווג ה-AI: הודעות תרחישי הבוט האוטומטיות נשמרות כ-role=staff/source=trigger (לא assistant) ולכן נספרו קודם כ׳צוות׳ — כעת קטגוריית ה-AI = assistant + trigger, והקטגוריה שונתה מ׳בוט׳ ל׳AI׳
v01.188.000חדשסוכניםminorסוכנים — פתיחת דוח העמלות החודשי לסוכן עצמו (פר-סוכן)
עד כה דוח העמלות החודשי של הסוכן היה גלוי רק למנהלים בדף הסוכן.
פרטים נוספים ↓הסתר ↑
עד כה דוח העמלות החודשי של הסוכן היה גלוי רק למנהלים בדף הסוכן. כעת הטננט יכול לפתוח זאת פר-סוכן: מתג חדש בטופס הסוכן ('צפייה בדוח העמלות שלו', כבוי כברירת מחדל) חושף לסוכן את דוח העמלות החודשי שלו ישירות בדשבורד הסוכן — כולל ניווט בין חודשים, פירוט לפי רכיב (מרווח, קבוע למשלוח, אחוז מהדוח, בונוס, עלויות, התאמות) וייצוא לאקסל. הגישה מוגבלת אך ורק לנתוני הסוכן עצמו — ה-agentId נגזר מה-session ולעולם לא מפרמטרים של הלקוח — ומצב המתג נקרא טרי בכל בקשה, כך שכיבויו מבטל את הגישה מיד. מנוע החישוב וייצוא ה-Excel משותפים עם המסלול הניהולי הקיים.
- מתג 'צפייה בדוח העמלות שלו' בטופס הסוכן — פר-סוכן, כבוי כברירת מחדל, נראה רק למנהלים
- כרטיס 'דוח העמלות שלי' בדשבורד הסוכן: ניווט חודשים, פירוט מלא וייצוא לאקסל
- מסלול עצמי מוגן /api/agent/earnings (+/export) — agentId מה-session בלבד ומותנה ב-selfEarningsVisible
- מנוע הדוח וייצוא ה-Excel חולצו ל-lib משותף (agent-earnings-export) בשימוש שני המסלולים
- תיקון גלילה בדשבורד הסוכן — הדף לא גלל (root ללא overflow-y-auto), כך שדוח העמלות נחתך בתחתית; הוגדר אזור גלילה תקין
- צמצום רווח הקצוות בדשבורד הסוכן ל-8px (p-6→p-2) ורווח בין הסקציות ל-16px — פחות מרווח מבוזבז
v01.187.001שיפורמסרוניםהסרת דף היסטוריית ההודעות (/messages)
דף 'היסטוריה' תחת מסרונים — טבלת כל ההודעות שנשלחו למשלוחים — הוסר כיוון שהיה מיותר.
פרטים נוספים ↓הסתר ↑
דף 'היסטוריה' תחת מסרונים — טבלת כל ההודעות שנשלחו למשלוחים — הוסר כיוון שהיה מיותר. הכניסה מהתפריט הצידי הוסרה, וקישור השורש /messages מפנה כעת לתיבת הנכנסות (/messages/inbox). נמחקו גם ה-API route הייעודי (/api/messages), פעולת השליחה-מחדש והרכיבים שהיו בשימוש בלעדי של הדף. שאר תתי-הדפים של מסרונים (נכנסות, לקוחות עסקיים, תבניות Meta, טריגרים, העדפות שליחה, עלויות) נותרו ללא שינוי.
v01.187.000חדשמשלוחיםminorמחיקת משלוח — צ'קבוקס לביטול גם בליונוויל
כל מחיקת משלוח (העברה לסל מיחזור) מציגה באישור צ'קבוקס חדש 'בטל את המשלוחים גם בליונוויל' (כבוי כברירת מחדל).
פרטים נוספים ↓הסתר ↑
כל מחיקת משלוח (העברה לסל מיחזור) מציגה באישור צ'קבוקס חדש 'בטל את המשלוחים גם בליונוויל' (כבוי כברירת מחדל). בסימון — המשימות המשויכות עוברות לסטטוס 'מבוטל' בליונוויל (PUT status=4; לליונוויל אין endpoint למחיקה מוחלטת) כחלק מאותה פעולה. משלוחים שכבר נמסרו/הושלמו לא מושפעים לעולם — לא מבטלים משלוח שנמסר. הביטול best-effort עם הגבלת קונקרנטיות: כשל מול ליונוויל לא מונע את המחיקה אצלנו. מומש דרך שירות משותף (cancelLionwheelTasksForShipments) ודגל cancelLionwheel יחיד ב-endpoint המחיקה, ומחובר בכל מסכי המחיקה הראשיים.
- צ'קבוקס 'בטל בליונוויל' בכל אישורי המחיקה: טבלת המשלוחים (מרובה + שורה), עמוד המשלוח, ואיסופים (שורה + קבוצה)
- ביטול = PUT /tasks/{id}/update עם status=4; משלוחים שהושלמו/נמסרו מדולגים (לא מבטלים משלוח שנמסר)
- best-effort — כשל מול ליונוויל לא מבטל את המחיקה עצמה; קונקרנטיות מוגבלת (rate limit)
- שירות משותף + דגל יחיד ב-bulk-delete = נקודת מעבר אחת לכל מסכי המחיקה
v01.186.001תיקוןאינטגרציית ווקומרסווקומרס — לא לייבא הזמנות שלא שולמו (on-hold ממתין לתשלום)
סטטוס on-hold ב-WooCommerce פירושו 'ממתין לתשלום' (שיטות תשלום offline, או שער תשלום שמשאיר את ההזמנה פתוחה כשהקונה לא השלים תשלום).
פרטים נוספים ↓הסתר ↑
סטטוס on-hold ב-WooCommerce פירושו 'ממתין לתשלום' (שיטות תשלום offline, או שער תשלום שמשאיר את ההזמנה פתוחה כשהקונה לא השלים תשלום). המערכת ייבאה ושיגרה אותן אוטומטית כאילו שולמו — כך נשלחו חבילות אמיתיות ללקוחות שרק ביקרו/עשו צ'קאאוט בלי לשלם. מעכשיו הזמנת on-hold מיובאת רק אם WooCommerce רשמה תשלום בפועל (date_paid) — מה שמכסה גם שער תשלום שמחזיק זמנית הזמנה ששולמה. processing/completed ממשיכים כרגיל (כולל הזמנות ₪0 חינם ללא date_paid). נוסף predicate טהור isOrderImportable עם בדיקות יחידה, ותוקן טקסט מטעה בעמוד חיבור החנות שהציג on-hold כ'התקבל תשלום'.
v01.186.000חדשאינטגרציית ווקומרסminorאינטגרציית ווקומרס — פירוט מאפייני פריט (חוברת לנשים/לגברים וכו')
עד כה בייבוא הזמנות מווקומרס נשמרו רק שם הפריט, הכמות והמחיר — ומאפייני השורה שווקומרס מציג מתחת לפריט (כמו 'חוברת לנשים', 'חוברת לגברים', 'סה"כ חוברות') נזרקו במיפוי.
פרטים נוספים ↓הסתר ↑
עד כה בייבוא הזמנות מווקומרס נשמרו רק שם הפריט, הכמות והמחיר — ומאפייני השורה שווקומרס מציג מתחת לפריט (כמו 'חוברת לנשים', 'חוברת לגברים', 'סה"כ חוברות') נזרקו במיפוי. כעת המאפיינים נקלטים מ-line_item meta_data של ההזמנה ומוצגים כשורת פירוט אפורה מתחת לשם הפריט ב'פריטי המשלוח' — בדיוק כפי שהם מופיעים במסך ההזמנה בווקומרס. מסוננים מאפייני meta פנימיים של ווקומרס (מפתחות שמתחילים ב-_) ומנוקה HTML מהערכים. נוסף גם סקריפט backfill שמושך מחדש הזמנות קיימות (שליפה מרוכזת דרך include=) ומשלים את הפירוט על משלוחים שכבר נכנסו.
- קליטת מאפייני שורה (meta_data) מהזמנות ווקומרס והצגתם מתחת לשם הפריט ב'פריטי המשלוח'
- עמודת meta חדשה ב-OrderItem — נשמרת בייבוא ונשמרת גם בעריכת פריטים ידנית
- סקריפט backfill למשלוחים קיימים, עם שליפה מרוכזת דרך include= (עוקף 401 בנתיב /orders/{id})
- endpoint אדמין מוגן להרצת ה-backfill בפרודקשן (שם ENCRYPTION_KEY זמין) — dry כברירת מחדל, ?run=1 להרצה בפועל
- הפירוט מוצג גם בעמודת הפריטים בטבלת הליקוט ובחלון משלוחי הלקוח — צ'יפ עם מונה פריטים שנפתח בריחוף לכרטיסיית פירוט (חוברות לנשים/לגברים/סה"כ)
- בדיקות יחידה לחילוץ המאפיינים (סינון meta פנימי, העדפת display_key/value, ניקוי HTML)
v01.185.000חדשיעד אקספרסminorיעד אקספרס — הוספת משלוחים מרובים לפי מספר
נוסף כפתור 'הוספת משלוחים' לסרגל הכלים של דף יעד אקספרס, שפותח חלון להגדרת יעד אקספרס לרשימת משלוחים לפי מספרי משלוח — בדיוק כמו שקיים בדף יעד שבת.
פרטים נוספים ↓הסתר ↑
נוסף כפתור 'הוספת משלוחים' לסרגל הכלים של דף יעד אקספרס, שפותח חלון להגדרת יעד אקספרס לרשימת משלוחים לפי מספרי משלוח — בדיוק כמו שקיים בדף יעד שבת. מדביקים רשימת מספרים (כפילויות מוסרות אוטומטית), בוחרים תאריך יעד (צ'יפים מהירים להיום/מחר/הימים הקרובים או בורר תאריך חופשי), והמשלוחים מסומנים כאקספרס גם אם אינם מוצגים בטבלה כרגע. בסיום מוצג פירוט של מה עודכן ומה לא נמצא.
- כפתור 'הוספת משלוחים' + חלון ייעודי בדף יעד אקספרס
- הדבקת רשימת מספרי משלוח עם הסרת כפילויות אוטומטית
- בחירת תאריך יעד עם צ'יפים מהירים (היום/מחר/הימים הקרובים) ובורר תאריך
- עדכון מרוכז דרך endpoint חדש set-target-express-by-barcodes עם פירוט תוצאות
v01.184.003תיקוןשליחיםדף שליח — לינק הגדרת סיסמה נחתך מעבר לרוחב החלון
בחלון 'לינק הגדרת סיסמה' (כפתור לינק כניסה בדף השליח) מחרוזת ה-token הארוכה הרחיבה את תוכן החלון הרבה מעבר לרוחבו ומעבר לרוחב המסך — כך שגם קופסת הקישור וגם כפתור 'העתק קישור' נחתכו.
פרטים נוספים ↓הסתר ↑
בחלון 'לינק הגדרת סיסמה' (כפתור לינק כניסה בדף השליח) מחרוזת ה-token הארוכה הרחיבה את תוכן החלון הרבה מעבר לרוחבו ומעבר לרוחב המסך — כך שגם קופסת הקישור וגם כפתור 'העתק קישור' נחתכו. ה-truncate הקיים לא נכנס לפעולה: DialogContent הוא display:grid, וה-div העוטף הוא grid-item עם min-width: auto — כלומר רוחב מינימלי לפי min-content, שהוא עצום בגלל ה-token ב-white-space: nowrap. נוסף min-w-0 לעוטף (וגם ל-flex-row ול-span שמציג את הקישור), כך שהתוכן מתכווץ והקישור מקוצר עם '...' בתוך גבולות החלון. אומת ברוחבי מסך 390px ו-900px.
v01.184.002שיפורתיבת העסקתיבת העסק — הסרת קו 'חיבור ה-WhatsApp נותק/חזר' מתוך הצ'אטים
הקו המערכתי שהוצג בתוך הצ'אטים ('חיבור ה-WhatsApp נותק ב-...
פרטים נוספים ↓הסתר ↑
הקו המערכתי שהוצג בתוך הצ'אטים ('חיבור ה-WhatsApp נותק ב-... · חזר ב-...') הוסר. הוא הופיע בכל שיחה בכל פעם שחיבור ה-Green API נותק וחזר — לרוב לרגעים בודדים — והוסיף רעש ויזואלי מיותר לתוך שרשור ההודעות. הוסר לחלוטין מהתצוגה (הקוד, ה-state והבאת הנתונים הנלווים נוקו).
v01.184.001חדשתיבת העסקתיבת העסק — תיוגי וואטסאפ רשמיים מוצגים עם שם (ואווטר לאיש צוות)
תיוג רשמי של וואטסאפ בתוך הודעה (@מספר) הוצג עד עכשיו כמספר גולמי.
פרטים נוספים ↓הסתר ↑
תיוג רשמי של וואטסאפ בתוך הודעה (@מספר) הוצג עד עכשיו כמספר גולמי. מעכשיו הוא מזוהה ומוצג יפה: אם המספר שייך לאיש צוות מוכר — מוצג שמו במערכת לצד האווטר שלו (צ'יפ ירוק); אם זה משתתף קבוצה שהמערכת מכירה מהודעות שהוא שולח — מוצג שמו בדיוק כפי שהוא מוצג מעל ההודעות שלו (בצבע הדובר); ואם המספר לא מזוהה כלל — נשאר כ-@מספר פשוט. הזיהוי נעשה מהטקסט הגולמי של ההודעה (שכבר מכיל את @מספר) בשילוב מפת טלפוני הצוות ושמות המשתתפים של אותה שיחה — בלי שאילתות DB נוספות. חל על תיוגים רשמיים של וואטסאפ בלבד (לא על התיוג הפנימי שלנו בהערות צוות).
v01.184.000שיפורתיבת העסקminorתיבת העסק — שני פילטרים נפתחים ('סוג' + 'מצב') במקום שורת צ'יפים, עם סינון לפי לא-נקראו / ממתינות / טיפול
שורת הצ'יפים השטוחה הוחלפה בשני פילטרים נפתחים (pill-dropdown), שניהם מאותחלים על 'הכל': (1) 'סוג' — הכל / לקוחות / שליחים / קבלנים / אנשי צוות / לא משוייכים.
פרטים נוספים ↓הסתר ↑
שורת הצ'יפים השטוחה הוחלפה בשני פילטרים נפתחים (pill-dropdown), שניהם מאותחלים על 'הכל': (1) 'סוג' — הכל / לקוחות / שליחים / קבלנים / אנשי צוות / לא משוייכים. (2) 'מצב' — חדש: הכל / לא נקראו / ממתינות לתשובה / בטיפול / טופל. 'ממתינות לתשובה' = ההודעה האחרונה בצ'אט היא מהצד השני ומחכים שנגיב — הפילטר התפעולי הכי שימושי. 'בטיפול'/'טופל' לפי סטטוס הטיפול המשותף של הצוות. צ'יפ 'תיוגים שלי' (אזכורים) נשאר כפי שהיה. שני הפילטרים פועלים בצד השרת, כך שכל התוצאות מוחזרות במלואן ומתדפדפות חלק (במקום 'לזחול' פנימה תוך כדי טעינת עמודים — לא-נקראו לבד הגיע ל-37 צ'אטים). כן בוטלה טבעת הפוקוס האגרסיבית שהופיעה על הפילטרים.
- שני פילטרים נפתחים ('סוג' + 'מצב') במקום שורת צ'יפים — נקי ומתרחב
- פילטר 'מצב' חדש: לא נקראו / ממתינות לתשובה / בטיפול / טופל
- 'ממתינות לתשובה' — צ'אטים שבהם הצד השני כתב אחרון ומחכים שנגיב
- 'בטיפול'/'טופל' לפי סטטוס הטיפול המשותף של הצוות
- הסינון בצד השרת — כל התוצאות במלואן, ללא 'קפיצות' של תוצאות שנוספות תוך כדי גלילה
- בוטלה טבעת הפוקוס על הפילטרים; צ'יפ 'תיוגים שלי' נשמר
v01.183.002תיקוןתיבת העסקתיבת העסק — זיהוי נכון של טלפונים וברקודים בהודעות (ברקוד → דראוור משלוח)
כשלקוח שלח רשימת מספרי משלוח לבירור (למשל '25570283 25570285 25570287…'), הם זוהו בטעות כמספרי טלפון: הזיהוי 'תפס' ספרת 0 שנמצאת באמצע ברקוד (…2557‹0›283…) ובלע ספרות נוספות מעבר לרווחים שבין הברקודים, כך שנוצרו 'מספרים'…
פרטים נוספים ↓הסתר ↑
כשלקוח שלח רשימת מספרי משלוח לבירור (למשל '25570283 25570285 25570287…'), הם זוהו בטעות כמספרי טלפון: הזיהוי 'תפס' ספרת 0 שנמצאת באמצע ברקוד (…2557‹0›283…) ובלע ספרות נוספות מעבר לרווחים שבין הברקודים, כך שנוצרו 'מספרים' מומצאים עם קידומות/סיומות לא-קשורות, ולחיצה עליהם פתחה צ'אט דמיוני עם מספר שלא יכול להיות טלפון. תוקן בשניים: (1) זיהוי טלפון עכשיו דורש פורמט ישראלי תקין ומלא כטוקן עצמאי — קידומת (0 או +972), 'ראש' אמיתי (נייד 5X / VoIP 7X / קידומת קו-נייח 2,3,4,8,9), ואז מספר הספרות המדויק, עם גבולות שמונעים התחלה באמצע רצף ספרות של ברקוד. (2) ברקודים מזוהים עכשיו כברקוד ולחיצים: השרת סורק את ההודעות אחר טוקנים ברקוד-דמויי ומחזיר רק את אלה שהם משלוחים אמיתיים בטננט (אימות מול DB, בלי ניחוש פורמט ובלי דליפה בין-טננטית) — וכל ברקוד כזה מוצג כצ'יפ עם העתקה/פתיחה שפותח דראוור תצוגה-מהירה של המשלוח, בדיוק כמו ב-/messages/inbox.
v01.183.001שיפורתיבת העסקתיבת העסק — צ'אט עם מספר של איש צוות מציג את שמו במערכת (חיפוש + סינון ייעודי)
צ'אט 1:1 עם מספר טלפון ששייך למשתמש מערכת (איש צוות) הציג עד עכשיו רק את המספר.
פרטים נוספים ↓הסתר ↑
צ'אט 1:1 עם מספר טלפון ששייך למשתמש מערכת (איש צוות) הציג עד עכשיו רק את המספר. מעכשיו הוא מציג את שם איש הצוות בדיוק כפי שהוא רשום במערכת (וגם את תמונת הפרופיל שלו כ-fallback), ברשימת השיחות ובכותרת הצ'אט. בנוסף, הקלדת שם איש הצוות בחיפוש מחזירה את הצ'אט שלו בתוצאות — הזיהוי לפי מפת טלפוני הצוות של הטננט (getTenantStaffPhoneMap), עם בניית מזהה השיחה הדטרמיניסטי (972<מספר>@c.us) לצד ההתאמה. חל רק על צ'אטים אישיים שאינם משויכים ללקוח עסקי; קבוצות וצ'אטים של לקוחות לא מושפעים. בנוסף נוסף צ'יפ סינון 'אנשי צוות' לצד 'הכל'/'לקוחות'/'שליחים'/'קבלנים'/'לא משויכים', שמציג רק את השיחות האישיות עם אנשי צוות; שיחות אלה גם הוצאו מקטגוריית 'לא משויכים' (כי כעת יש להן קטגוריה משלהן).
v01.183.000חדשצ'אט לקוחות עסקייםminorצ׳אט לקוחות — קו 'הודעות שלא נקראו' ופתיחה ישירות עליו (כמו בוואטסאפ)
עד היום, כשנכנסת לשיחה בתיבת צ'אט הלקוחות העסקיים שהצטברו בה הודעות חדשות, לא היה שום סימן ויזואלי איפה נגמר מה שכבר קראת ואיפה מתחילות ההודעות החדשות — והצ'אט תמיד נפתח בתחתית, כך שהיית צריך לגלול למעלה ולנחש.
פרטים נוספים ↓הסתר ↑
עד היום, כשנכנסת לשיחה בתיבת צ'אט הלקוחות העסקיים שהצטברו בה הודעות חדשות, לא היה שום סימן ויזואלי איפה נגמר מה שכבר קראת ואיפה מתחילות ההודעות החדשות — והצ'אט תמיד נפתח בתחתית, כך שהיית צריך לגלול למעלה ולנחש. מעכשיו, כמו בוואטסאפ האמיתי: לפני ההודעה הראשונה שלא נקראה מוצג קו מפריד ברור ('N הודעות שלא נקראו'), והצ'אט נפתח אוטומטית ממוקם בדיוק על הקו הזה — עם מעט הקשר מעליו — גם אם אחריו יש עשרות או מאות הודעות. מספר ההודעות שלא נקראו נלקח ממצב הקריאה האמיתי של השיחה (נתפס ברגע הפתיחה, לפני סימון-כנקרא), וההודעה הראשונה שלא נקראה מזוהה כ-N ההודעות הנכנסות האחרונות. הקו נשאר במקומו כל עוד השיחה פתוחה (הודעות חדשות שמגיעות לא מזיזות אותו) ומתאפס במעבר לשיחה אחרת. משתלב עם כפתור הגלילה-לתחתית ומונה ההודעות החדשות שנוספו קודם.
- קו מפריד 'N הודעות שלא נקראו' לפני ההודעה הראשונה שטרם נקראה (עיצוב ירוק, כמו וואטסאפ)
- פתיחת הצ'אט נוחתת אוטומטית על הקו — לא בתחתית — גם כשיש אחריו הרבה הודעות
- מבוסס על מצב הקריאה האמיתי של השיחה (unreadCount) שנתפס לפני סימון-כנקרא
- הקו יציב: הודעות חדשות שמגיעות תוך כדי לא מזיזות אותו; מתאפס במעבר שיחה
- פתיחה מחיפוש/דיפ-לינק להודעה ספציפית עדיין קופצת להודעה המבוקשת (גובר על הקו)
v01.182.000חדשתיבת העסק / בוט תפעוליminorדיווח על כשלי בוט מתוך תיבת העסק + דף סקירה לניתוח תקופתי
במקום לחפש ידנית כשלים של הבוט בקבוצות ולנתח כל אחד בנפרד — לולאת משוב מובנית.
פרטים נוספים ↓הסתר ↑
במקום לחפש ידנית כשלים של הבוט בקבוצות ולנתח כל אחד בנפרד — לולאת משוב מובנית. על כל הודעה בתיבת העסק (קליק ימני/לחיצה ארוכה) נוסף 'דווח על כשל בוט': הצוות מסמן תשובה לא ראויה של הבוט או הודעה שהבוט התעלם ממנה, ובחלונית מתאר למה זה נראה ככשל ומה הוא ממליץ לתקן. הדיווח נשמר עם snapshot של ההקשר (השיחה, ההודעה המסומנת, מי דיווח ומתי). כל כמה ימים עוברים על הדיווחים שהצטברו בדף ייעודי בהגדרות (AI → 'דיווחי כשל'): כל דיווח מציג את ההודעה, התיאור וההמלצה, ומאפשר לפתוח את השיחה עצמה בדיוק בהודעה המדווחת (עם ההודעות שלפני ואחרי) לצורך ניתוח, ולסמן סטטוס (נסקר/טופל/נדחה).
- כפתור 'דווח על כשל בוט' על כל הודעה בתיבת העסק — עובד גם על תשובה שגויה של הבוט וגם על הודעה שהבוט התעלם ממנה
- טופס קצר: 'למה נראה שכשל' + 'מה להמליץ לתקן' (רשות); נשמר עם הקשר מלא של השיחה וההודעה
- דף סקירה בהגדרות (AI → דיווחי כשל) עם סינון לפי סטטוס וספירות, לניתוח תקופתי מרוכז
- 'פתח בצ׳אט' בכל דיווח מקפיץ ישירות לשיחה ולהודעה המדווחת, עם ההקשר שלפני ואחרי
- סימון סטטוס לכל דיווח: נסקר / טופל / נדחה / החזרה לפתוח
v01.181.000חדשצ'אט לקוחות עסקיים / חיפושminorצ׳אט לקוחות — חיפוש בתוך תוכן ההודעות + קפיצה ישירה להודעה (כמו בוואטסאפ)
עד היום החיפוש בתיבת צ'אט הלקוחות העסקיים החזיר רק את השיחה (לפי שם/טלפון), ואם ההתאמה הייתה בתוך גוף הודעה — השיחה נפתחה בתחתית, בלי לראות איפה בכלל נמצאה המילה.
פרטים נוספים ↓הסתר ↑
עד היום החיפוש בתיבת צ'אט הלקוחות העסקיים החזיר רק את השיחה (לפי שם/טלפון), ואם ההתאמה הייתה בתוך גוף הודעה — השיחה נפתחה בתחתית, בלי לראות איפה בכלל נמצאה המילה. מעכשיו החיפוש עובד כמו בוואטסאפ האמיתי: התוצאות מחולקות לשתי סקציות — 'צ'אטים' (התאמות לפי שם/טלפון/כותרת) ו'הודעות' (התאמות בתוך תוכן ההודעות). כל הודעה תואמת מוצגת בשורה נפרדת עם קטע-טקסט (snippet) ממוקד סביב המילה, כשהמילה שחיפשת מודגשת, לצד שם הצ'אט וזמן ההודעה. לחיצה על תוצאה פותחת את הצ'אט וגוללת ישירות אל ההודעה עצמה — נחיתה מיידית סמוך אליה ואז גלילה חלקה וקצרה שעוצרת עליה, עם הבהוב הדגשה כדי שקל לאתר אותה. מבוסס על אינדקס pg_trgm הקיים על תוכן ההודעות.
- תוצאות חיפוש בשתי סקציות: 'צ'אטים' (שם/טלפון/כותרת) ו'הודעות' (תוכן) — כמו בוואטסאפ
- כל הודעה תואמת = שורה נפרדת עם snippet ממוקד והמילה המחופשת מודגשת
- לחיצה על תוצאת הודעה פותחת את הצ'אט וקופצת ישירות אל ההודעה, עם גלילה חלקה קצרה והבהוב הדגשה
- החיפוש בתוכן גלובלי על פני כל השיחות בתצוגה הנוכחית (תיבה/ארכיון); מוצגות עד 50 תוצאות הודעה
- endpoint חדש /api/ai/business-chat/messages/search; חיפוש ה'צ'אטים' צומצם לשם/טלפון/כותרת (התאמות תוכן עברו לסקציית ההודעות)
v01.180.000חדשבוט תפעולי / שידור + גישורminorבוט שידור — קבלן שמבקש שידור על משלוח שמשובץ לקבלן אחר מקבל אותו (שיבוץ-מחדש אוטומטי)
כשקבלן ביקש 'תשדרו' על משלוח שכבר היה משודר — הבוט השיב 'כבר היה משודר אליך' והפסיק, גם כשהמשלוח היה בכלל משובץ לקבלן אחר.
פרטים נוספים ↓הסתר ↑
כשקבלן ביקש 'תשדרו' על משלוח שכבר היה משודר — הבוט השיב 'כבר היה משודר אליך' והפסיק, גם כשהמשלוח היה בכלל משובץ לקבלן אחר. התוצאה: הבוט 'שיקר' (זה לא היה משודר אליו), לא עשה כלום, ובן אדם נאלץ לשבץ ידנית (אירוע פרודקשן 07-07, קבוצת 'שלום דוד', משלוח 25548227 — הקבלנים אף לעגו לבוט). הסיבה: הבדיקה 'כבר משודר' הסתפקה בקיום מזהה שידור כלשהו, בלי לבדוק למי המשלוח משובץ. התיקון: 'כבר משודר אליך' חל מעכשיו רק כשהמשלוח באמת משובץ לקבלן המבקש (או לתת-שליח שלו). כשהוא משובץ לקבלן אחר ויש משימת מסירה פעילה — בקשת שידור מפורשת מפעילה שיבוץ-מחדש: הבוט מעביר את המשלוח לקבלן המבקש, משדר מחדש, ומשיב 'הועבר אליך ושודר ✅' עם מספר השידור החדש. אם המשלוח כבר נמסר/הושלם (אין משימה פעילה) — לא נוגעים בו, כמו קודם.
- 'כבר משודר אליך' חל רק כשהמשלוח באמת משובץ לקבלן המבקש — לא עוד הודעה שגויה כשהוא משובץ לאחר
- בקשת שידור על משלוח של קבלן אחר (שעדיין לא נמסר) מעבירה אותו אוטומטית למבקש ומשדרת מחדש — 'הועבר אליך ושודר ✅'
- מזהה השידור בתשובה נקרא טרי מהספק (לא מציג את מזהה הקבלן הקודם); אם עדיין לא התעדכן — מוצג בלי מזהה במקום מזהה שגוי
- לא נוגעים במשלוח שכבר נמסר/הושלם; שיבוץ-מחדש מכבד גם תת-שליחים של אותו קבלן
- ניתן לעריכה בהגדרות → תרחישי בוט (תבניות 'הועבר מקבלן אחר אליך')
- גישור 'אין מענה': דיווח קבלן על ברקוד ספציפי במצב 'נכשל' (FAILED — 'עדיין אפשר לטפל') כבר לא נחסם, כי זה בדיוק המצב שבו הקבלן ממשיך לנסות וזקוק לטלפון/הנחיה מהלקוח (החמצה שאותרה בקבוצת 'זיפ', משלוח 25885959). 'נכשל סופית'/נמסר/בוטל עדיין חסומים
v01.179.001שיפורפורטל שליחיםפורטל שליחים — כל החלק העליון קבוע, רק הרשימות גוללות + הסבר לכל טאב
שיפור חווית גלילה בפורטל השליחים: הפורטל עבר למבנה גובה-קבוע (flex column על מלוא גובה המסך) כך שכל החלק העליון — סרגל הברכה, מתגי הטאבים (הדוח שלי/צ'קליסט/מעוכבים/יעד שבת), וכן הבקרות הפנימיות של כל טאב (סינון, צ'יפים ל…
פרטים נוספים ↓הסתר ↑
שיפור חווית גלילה בפורטל השליחים: הפורטל עבר למבנה גובה-קבוע (flex column על מלוא גובה המסך) כך שכל החלק העליון — סרגל הברכה, מתגי הטאבים (הדוח שלי/צ'קליסט/מעוכבים/יעד שבת), וכן הבקרות הפנימיות של כל טאב (סינון, צ'יפים לאזורים, פס ההתקדמות של הצ'קליסט, כותרת הפרשה, בורר התקופה בדוח) — נשאר קבוע וסטיקי, ורק רשימות המשלוחים גוללות (overflow-y-auto פנימי). קודם כל העמוד גלל יחד עם הבקרות. חל על כל ארבעת הטאבים. בנוסף נוספה שורת הסבר קצרה (עם אייקון) בראש כל טאב שמסבירה לשליח מה משמעות הטאב וכיצד להשתמש בו. וכן עוצב מחדש כרטיס המשלוח בטאב 'יעד שבת': שם השולח (מקור) מוצג בגדול במקום שם הנמען, מזהה המשלוח הוגדל ועלה למעלה (מוצמד לימין, שם השולח לשמאל באותה שורה), אזור ההפצה מוצג כצ'יפ קטן ופחות דומיננטי לצד צ'יפ הסטטוס (סטטוס מימין, אזור משמאל), ופרטי הנמען עם כתובת מלאה עברו לשורת פרטים תחתונה עם אייקונים. אותם עקרונות הוחלו גם על כרטיסי הצ'קליסט והמעוכבים דרך רכיב כרטיס משותף (PortalCard): בצ'קליסט האזור מוצג כצ'יפ קטן לצד תג הדחיפות; במעוכבים תג ימי-העיכוב נשאר הדומיננטי למעלה והאזור עבר לשורת הפרטים התחתונה. כמו כן נוספה בדף השליח בממשק הניהול טבלת 'צ'קליסט' מלאה (באותו סגנון כשאר טבלאות המשלוחים בדף) המציגה למנהל את המשלוחים שהשליח מחוייב לנקות מהמחסן, כולל עמודת דחיפות — נטענת מ-/api/drivers/[id]/checklist.
v01.179.000חדשפורטל שליחים / טריגריםminorפורטל שליחים — טאב 'צ'קליסט' יומי + תזכורות וואטסאפ אוטומטיות
טאב חדש 'צ'קליסט' בפורטל השליחים, לצד 'מעוכבים' ו'יעד שבת'.
פרטים נוספים ↓הסתר ↑
טאב חדש 'צ'קליסט' בפורטל השליחים, לצד 'מעוכבים' ו'יעד שבת'. הרשימה מרכזת את המשלוחים שהשליח חייב 'לנקות' (להוציא להפצה) מהמחסן ביום ההפצה הבא כדי לא לחרוג מימי ההתחייבות — בדיוק אותו חישוב של טאב 'יום אחרון להפצה' בדף פערי ההפצה (שעון תאריך-גורם + ימי עסקים + חגים), אך צופה קדימה ליום ההפצה הבא של השליח. הרשימה 'מתגלגלת' בשעת איפוס אישית פר-שליח (ברירת מחדל 18:00 שעון ישראל) ולא בחצות, כוללת רק משלוחים בסטטוס 'נקלט במחסן' (יורדים מיד כשעוברים ל'יצא להפצה'), משויכת לפי אזורי האחריות של השליח, ובימי רביעי–שישי מצרפת גם משלוחי 'יעד שבת' לקו. הדף מתעדכן אונליין (polling) כך שהשליח רואה את הרשימה מצטמצמת עד שהיא נקייה. נוספו שני טריגרי וואטסאפ נערכים (ב-/messages/triggers) שנשלחים לקבוצת השליח: תזכורת יומית בשעת האיפוס, ותזכורת 'התחיל ולא סיים'. תג הצ'קליסט וסטטוס העיכוב מוצגים גם בדף המשלוח הפנימי.
- חישוב זהה ל'יום אחרון להפצה', צופה קדימה ליום ההפצה הבא; גלגול בשעת איפוס אישית פר-שליח (בר"מ 18:00) במקום חצות
- רק סטטוס 'נקלט במחסן', שיוך לפי אזורי אחריות, צ'יפים לניווט בין אזורים, ובימי ד'–ו' צירוף משלוחי יעד שבת
- פס התקדמות 'נוקו X מתוך Y' (מבוסס snapshot יומי), תגי דחיפות ('יום אחרון!' / 'חרג ב-N'), ומיון לפי דחיפות
- סנכרון אונליין — הרשימה מצטמצמת בזמן אמת ככל שמשלוחים יוצאים להפצה; אפשרות לרשום הערה 'למה לא יצא'
- שני טריגרי וואטסאפ נערכים לקבוצת השליח: תזכורת יומית ותזכורת 'התחיל ולא סיים' (15 דק' מהניקוי האחרון)
- פאנל צ'קליסט/עיכוב בדף המשלוח הפנימי; ותיקון: מעבר סטטוס ידני מציב כעת גם 'תאריך גורם' ו'תאריך יציאה' (sticky)
v01.178.004תיקוןמסרונים / רינדור תבניותמסרונים — שעה/תאריך בהודעות ללקוח לפי שעון ישראל (תיקון 3 שעות אחורה)
המשתנים {{current_time}} ו-{{current_date}} בתבניות ההודעה (טריגרים אוטומטיים, תיבת דואר, סוכן AI, resend) חושבו בשעון השרת של Vercel שהוא UTC — כלומר 3 שעות אחורה משעון ישראל בקיץ.
פרטים נוספים ↓הסתר ↑
המשתנים {{current_time}} ו-{{current_date}} בתבניות ההודעה (טריגרים אוטומטיים, תיבת דואר, סוכן AI, resend) חושבו בשעון השרת של Vercel שהוא UTC — כלומר 3 שעות אחורה משעון ישראל בקיץ. לקוח שקיבל הודעה ב-08:40 ('ניסינו להשיג אותך') ראה 'מועד הניסיון 05:40'. הפורמטרים ב-template-renderer היו היחידים במערכת שלא ציינו timeZone (בשונה מ-employee-triggers, lead-triggers, sorting-error-utils שכבר נעולים ל-Asia/Jerusalem). נוסף timeZone: 'Asia/Jerusalem' לשני הפורמטרים — מודע לשעון קיץ/חורף.
v01.178.003שיפוראפליקציית שליחיםאפליקציית שליחים — כתובת ותוויות ברשימת המשימות, ניקוי הכרטיס וכפתור השיתוף
סבב שיפורים לרשימת המשימות ולמסך המשלוח בעקבות משוב שליחים: (1) הכתובת והעיר לא הופיעו בכרטיסי המשלוח — ה-API בנה את הכתובת רק משדות ה-Visit, שריקים במשלוחי Lionwheel (הכתובת חיה על המשלוח).
פרטים נוספים ↓הסתר ↑
סבב שיפורים לרשימת המשימות ולמסך המשלוח בעקבות משוב שליחים: (1) הכתובת והעיר לא הופיעו בכרטיסי המשלוח — ה-API בנה את הכתובת רק משדות ה-Visit, שריקים במשלוחי Lionwheel (הכתובת חיה על המשלוח). כעת ה-API (רשימת היום + פרטי משלוח) נופל לכתובת מהמשלוח כשה-Visit ריק — כך רחוב, מספר ועיר מוצגים תמיד. תיקון צד-שרת, חל מיד גם על בניות קיימות. (2) נוספה תווית 'X חבילות' לכרטיס משלוח עם יותר מחבילה אחת (לצד התוויות הקיימות: גוביינא, דחוף, אקספרס, שבת). (3) הוסרה שורת שלושת הכפתורים (התקשר/וואטסאפ/נווט) מהכרטיס המודגש של העצירה הבאה — היא לא פעלה והייתה מיותרת, שכן לחיצה ארוכה על כל משלוח פותחת ממילא גיליון פעולות מעוצב עם אותן פעולות. (4) כפתור 'שתף פרטי משלוח' במסך המשלוח מפיק כעת טקסט זהה בדיוק לכפתור 'העתק פרטי יעד' בכרטיס יעד המשלוח בממשק הניהול (משלוח / שם / רחוב / דירה / קומה / עיר / טלפון עם אימוג'ים). בנוסף, לקראת פרסום מקביל ב-App Store של Apple — נוסף דגל תאימות הצפנה (ITSAppUsesNonExemptEncryption=false) ל-Info.plist, כדי לחסוך את שאלת תאימות-הייצוא בכל הגשה ל-App Store (האפליקציה משתמשת רק ב-HTTPS סטנדרטי, פטור מייצוא).
- כתובת ועיר מוצגות תמיד בכרטיסי המשלוח (fallback לכתובת מהמשלוח כשה-Visit ריק) — חל מיד גם על גרסאות מותקנות
- תווית 'X חבילות' למשלוח מרובה-חבילות בכרטיס הרשימה
- הוסרה שורת הכפתורים הלא-פעילה מהכרטיס המודגש — הפעולות זמינות בלחיצה ארוכה
- שיתוף פרטי משלוח בפורמט זהה להעתקה בממשק הניהול
v01.178.002תיקוןמסרונים / תיבת דואר נכנסתיבת דואר — תבנית שנשלחה מוצגת בצ'אט עם הערכים האמיתיים
כששלחו תבנית Meta מאושרת מהצ'אט ב-messages/inbox, בועת ההודעה בצ'אט של Shipnest הציגה את גוף התבנית הגולמי עם שמות המשתנים ({{destination_name}}, {{barcode}}, {{source_name}}) במקום הערכים שמולאו.
פרטים נוספים ↓הסתר ↑
כששלחו תבנית Meta מאושרת מהצ'אט ב-messages/inbox, בועת ההודעה בצ'אט של Shipnest הציגה את גוף התבנית הגולמי עם שמות המשתנים ({{destination_name}}, {{barcode}}, {{source_name}}) במקום הערכים שמולאו. הלקוח עצמו קיבל את ההודעה המלאה והנכונה — Meta מבצעת את ההחלפה בצד שלה — אבל בתצוגה הפנימית נשמר ה-preview הגולמי (tpl.body) ולא הטקסט המוחלף, מה שיצר רושם מטעה שההודעה נשלחה עם שמות המשתנים. כעת נתיב השליחה מחליף את ערכי הפרמטרים (לפי metaParamMap: variable→position) לתוך גוף התבנית לפני שמירת הבועה, כך שהצ'אט מציג בדיוק את מה שהלקוח קיבל.
v01.178.001תיקוןבוט WhatsApp / Business Inboxבוט — קישור מעקב אמיתי במקום placeholder מהוזה
כשלקוח בצ'אט 1:1 ביקש 'שלח לי לינק', סוכן הלקוח החזיר placeholder מהוזה ('[קישור למעקב דמיוני]') — כי לא היה לו שום כלי שמפיק URL אמיתי, וה-prompt לא הזכיר קישורים כלל.
פרטים נוספים ↓הסתר ↑
כשלקוח בצ'אט 1:1 ביקש 'שלח לי לינק', סוכן הלקוח החזיר placeholder מהוזה ('[קישור למעקב דמיוני]') — כי לא היה לו שום כלי שמפיק URL אמיתי, וה-prompt לא הזכיר קישורים כלל. נוסף כלי getShipmentLinks שמחזיר את אותם קישורי מעקב ('/tracking/{public_id}') ועדכון פרטי מסירה ('/validate/{public_id}') המופיעים תחת 'קישורים להעתקה' בדף המשלוח. אם לא סופק ברקוד — הכלי בוחר אוטומטית את המשלוח הפעיל היחיד, ואם יש כמה פעילים הוא מחזיר needBarcode והבוט מבקש מספר משלוח. ה-prompt חוזק באיסור מוחלט להמציא קישור.
v01.178.000חדששליחים / קבלן-מנהלminorשליחים — ניתוק סאב-שליח מבוסס תאריך (כולל רטרואקטיבי)
הסרת סאב-שליח מצוות של קבלן-מנהל דורשת כעת בחירת 'תאריך ניתוק', והניתוק חל מאותו תאריך ואילך — גם רטרואקטיבית.
פרטים נוספים ↓הסתר ↑
הסרת סאב-שליח מצוות של קבלן-מנהל דורשת כעת בחירת 'תאריך ניתוק', והניתוק חל מאותו תאריך ואילך — גם רטרואקטיבית. עד היום ההסרה נחסמה כל עוד היו לסאב משלוחים פעילים תחת המנהל; במקום החסימה, כל ביקור שהסאב ביצע תחת המנהל מתאריך הניתוק והלאה (הושלם או פעיל) מנותק מהמנהל: התיוג managedByDriverId מנוקה, כך שגם חשבון הלקוח→מנהל וגם התשלום מנהל→סאב מפסיקים לכלול אותו, והעבודה חוזרת להיות עצמאית של הסאב. משלוחים שלפני התאריך נשארים משויכים למנהל. עלויות המשלוחים המושפעים וימי-המנהל שאיבדו משלוח (לפיצול business-pickup מחדש) מחושבים מחדש אוטומטית. בורר התאריך מוגבל בין מועד יצירת הקישור להיום (ללא עתיד), והפעולה נרשמת ל-audit עם התאריך ומספר הביקורים שנותקו.
- דיאלוג ההסרה כולל DatePicker לתאריך ניתוק — ברירת מחדל היום, ניתן לבחור תאריך רטרואקטיבי
- החסימה הישנה על 'משלוחים פעילים תחת המנהל' הוסרה — הניתוק מבוסס-תאריך מטפל גם בפעילים
- ניקוי managedByDriverId מהביקורים מהתאריך ואילך + recompute עלויות אוטומטי לצד הסאב ולימי-המנהל
v01.177.003שיפורפורטל לקוח / מדריך חיבור חנותפורטל — מדריך חיבור חנות: מספרי שלב במקום חצים, וחצי שדות בכיוון RTL
ליטוש עיצובי למדריכי חיבור החנות (WooCommerce/Konimbo/Shopify): (1) סמני השלבים ברשימות הוחלפו מחץ אחיד למספר השלב בפועל, כולל מספור רציף בסקציית מפתחות ה-API של WooCommerce גם כשצעד 'הוסף מפתח' מוסתר (קישור עמוק קיים) —…
פרטים נוספים ↓הסתר ↑
ליטוש עיצובי למדריכי חיבור החנות (WooCommerce/Konimbo/Shopify): (1) סמני השלבים ברשימות הוחלפו מחץ אחיד למספר השלב בפועל, כולל מספור רציף בסקציית מפתחות ה-API של WooCommerce גם כשצעד 'הוסף מפתח' מוסתר (קישור עמוק קיים) — קודם היה נוצר דילוג 1,3,4,5. (2) חצי ה'ערך' בטבלאות השדות הופכו לכיוון שמאל (←) התואם RTL, עם רווח גדול יותר אחרי החץ ורווח קטן יותר לפניו.
v01.177.002שיפורבוט WhatsApp / Business Inboxבוט — זיהוי משלוח מהודעה מצוטטת (swipe-to-reply)
המשך לתיקון הברקוד המהוזה: כששליח מדווח בעיה בלי לכתוב ברקוד אבל *מגיב-בציטוט* להודעה שמזהה משלוח, הבוט מזהה כעת את המשלוח מההודעה המצוטטת — דטרמיניסטית — במקום להישען על חילוץ הברקוד של המסווג.
פרטים נוספים ↓הסתר ↑
המשך לתיקון הברקוד המהוזה: כששליח מדווח בעיה בלי לכתוב ברקוד אבל *מגיב-בציטוט* להודעה שמזהה משלוח, הבוט מזהה כעת את המשלוח מההודעה המצוטטת — דטרמיניסטית — במקום להישען על חילוץ הברקוד של המסווג. שני נתיבים: (א) השליח ציטט את שאלת ה-relay של הבוט → AiScenarioRelay.questionMessageId → המשלוח המדויק; (ב) השליח ציטט הודעה אחרת (למשל שורת OCR של מדבקה) → מחלצים מספר ומאמתים שהוא ברקוד אמיתי של ה-tenant. הקדימות: ברקוד שמופיע בטקסט גובר; הציטוט ממלא רק כשאין ברקוד בטקסט — additive, בלי לשבור קיים. אומת מול נתוני פרודקשן: ציטוט שאלת-relay פותר למשלוח הנכון, וציטוט מדבקה פותר ל-25618278 הנכון.
v01.177.001תיקוןבוט WhatsApp / Business Inboxבוט — מניעת שיוך דיווח שליח למשלוח שגוי (ברקוד מהוזה)
כשל שנתפס בשטח: שליח דיווח "גיבתון לא עונה" (בלי ברקוד), והבוט פתח relay ועדכן את הלקוח לגבי משלוח 23950704 — משלוח אחר לגמרי (תקוע חודשים אצל לקוח אחר).
פרטים נוספים ↓הסתר ↑
כשל שנתפס בשטח: שליח דיווח "גיבתון לא עונה" (בלי ברקוד), והבוט פתח relay ועדכן את הלקוח לגבי משלוח 23950704 — משלוח אחר לגמרי (תקוע חודשים אצל לקוח אחר). השורש: המסווג (LLM) שמתבקש לחלץ ברקוד מההודעה *המציא* ברקוד שאינו קיים בטקסט, ו-resolveDriverShipment פתח relay על המשלוח השגוי ושלח ללקוח שלו. תוקן: סומכים על הברקוד של המסווג רק אם ספרותיו מופיעות מילולית בהודעה (barcodeIfMentioned); אחרת מתעלמים ממנו — הבוט נופל לזיהוי לפי משלוח פעיל של השליח, ובעמימות (ריבוי משלוחים פעילים) נשאר שקט במקום לשדר על משלוח שגוי. נוספו טסטים כולל מקרה השטח.
v01.177.000חדשעוזר AI פנימיminorעוזר AI — עלות משלוח בודד, סינון לפי תאריך איסוף, ממוצע הכנסה לחבילה, ותיקון הזיות תאריכים
סבב שיפורים לעוזר הפנימי בעקבות ניתוח 5 שיחות אמת שבהן העוזר התקשה בשאלות פיננסיות ובאיתור משלוחים חסרים מדוח.
פרטים נוספים ↓הסתר ↑
סבב שיפורים לעוזר הפנימי בעקבות ניתוח 5 שיחות אמת שבהן העוזר התקשה בשאלות פיננסיות ובאיתור משלוחים חסרים מדוח. שישה תיקונים: (1) getShipmentDetails החזיר ביקורים בלי תאריכים — העוזר 'המציא' תאריכי מסירה וקליטה (למשל 'נמסר 29/6' כשבפועל 1/7). כעת מוחזרים תאריכים מתויגים: תאריך איסוף (pickupScanAt), תאריך מסירה בפועל (deliveredAt), ותאריך ניסיון שנכשל — והעוזר מונחה לקרוא אך ורק מהשדות ולעולם לא לנחש. (2) getCostSummary — 'הכנסה' הובנה הפוך: העוזר טען שוב ושוב שההכנסה היא 'רק ממשלוחים שהושלמו' וחילק במונה שגוי, ואף 'המציא' שמבוטלים לא נכללים. תוקן: ההכנסה מכסה את כל המשלוחים לפי תאריך קליטה, נוספו ממוצעים מוכנים (הכנסה למשלוח, הכנסה לחבילה) וספירת חבילות, וההערה מבהירה שמבוטלים/חדשים כלולים אלא אם מסננים אותם. (3) כלי חדש getShipmentCost — עלות המסירה/איסוף של משלוח בודד (רשומה בפועל, או הערכה למשלוח שטרם הושלם); קודם העוזר נכנע ('אין מחירון לשליח') למרות שלמשלוח שנמסר יש עלות רשומה. (4) סינון חדש לפי 'תאריך איסוף מלקוח' (pickupFrom/pickupTo) — בדיוק ציר התאריך שבו משתמשת דיווחה על משלוחים חסרים; מבוסס על האיסוף שהושלם בפועל (לא על תאריך מתגלגל), כך שמשלוח שטרם נאסף כראוי לא ייכלל. (5) העברת שם לקוח או ברקוד בטעות כמזהה לקוח (customerId) החזירה 0 תוצאות בשקט — כעת נזרקת שגיאה ברורה שמנחה לאתר את הלקוח קודם. (6) הנחיות: שלושת צירי התאריך (קליטה/מסירה/איסוף), סמנטיקת ההכנסה, ומניעת לולאת ניחושים באבחון 'משלוח חסר מדוח'. הכל אומת מול נתוני הפרודקשן, כולל בדיקה יריבה שאיתרה ותיקנה שלושה באגים לפני העלייה.
- כלי חדש getShipmentCost — עלות מסירה/איסוף של משלוח בודד (רשומה או הערכה), מוגן בהרשאת פיננסים
- סינון חדש לפי תאריך איסוף מלקוח (pickupFrom/pickupTo) — ציר תאריך שלישי לצד קליטה ומסירה
- getCostSummary: ממוצע הכנסה למשלוח ולחבילה + ספירת חבילות; תוקן שההכנסה מכסה את כל המשלוחים ולא רק שהושלמו
- תיקון הזיות תאריכים — getShipmentDetails מחזיר כעת תאריך איסוף, מסירה וכישלון מפורשים
- מזהה לקוח שגוי (שם/ברקוד) זורק שגיאה ברורה במקום להחזיר 0 תוצאות בשקט
v01.176.004חדשבוט WhatsApp / Business Inboxבוט — הצללת דיווח שליח שלא ניתן להעביר ללקוח לא-נגיש
כשקבלן מדווח בעיית מסירה (אין מענה / כתובת שגויה / טלפון שגוי / כשל) והבוט מזהה את התרחיש — אבל ללקוח העסקי אין יעד WhatsApp מקושר — הדיווח היה מת בשקט (matched_no_action).
פרטים נוספים ↓הסתר ↑
כשקבלן מדווח בעיית מסירה (אין מענה / כתובת שגויה / טלפון שגוי / כשל) והבוט מזהה את התרחיש — אבל ללקוח העסקי אין יעד WhatsApp מקושר — הדיווח היה מת בשקט (matched_no_action). סריקת DB מצאה 67 דיווחים כאלה שנעלמו לאורך הצי. כעת, במקום שקט, הבוט מוסיף הערה פנימית לצוות בתוך שרשור-הקבלן ב-inbox ("הקבלן דיווח X על משלוח Y — הלקוח Z אינו נגיש, יש לטפל ידנית") ומסמן את השיחה כלא-נקראה. ההערה פנימית בלבד (role=staff, internal) ולעולם לא נשלחת ל-WhatsApp — אפס סיכון שליחה אוטונומית. עם דדופ של 24ש' למניעת הצפה מ-burst חוזר.
v01.176.003תיקוןפורטל לקוח / דף משלוחיםפורטל — שלד הטבלה ומצב 'אין משלוחים' ממלאים את מלוא גובה הטבלה
המשך תיקון: שלד הטעינה עדיין כיסה רק חלק מגובה הטבלה.
פרטים נוספים ↓הסתר ↑
המשך תיקון: שלד הטעינה עדיין כיסה רק חלק מגובה הטבלה. שתי סיבות תוקנו — (1) באג תזמון: ה-effect שמדד את גובה אזור-הגלילה היה תלוי במשתנים שלא משתנים כשה-ref מתמונט (רק אחרי טעינת ההעדפות), כך שהמדידה מעולם לא רצה והמספר נשאר על ברירת המחדל; נוסף prefsLoaded לתלויות. (2) הערכת-יתר של גובה שורת השלד — כויל לגובה אמיתי (~33px) עם באפר שמבטיח מילוי. בנוסף, מבנה אזור-הגלילה יושר לזה של טבלת הניהול (flex flex-col), ומצב 'אין משלוחים'/'לא נמצאו תוצאות' עבר ל-flex-1 כך שהוא ממורכז וממלא את כל שטח הטבלה.
v01.176.002שיפורבוט WhatsApp / Business Inboxבוט — פתרון relay מתוך עדכון מרוכז של קבלן (threading לפי ברקוד)
קבלן עמוס עונה על הרבה משלוחים בהודעה אחת ("…25682330 סופק 25730095 היום…").
פרטים נוספים ↓הסתר ↑
קבלן עמוס עונה על הרבה משלוחים בהודעה אחת ("…25682330 סופק 25730095 היום…"). שער-הרלוונטיות ההוליסטי דחה batch כזה כ"לא תשובה", וה-relays של אותם משלוחים מתו בלי מענה — הלקוח שבצד השני לא קיבל את הסטטוס שהקבלן בעצם מסר. נוסף שלב threading דטרמיניסטי: כשברקוד של relay פתוח מופיע מילולית בהודעה עם קטע-סטטוס אחריו, הבוט משדר ללקוח *רק את הקטע של המשלוח שלו* ופותר את ה-relay. השינוי additive בלבד (רץ רק כשלא נמצאה התאמת quoted-id, ורק על ברקוד מדויק + מילת-סטטוס — אחרת נופל בדיוק להתנהגות הקיימת), וגם מקשיח פרטיות: משדר קטע-משלוח בודד במקום כל ה-batch. אומת בבקטסט על נתוני היסטוריה אמיתיים: אפס mis-fire.
v01.176.001תיקוןבוט WhatsApp / Business Inboxבוט — תיקון דליפת טקסט־חשיבה פנימי אל הודעות ללקוח
בתרחישי ה-relay של הבוט ("אין מענה" / "נכשל במסירה"), כשהקלט מקבוצת השליח לא היה דיווח אמיתי על קושי במסירה (למשל מספר משלוח בלבד), המודל היה מדקלם בעברית את הוראת ה"אין מה לומר" ("מחרוזת ריקה לחלוטין…") — והטקסט הזה נשל…
פרטים נוספים ↓הסתר ↑
בתרחישי ה-relay של הבוט ("אין מענה" / "נכשל במסירה"), כשהקלט מקבוצת השליח לא היה דיווח אמיתי על קושי במסירה (למשל מספר משלוח בלבד), המודל היה מדקלם בעברית את הוראת ה"אין מה לומר" ("מחרוזת ריקה לחלוטין…") — והטקסט הזה נשלח כהודעה ללקוח (לקוח אחד אף השיב "מה זה מחרוזת ריקה?"). שלושה תיקונים משלימים: (1) הוחלף סימן ה"אין מידע" בפרומפט מ"מחרוזת ריקה" למילת־בקרה NONE שאי־אפשר לבלבל עם תקציר אמיתי; (2) הוקשח שומר־הסף (asCustomerSafeHebrew) לפסול גם הד־הוראה/מטא־טקסט בעברית, לא רק באנגלית; (3) נוסף guard דטרמיניסטי שלא פותח relay של "אין מענה" כשה-burst אינו נושא טקסט דיווח (מספר/אזכור בלבד). נוספו טסטים למקרה העברי ולמילת ה-NONE.
v01.176.000שיפורפורטל לקוח / דף משלוחיםminorפורטל — שורת מסננים פעילים, מוני סטטוס ושיפורי טבלה נוספים
סבב שני של שדרוגים לטבלת המשלוחים בפורטל: (A) שורת 'מסננים פעילים' (בדסקטופ) מעל הטבלה — כל מסנן פעיל (סטטוס/תווית/סוג/סינון-עמודה) מוצג כצ'יפ הניתן להסרה בקליק, עם כפתור 'נקה הכל'.
פרטים נוספים ↓הסתר ↑
סבב שני של שדרוגים לטבלת המשלוחים בפורטל: (A) שורת 'מסננים פעילים' (בדסקטופ) מעל הטבלה — כל מסנן פעיל (סטטוס/תווית/סוג/סינון-עמודה) מוצג כצ'יפ הניתן להסרה בקליק, עם כפתור 'נקה הכל'. (B) מוני משלוחים ליד כל אפשרות בפילטר הסטטוס — כמה משלוחים בכל סטטוס בהינתן שאר המסננים (facet יעיל על עמודת הסטטוס האינדקסית). (C) תוקן באג: משתמש חדש בפורטל ראה את כל העמודות (כולל המוסתרות כברירת מחדל) עד שפתח את תפריט העמודות — כעת ברירת המחדל של העמודות מכובדת מיד בטעינה. (D) עמודת הברקוד ננעצת לימין כברירת מחדל כך שנשארת גלויה בגלילה אופקית (למשתמשים חדשים; בחירת משתמש קיים גוברת). (E) שורות שלד (skeleton) בזמן טעינה במקום ספינר בודד — מספר השורות מחושב לפי גובה הטבלה כך שהשלד ממלא את כל האזור; גם מצב 'אין משלוחים'/'לא נמצאו תוצאות' ממורכז וממלא את כל שטח הטבלה במקום פס קצר בראשה. (F) עמודת התאריך מציגה 'היום'/'אתמול' למשלוחים טריים, עם התאריך המלא ב-tooltip.
- שורת 'מסננים פעילים' (דסקטופ) עם צ'יפים להסרה + 'נקה הכל'
- מוני משלוחים לכל סטטוס בפילטר הסטטוס
- תיקון: משתמש חדש כבר לא רואה את כל העמודות בבת אחת (כיבוד ברירת מחדל)
- עמודת ברקוד נעוצה כברירת מחדל (נשארת גלויה בגלילה)
- שורות שלד בזמן טעינה + תאריך יחסי 'היום'/'אתמול'
v01.175.001שיפורפורטל לקוח / דף משלוחיםפורטל — שיפורי עיצוב ועמודות בדף 'המשלוחים שלי'
סבב שיפורי עיצוב ותצוגה לטבלת המשלוחים בפורטל הלקוח: (1) איחוד עמודות 'שולח' ו'חשבון' לעמודה אחת 'יוזר' (שם החשבון המקושר), שמוצגת רק בלקוחות עם יותר מחשבון מקושר אחד.
פרטים נוספים ↓הסתר ↑
סבב שיפורי עיצוב ותצוגה לטבלת המשלוחים בפורטל הלקוח: (1) איחוד עמודות 'שולח' ו'חשבון' לעמודה אחת 'יוזר' (שם החשבון המקושר), שמוצגת רק בלקוחות עם יותר מחשבון מקושר אחד. (2) עיצוב גופן אחיד לכל תאי הטבלה — הוסרו הבדלי גודל/צבע/גופן פר-עמודה (text-xs, טקסט מעומעם, מונוספייס) כך שכל הטקסטים והמספרים מוצגים באותו עיצוב; ה-badges של סטטוס/דחיפות, תגית הברקוד וה-chips של התוויות נשמרו כאלמנטים ייעודיים. (3) תוקן צבע הרקע של כותרת עמודת הפעולות שבלט משאר הכותרות (הותאם ל-bg-card). (4) נוספה עמודה 'נוצר ע״י' לבקשת לקוחות: משלוח שנוצר ע״י משתמש פורטל מציג את שם המשתמש, ומשלוח שנוצר ע״י צוות הטננט מציג את שם הטננט (החברה) בלבד — ללא שם היוצר.
- עמודות 'שולח' + 'חשבון' → עמודה אחת 'יוזר' (מוצגת רק בחשבונות מקושרים)
- עיצוב גופן אחיד לכל העמודות — טקסטים ומספרים באותו גודל/צבע/גופן
- כותרת עמודת הפעולות כבר לא בולטת בצבע שונה משאר הכותרות
- עמודה חדשה 'נוצר ע״י': שם משתמש הפורטל, או שם הטננט למשלוחים שנוצרו ע״י הצוות
- היררכיית אייקון עמודת הפעולות תוקנה: אייקון התפריט בכותרת בולט יותר ואייקוני השורות עדינים יותר (במקום הפוך)
v01.175.000חדשפורטל לקוח / הרשאות משתמשיםminorפורטל — הרשאת 'צפייה בעלות המשלוח' פר-משתמש (הסתרת עלות ממשתמשים נבחרים)
מנהלי משתמשים בפורטל (בעלים / manage_users) יכולים כעת להגביל אילו מבין משתמשי הצוות שלהם רואים את עלות/מחיר המשלוח.
פרטים נוספים ↓הסתר ↑
מנהלי משתמשים בפורטל (בעלים / manage_users) יכולים כעת להגביל אילו מבין משתמשי הצוות שלהם רואים את עלות/מחיר המשלוח. נוספה הרשאה חדשה 'צפייה בעלות המשלוח' לדף ניהול הצוות (הגדרות → צוות) וגם למסך ניהול משתמשי הפורטל בצד הטננט. ברירת המחדל: כבויה לכל המשתמשים הרגילים (קיימים וחדשים) — כך שהעלות מוסתרת עד שמנהל מעניק את ההרשאה במפורש; מנהלי המשתמשים רואים את העלות תמיד ואי אפשר לחסום אותם. ההסתרה נאכפת בצד השרת בכל שלושת מסלולי הנתונים של הפורטל (רשימת המשלוחים, פרטי המשלוח, ותצוגת ה-Drawer) — הערך פשוט לא מגיע לדפדפן — כך שהיא חלה על עמודת 'מחיר' בטבלה, על כרטיס 'עלות המשלוח' בפרטים, על החיפוש בטקסט ועל ייצוא האקסל. למשתמש מוגבל עמודת 'מחיר' אף אינה מוצעת בבורר העמודות.
- הרשאה חדשה 'צפייה בעלות המשלוח' — ניתנת להענקה/שלילה פר-משתמש בהגדרות → צוות (וגם בניהול משתמשי הפורטל בצד הטננט)
- כבויה כברירת מחדל לכל המשתמשים (קיימים וחדשים); מנהלי המשתמשים — בעלים / manage_users — רואים תמיד ואי אפשר לחסום אותם
- האכיפה בצד השרת: העלות מנוטרלת בכל מסלולי הפורטל (רשימה, פרטים, drawer) כך שאינה דולפת דרך ה-API, החיפוש או ייצוא האקסל
- למשתמש מוגבל עמודת 'מחיר' אינה מוצעת כלל בבורר העמודות (במקום להציג עמודה ריקה)
v01.174.001חדשפערי הפצהפערי הפצה — כפתור 'העתקה לקבלן' עם שורת 'יצא ב-... N ימים אצלכם'
בדף פערי ההפצה, בתצוגת משלוחים המשובצים לשליח, נוסף כפתור 'העתקה לקבלן' לצד כפתור ההעתקה הרגיל (שנשאר ללא שינוי).
פרטים נוספים ↓הסתר ↑
בדף פערי ההפצה, בתצוגת משלוחים המשובצים לשליח, נוסף כפתור 'העתקה לקבלן' לצד כפתור ההעתקה הרגיל (שנשאר ללא שינוי). ההעתקה לקבלן מוסיפה לכל משלוח שורה שלישית: 'יצא ב- DD/MM/YYYY - N ימים אצלכם' — התאריך הוא מועד שיבוץ השליח ו-N הוא מספר ימי העסקים מאז. כאשר המשלוח נמצא 3 ימי עסקים ומעלה אצל הקבלן מתווסף סימן קריאה בסוף השורה, אחרת ללא. הרשימה המועתקת ממוינת מהחמור לקל לפי מספר הימים אצל הקבלן (הגבוה ביותר ראשון). הכפתור מוצג רק בתצוגת 'משובץ' (שם קיים קבלן).
v01.174.000חדשבוט תפעולי / תרחישי גישורminorבוט תפעולי — הקבלן מדווח 'סופק/הסתדר' → הבוט מעדכן את הלקוח וסוגר את הבירור
עד עכשיו גישור 'אין מענה' היה נסיעה חד-כיוונית וחד-פעמית: הקבלן מדווח שאין מענה → הבוט שואל את הלקוח אם יש טלפון/הנחיה → כשהלקוח עונה, הבוט מעביר לקבלן וסוגר.
פרטים נוספים ↓הסתר ↑
עד עכשיו גישור 'אין מענה' היה נסיעה חד-כיוונית וחד-פעמית: הקבלן מדווח שאין מענה → הבוט שואל את הלקוח אם יש טלפון/הנחיה → כשהלקוח עונה, הבוט מעביר לקבלן וסוגר. אבל אם הקבלן עצמו הודיע בקבוצתו 'סופק' / 'הסתדר' / 'נמסר' (לפני או אחרי שהלקוח ענה) — שום דבר לא הועבר ללקוח, והלקוח נשאר תלוי על שאלה שכבר לא רלוונטית. נוספה 'רגל שלישית' לגישור: כשמגיעה הודעה בקבוצת הקבלן בזמן שהבירור עדיין פתוח, והיא מדווחת שהמשלוח סופק/הסתדר, הבוט מעביר את הבשורה ללקוח (כתגובה מצוטטת לשאלת 'אין מענה' המקורית) וסוגר את הבירור. הזיהוי מדויק וזול: קודם מסנן מילות-מפתח חינמי (סופק/נמסר/הסתדר/בוצע...), ורק אם קיים בירור פתוח ומילת-מפתח תואמת — שער LLM אחד (Haiku) מאשר שזה באמת דיווח מסירה חיובי ולא שלילה ('לא נמסר') או כשל. הודעות צוות בקבוצה מדולגות. בנוסף תוקן באג תצוגה: תשובת-ציטוט (swipe-to-reply) של לקוח שגם פתרה גישור נשמרה בלי הפניית-הציטוט, ולכן הופיעה בתיבת העסק בלי בלוק הציטוט הוויזואלי — עכשיו הציטוט נשמר ומוצג גם במסלול זה. ותיקון דיוק חשוב: כשקבלן מדווח 'אין מענה' (או כתובת/טלפון שגויים) בלי לציין מספר משלוח, הבוט היה מנחש את המשלוח הפתוח האחרון שלו — ובקבוצת קבלן עם עשרות משלוחים פעילים זה פגע במשלוח ובלקוח לא-קשורים (למשל פנייה מיותרת ללקוח 'כביסכל' על משלוח 23165589, בזמן ש'אין מענה' הייתה בכלל תשובה לשאלת צוות על משלוח אחר שכבר נכשל). מעכשיו, כשאין ברקוד בדיווח ולקבלן יותר ממשלוח פתוח פעיל אחד — הבוט שותק במקום לנחש.
- רגל שלישית לגישור 'אין מענה': דיווח 'סופק/הסתדר' מהקבלן מועבר ללקוח וסוגר את הבירור, במקום להשאיר אותו תלוי
- העדכון ללקוח נשלח כתגובה מצוטטת לשאלת 'אין מענה' המקורית — כדי שהוא יבין להֵקשר
- זיהוי חסכוני: מסנן מילות-מפתח חינמי ואז שער LLM יחיד שמאשר מסירה חיובית ודוחה שלילה/כשל; הודעות צוות מדולגות
- ניתן לעריכה בהגדרות → תרחישי בוט (תבנית 'יידוע הלקוח כשהשליח מדווח שהמשלוח סופק/הסתדר')
- תיקון תצוגה: תשובת-ציטוט של לקוח שפתרה גישור מציגה כעת את בלוק הציטוט בתיבת העסק (קודם נשמט)
- תיקון דיוק: דיווח שליח→לקוח ללא ברקוד מפסיק לנחש משלוח — הבוט פועל רק כשיש לקבלן משלוח פתוח פעיל יחיד (מונע פנייה ללקוח הלא-נכון)
v01.173.001תיקוןתיבת העסק / Green API webhookתיבת העסק — תגובת איש צוות בקבוצה לא סימנה את הצ'אט כנקרא
המשך לטיפול בנקרא/לא-נקרא: נציגות התלוננו שגם כשאיש צוות מהחברה שמשתתף בקבוצה הגיב, הצ'אט נשאר מסומן כלא-נקרא.
פרטים נוספים ↓הסתר ↑
המשך לטיפול בנקרא/לא-נקרא: נציגות התלוננו שגם כשאיש צוות מהחברה שמשתתף בקבוצה הגיב, הצ'אט נשאר מסומן כלא-נקרא. הסיבה: כשאיש צוות כותב בקבוצה ממספר שאינו החשבון המחובר ל-Green API (מספר אישי, או מספר עסקי שהוא רק משתתף בקבוצה), Green API שולח את זה כהודעה נכנסת (role=user) ולא כהודעה יוצאת — ולכן התיקון הקודם (שקידם את סימון הנקרא רק על הודעות יוצאות) לא זיהה אותה, וההודעה אף הגדילה את מונה הלא-נקראו. התיקון: זיהוי השולח מול מפת טלפוני הצוות של הטננט (resolveGroupSender) — הודעת צוות בקבוצה מקדמת עכשיו את lastReadAt ומנקה סימון-לא-נקרא ידני, בדיוק כמו תגובה מהחשבון המחובר. תלוי בכך שהטלפון של איש הצוות (ראשי או משני) רשום במערכת.
v01.173.000חדשאפליקציית שליחיםminorאפליקציית השליחים — הערת שליח פרטית + עריכת פרטי כתובת (קומה/כניסה/דירה/קוד)
השליח יכול כעת לרשום בדף המשלוח באפליקציה 'הערת שליח' — להתמצאות בכתובת או לעדכון התפעול על כשלים.
פרטים נוספים ↓הסתר ↑
השליח יכול כעת לרשום בדף המשלוח באפליקציה 'הערת שליח' — להתמצאות בכתובת או לעדכון התפעול על כשלים. ההערה פרטית: גלויה לשליח ולצוות התפעול בדשבורד הווב בלבד, לעולם לא לנמען ולא לשולח (לא בפורטל, לא ב-WhatsApp, לא ב-API הציבורי, ולא מסתנכרנת לליונוויל). בנוסף, השליח יכול לתקן ישירות מהאפליקציה את פרטי הכתובת — קומה, כניסה, דירה וקוד כניסה — והתיקון מתעדכן בכל המערכת: הוא נכתב על הביקור וגם ממופה לשדות הכתובת הקנוניים של המשלוח, כך שהדיספצ'ר בווב ופורטל השולח רואים את הכתובת המעודכנת (וישרת גם מסירה חוזרת או העברה לשליח אחר). מבחינה טכנית: נוספה עמודת courier_note ל-Shipment ועמודות entrance/entranceCode ל-Visit; נקודת הקצה של הביקור במובייל מחזירה את השדות ותומכת ב-PATCH לשמירתם (עם בדיקת בעלות מלאה — השליח יכול לערוך רק ביקור שמשויך אליו); בדשבורד הווב הערת השליח מוצגת בכרטיס יעד המשלוח לצוות התפעול. עריכה זמינה גם על ביקור שהסתיים (כשל) — כדי שאפשר יהיה לעדכן על כשל בדיעבד.
- הערת שליח פרטית בדף המשלוח — להתמצאות בכתובת או עדכון תפעול על כשלים
- פרטיות מלאה: גלוי לשליח ולתפעול בלבד — לא לנמען, לא לשולח (פורטל/WhatsApp/API ציבורי), ולא לליונוויל
- עריכת קומה/כניסה/דירה/קוד כניסה ישירות מהאפליקציה, עם תיקון שמתעדכן בכל המערכת (דיספצ'ר + פורטל השולח)
- צוות התפעול רואה את הערת השליח בכרטיס יעד המשלוח בדשבורד הווב
- עריכה מותרת גם על ביקור שנכשל — לעדכון תפעול בדיעבד; עם בדיקת בעלות (השליח עורך רק ביקור שלו)
v01.172.004שיפורתמונת מחסןתמונת מחסן — הבר העליון עוצב מחדש כמו בדף המשלוחים (כולל כפתור X לניקוי החיפוש)
הבר העליון של 'תמונת מחסן' אוחד לאותה מערכת רכיבים של דף /shipments: PageToolbar עם ToolbarSearch (שדה חיפוש עם כפתור X לניקוי מיידי — שהיה חסר לגמרי) וכפתורי ToolbarButton אחידים ל'רענון' ו'הדפסה', במקום Input גולמי וכפ…
פרטים נוספים ↓הסתר ↑
הבר העליון של 'תמונת מחסן' אוחד לאותה מערכת רכיבים של דף /shipments: PageToolbar עם ToolbarSearch (שדה חיפוש עם כפתור X לניקוי מיידי — שהיה חסר לגמרי) וכפתורי ToolbarButton אחידים ל'רענון' ו'הדפסה', במקום Input גולמי וכפתורי אייקון ghost. שאר תוכן הכותרת — הכותרת עצמה, תג מספר המשלוחים, חותמת 'עודכן ב', ותג 'N תואמות' — נשמר בתוך הבר.
v01.172.003שיפורתמונת מחסןתמונת מחסן — חיפוש מסנן את המשבצות הרלוונטיות במקום רק להקיף אותן
בדף 'תמונת מחסן', חיפוש (ברקוד / שם לקוח / עיר / קוד אזור) רק הקיף במסגרת את המשבצות התואמות ועמעם את השאר ל-30% שקיפות — לא מספיק בולט.
פרטים נוספים ↓הסתר ↑
בדף 'תמונת מחסן', חיפוש (ברקוד / שם לקוח / עיר / קוד אזור) רק הקיף במסגרת את המשבצות התואמות ועמעם את השאר ל-30% שקיפות — לא מספיק בולט. כעת החיפוש מסנן ממש: מוצגות רק המשבצות שמכילות תוצאה תואמת, והשאר נעלמות. נוסף תג 'N תואמות' בכותרת, מצב 'לא נמצאו תוצאות' עם כפתור ניקוי חיפוש, וגרירה לסידור-מחדש מושבתת בזמן חיפוש (כדי שדריפה על תת-קבוצה לא תיצור סדר חלקי שגוי). לוגיקת ההתאמה אוחדה למקור-אמת יחיד המשמש גם לסינון וגם להדגשת המשבצת בתוך הכרטיס.
v01.172.002תיקוןליקוטליקוט — טאבי 'נלקטו' הפסיקו לצבוע באדום ולספור ימי המתנה למשלוחים שכבר לוקטו
בדף הליקוט, בטאבים 'נלקטו היום' ו'סה"כ נלקטו', המערכת המשיכה לחשב 'ימי המתנה' כ-(היום − תאריך ההוספה) ולצבוע שורות באדום/כתום לפי הוותק — מדד חסר-תועלת עבור משלוח שכבר לוקט (הוא כבר לא 'ממתין', והמספר גדל לנצח).
פרטים נוספים ↓הסתר ↑
בדף הליקוט, בטאבים 'נלקטו היום' ו'סה"כ נלקטו', המערכת המשיכה לחשב 'ימי המתנה' כ-(היום − תאריך ההוספה) ולצבוע שורות באדום/כתום לפי הוותק — מדד חסר-תועלת עבור משלוח שכבר לוקט (הוא כבר לא 'ממתין', והמספר גדל לנצח). כעת צביעת הדחיפות (אדום/כתום) חלה רק על משלוחים שעדיין ממתינים לליקוט; ובמשלוח שלוקט עמודת 'ימי המתנה' מציגה את זמן הטיפול הקבוע — מרגע ההוספה ועד הליקוט (נגזר מ-pickedAt) — בתג ניטרלי, עובדה היסטורית שאינה משתנה במקום מונה מתגלגל. אותה נוסחה מוחלת גם על המיון לפי 'ימי המתנה' ועל ייצוא ה-Excel. ה-API של הליקוט מחזיר כעת את pickedAt.
v01.172.001תיקוןסוכניםדוח עמלות הסוכן — רשימת המשלוחים גלשה מעל הכרטיסיות שמתחת
בדף פרטי הסוכן, כשלסוכן היו הרבה משלוחים מזכים (למשל 313), רשימת המשלוחים ב'דוח עמלות חודשי' נפרשׂה במלוא גובהה וכיסתה את הכרטיסיות 'כללי עמלה' ו'חיוב/זיכוי חד-פעמי' שמתחתיה.
פרטים נוספים ↓הסתר ↑
בדף פרטי הסוכן, כשלסוכן היו הרבה משלוחים מזכים (למשל 313), רשימת המשלוחים ב'דוח עמלות חודשי' נפרשׂה במלוא גובהה וכיסתה את הכרטיסיות 'כללי עמלה' ו'חיוב/זיכוי חד-פעמי' שמתחתיה. הסיבה: רכיב ScrollArea של Radix עם max-height בלבד (בלי גובה מוגדר) — ה-Viewport הפנימי (size-full) לא קיבל גובה אמיתי לחשב מולו, גדל לגובה התוכן המלא, וגלש. הוחלף ב-div רגיל עם overflow-y-auto, שם max-height עובד נכון עם גלילה native. אותו דפוס תוקן גם בדיאלוג הוספה לליקוט (רשימת הפרשות), שהיה חשוף לאותה גלישה מעל כפתורי הדיאלוג.
v01.172.000תיקוןאפליקציית שליחיםminorאפליקציית השליחים — מקבץ תיקוני אמינות וקריטיים (מחסן, מיקום, אופליין, אזור-זמן)
מקבץ תיקונים מקיף לאפליקציית השליחים אחרי סקירת קוד רב-ממדית.
פרטים נוספים ↓הסתר ↑
מקבץ תיקונים מקיף לאפליקציית השליחים אחרי סקירת קוד רב-ממדית. תוקנו חמש תקלות קריטיות: (1) סורק המחסן במובייל (קליטה/שיוך) קרא ל-endpoint של הווב שמאומת בעוגיות דפדפן ולכן כל סריקה נכשלה — לוגיקת הסריקה חולצה ל-scan-core משותף, נבנה endpoint מובייל ייעודי מאומת-טוקן (/api/v1/mobile/admin/scan) עם בדיקת תפקיד, וההתנהגות (קליטה, שיוך, סנכרון ליונוויל, יומן ביקורת) זהה לחלוטין לסורק הווב. (2) מעקב מיקום ברקע ב-iOS לא יכול היה לעבוד כלל כי חסר UIBackgroundModes — נוסף isIosBackgroundLocationEnabled ל-app.json. (3) עבודת ליקוט אופליין על אצווה לא-משויכת (OPEN) נדחתה כולה בסנכרון ואבדה — נוסף claim אטומי ומוגן-מרוץ שתופס אצווה פנויה לעובד שהוריד אותה. (4) מסך ההכנסות והבורר-תאריך במסך הבית הציגו את היום/החודש הקודם עקב המרת תאריך ב-UTC — התאריכים נגזרים כעת מהיום המקומי, והשרת מפרש טווחי-יום כגבולות שעון ישראל. (5) timeout גורף של 10 שניות חנק העלאות תמונה ברשת סלולרית חלשה — הועלה ל-120 שניות עבור בקשות עם תמונה. בנוסף הוקשח תור הסנכרון אופליין: retry עם backoff מעריכי (התור כבר לא נתקע בשקט כשהוא 'מקוון' אבל הבקשות נכשלות), תקרת ניסיונות שמעבירה פריט 'רעיל' ל-failed במקום לחסום את כל התור, סיווג 403 וקובץ-חסר כשגיאה סופית, תיוג פעולות לפי משתמש (מכשיר משותף לא מסנכרן עבודת נהג אחד תחת טוקן של אחר), ותמונות כשל/צ'ק מועתקות כעת ל-documentDirectory כמו POD כדי שהמערכת לא תמחק אותן לפני ההעלאה. רענון הטוקן מבחין כעת בין כשל רשת רגעי (משאיר את הסשן) לבין דחייה אמיתית (מנתק), כך ששליח לא מנותק באמצע משמרת על תקלת רשת חולפת; ומעקב ה-GPS נעצר ביציאה מהמערכת (פרטיות + סוללה). אכיפת גביית COD שבה לפעול במצב אופליין (סטטוס הגבייה מוזרם מנקודת /today). בצד הדיספצ'ר: נוסף שומר-תפקיד לקבוצת מסכי האדמין, תור הביקורים הלא-משויכים כולל כעת גם צבר של עד שבוע אחורה (במקום להיעלם בחצות), שיוך ממובייל מריץ את קידום סטטוס המשלוח וסנכרון ליונוויל כמו בווב ואינו מאפשר לשייך מחדש ביקור שהושלם, והקשה על התראת פוש מנווטת נכון גם כשהאפליקציה סגורה (cold-start). בהמשך הוקשחה זרימת ההזדכות (COD settlement): תמונות ההוכחה נדחסות כעת בצד הלקוח (resize 1600 + איכות 0.8) לפני ההעלאה — קודם 5 תמונות לא-דחוסות חרגו ממגבלת גוף-הבקשה של Vercel (4.5MB) והפילו את ההזדכות ב-413; ויצירת ההזדכות בשרת הפכה לאטומית — יצירת הרשומה ותפיסת רשומות ה-COD רצות בטרנזקציה אחת עם updateMany מותנה (settlementId עדיין null), כך שבקשה מקבילה או ניסיון-חוזר לא יכולים להזדכות פעמיים על אותו כסף (אי-התאמה בספירה מגלגלת את כל הטרנזקציה אחורה ומחזירה 409). לבסוף, התראות פוש נשלחות כעת גם מזרימות השיוך בווב: שיוך בודד מדשבורד הווב שולח לשליח 'משלוח חדש'/'הועבר אליך' (ולשליח הקודם 'הועבר ממך'), ושיוך מרובה (לאסו במפה) שולח התראה מקובצת אחת — 'שויכו אליך N משלוחים' — במקום N התראות. קבלנים חיצוניים (ספקי broadcast) מוחרגים; שליח בלי טוקן פוש הוא no-op. עד כה פוש נשלח רק משיוך במובייל, כך שהשליחים פיצו על כך ב-polling.
- סורק המחסן במובייל תוקן — endpoint ייעודי מאומת-טוקן שמשתף את אותה לוגיקה בדיוק כמו סורק הווב (קליטה/שיוך/סנכרון ליונוויל/ביקורת)
- מעקב מיקום ברקע ב-iOS מופעל (UIBackgroundModes) — קודם לא עבד כלל אחרי נעילת מסך
- ליקוט אופליין על אצווה לא-משויכת כבר לא אובד — claim אטומי מוגן-מרוץ תופס את האצווה לעובד
- מסך ההכנסות וניווט התאריכים הציגו יום/חודש קודם (באג UTC) — תוקן לגבולות יום בשעון ישראל
- העלאות תמונה (POD/גוביינא/כשל) כבר לא נחנקות ב-timeout של 10ש' ברשת חלשה — 120ש' לבקשות עם תמונה
- תור הסנכרון אופליין הוקשח: backoff מעריכי, תקרת ניסיונות לפריט תקוע, תמונות נשמרות ב-documentDirectory, ותיוג פעולות לפי משתמש
- רענון טוקן לא מנתק שליח על כשל רשת רגעי; מעקב GPS נעצר ביציאה מהמערכת
- אכיפת גביית COD שבה לפעול גם אופליין, ושומר-תפקיד נוסף לקבוצת מסכי הדיספצ'ר
- שיוך ממובייל מקדם סטטוס ומסנכרן ליונוויל כמו הווב, חוסם שיוך-מחדש של ביקור שהושלם, ותור הלא-משויכים כולל צבר שבוע אחורה
- הזדכות COD: דחיסת תמונות הוכחה בצד הלקוח (תיקון 413), ויצירה אטומית בשרת (טרנזקציה + claim מותנה) שמונעת הזדכות כפולה על אותו כסף
- התראות פוש נשלחות כעת גם משיוך בווב — שיוך בודד ('משלוח חדש'/'הועבר') ושיוך מרובה עם התראה מקובצת אחת; קודם פוש נשלח רק מהמובייל
v01.171.001שיפורתיבת העסקתיבת העסק — העתקה נוחה: קטע מסומן, מספרי טלפון ומיילים
שיפורי העתקה ואינטראקציה ב-business-inbox בעקבות משוב מנציגות שירות: (1) העתקת הודעה דרך תפריט-ההקשר העתיקה תמיד את כל ההודעה, גם כשסומן רק קטע — עכשיו 'העתק' מכבד את הבחירה ומעתיק רק את מה שסומן (כשהבחירה נמצאת בתוך אות…
פרטים נוספים ↓הסתר ↑
שיפורי העתקה ואינטראקציה ב-business-inbox בעקבות משוב מנציגות שירות: (1) העתקת הודעה דרך תפריט-ההקשר העתיקה תמיד את כל ההודעה, גם כשסומן רק קטע — עכשיו 'העתק' מכבד את הבחירה ומעתיק רק את מה שסומן (כשהבחירה נמצאת בתוך אותה הודעה). (2) מספרי טלפון, כתובות אימייל וקישורים בתוך הודעות הפכו לאינטראקטיביים: לחיצה על מספר פותחת את השיחה של אותו מספר בתוך התיבה עצמה — ואם אין היסטוריית התכתבות, נפתחת שיחה חדשה מוכנה לשליחה; לחיצה על אימייל פותחת חלון כתיבת מייל; וקישור נפתח בכרטיסייה חדשה. לחיצה ימנית (או לחיצה ארוכה במובייל) פותחת תפריט — פתיחת שיחה / חיוג / העתקת מספר עבור טלפון, שליחת מייל / העתקת כתובת עבור אימייל. זיהוי הטלפונים דורש 0 או +972 מוביל כדי לא לזהות ברקודים/מחירים בטעות. (3) כפתור העתקה קטן מופיע ליד מספר הטלפון של הלקוח ב-header של הצ'אט, בסגנון ההעתקה הקיים בשאר המערכת.
v01.171.000חדשצ'אט לקוחות עסקיים / business-inboxminorצ'אט לקוחות עסקיים — הערות פנימיות ותיוג חברי צוות
נוסף מנגנון שיתוף פעולה פנימי ב-business-inbox: אפשר להוסיף 'הערה פנימית' לשיחה — פתק שנשמר בשיחה אך לעולם לא נשלח ללקוח בוואטסאפ — ובתוכה לתייג חבר צוות עם @.
פרטים נוספים ↓הסתר ↑
נוסף מנגנון שיתוף פעולה פנימי ב-business-inbox: אפשר להוסיף 'הערה פנימית' לשיחה — פתק שנשמר בשיחה אך לעולם לא נשלח ללקוח בוואטסאפ — ובתוכה לתייג חבר צוות עם @. חבר הצוות שתויג מקבל סימון בתוך המערכת (מונה 'תיוגים שלי' עם מסנן שקופץ ישר לשיחות הרלוונטיות), וההערה מודגשת לו עם תווית 'תויגת'. הרקע: וואטסאפ/Green API לא מאפשרים תיוג נייטיב אמיתי דרך ה-API (אין mentionedJid ב-SendMessage), ולכן התיוג מומש כיכולת פנימית מלאה בתוך Shipnest, מבודדת לחלוטין מהלקוח.
- מצב 'הערה פנימית' נפרד בתיבת הכתיבה (כפתור פתק) — הערה בצבע ענבר שלא נשלחת ללקוח
- תיוג חברי צוות עם @ והשלמה אוטומטית של שמות הצוות
- מונה 'תיוגים שלי' + מסנן לשיחות שבהן תויגת, והדגשת 'תויגת' על ההערה
- התיוג נראה רק לצוות — הלקוח לעולם לא רואה הערות או תיוגים
v01.170.001תיקוןליקוט / סנכרון ליונוויל / יבואמשלוחים מיובאים נשמטו מרשימת הליקוט — מירוץ בין היבוא ל-webhook
יבוא של 54 משלוחים ללקוח שמוגדר 'דורש ליקוט' הכניס לרשימת הליקוט רק 25 מהם, באופן אקראי.
פרטים נוספים ↓הסתר ↑
יבוא של 54 משלוחים ללקוח שמוגדר 'דורש ליקוט' הכניס לרשימת הליקוט רק 25 מהם, באופן אקראי. הסיבה השורשית: ההרשמה האוטומטית לליקוט (לפי הגדרת הלקוח requiresPicking) רצה רק כשה-webhook של ליונוויל ראה את המשלוח כ'נוצר' (created). אבל היבוא יוצר בעצמו את שורת המשלוח המקומית (upsertShipment), ובמקביל ליונוויל שולח webhook task_created לאותה משימה — מי שמנצח את המירוץ מקבל את פעולת ה-created, והמפסיד רואה 'updated'. סבב ה-/tasks/show הנוסף של היבוא הופך את זה למירוץ אמיתי שיכול ליפול לכל צד בכל שורה; כשהיבוא ניצח, ה-webhook ראה 'updated' ודילג על ההרשמה — והמשלוח נשמט בשקט מהליקוט. התיקון: ההרשמה רצה עכשיו גם על 'updated' (כל עוד לא 'skipped'), עם שמירה על ה-guard הקיים (מתעדכן רק כשגם pickingStatus וגם pickingType עדיין null) — כך שהיא idempotent, לא דורסת סוג-ליקוט שנבחר ביבוא, ולא מחזירה לחיים משלוח שהוסר ידנית (הסרה מנקה pickingStatus אך משמרת pickingType). בנוסף: תיקון נתונים רטרואקטיבי שהכניס לרשימה את 29 המשלוחים שנשמטו, וסקריפט תחזוקה backfill-stranded-picking (dry-run כברירת מחדל, ממוקד רק למשלוחים פתוחים שנוצרו לאחרונה). ולבסוף — הוסרה סתירת ה-UX שהזמינה את הבלבול מלכתחילה: כשבוחרים ביבוא לקוח שמוגדר 'דורש ליקוט', שדה הליקוט מקבל עכשיו כברירת מחדל את סוג הליקוט של הלקוח (עלוני שבת / מוצרים) במקום 'ללא ליקוט'. זה גם גורם ליבוא לקבוע את סטטוס הליקוט ישירות ומיידית, בלי תלות במירוץ ה-webhook.
v01.170.000חדשתיבת העסק / Green APIminorתיבת העסק — סטטוס טיפול משותף + סימון-נקרא אוטומטי כשנציג עונה מהוואטסאפ
כשחלק מהנציגים עובדים ב-business-inbox וחלק בוואטסאפ הרגיל, נוצר בלגן: צ'אטים נשארו 'לא נקראו' בממשק גם אחרי שקולגה טיפלה בהם בוואטסאפ, ולא היה שום סימן משותף מה טופל ומה לא.
פרטים נוספים ↓הסתר ↑
כשחלק מהנציגים עובדים ב-business-inbox וחלק בוואטסאפ הרגיל, נוצר בלגן: צ'אטים נשארו 'לא נקראו' בממשק גם אחרי שקולגה טיפלה בהם בוואטסאפ, ולא היה שום סימן משותף מה טופל ומה לא. הסיבה השורשית — Green API אף פעם לא מדווח על קריאת צ'אט במכשיר אחר, ולכן אי אפשר לסנכרן את סימוני ה'נקרא' של וואטסאפ בין הממשק למכשירים המקושרים. הפתרון עוקף את המגבלה בשתי דרכים: (1) כשקולגה עונה ללקוח מהטלפון/וואטסאפ הרגיל — האות היחיד ש-Green API כן שולח (outgoingMessageReceived) — הצ'אט מסומן אוטומטית כנקרא גם בממשק, ומפסיק להיות מודגש כלא-מטופל; (2) סטטוס טיפול משותף חדש (חדש / בטיפול / טופל) + 'מי מטפל', שנשמר אצלנו ומשותף לכל הנציגים בממשק — מקור אמת אחד ל'מה טופל', בלתי תלוי בסימוני הוואטסאפ.
- סימון-נקרא אוטומטי: קולגה שעונה מהוואטסאפ הרגיל מסירה את סימון הלא-נקרא בממשק
- סטטוס טיפול משותף — חדש / בטיפול / טופל — עם שם הנציג שמטפל, גלוי לכל הצוות
- שליטה מהירה: מה-header של הצ'אט, מתפריט-ההקשר ברשימה, וצ'יפ סטטוס בכל שורה
v01.169.005תיקוןשכר שליחים / סנכרון ליונווילמסירות של קבלן נעלמו מדוח השכר לשליח כשליונוויל השמיט את הנהג
קבלן/מנהל צוות ראה בדוח פורטל השליחים פחות ביקורים וחבילות נוספות ממה שביצע בפועל (למשל 26 ביקורים / 29 חבילות נוספות במקום 27 / 36).
פרטים נוספים ↓הסתר ↑
קבלן/מנהל צוות ראה בדוח פורטל השליחים פחות ביקורים וחבילות נוספות ממה שביצע בפועל (למשל 26 ביקורים / 29 חבילות נוספות במקום 27 / 36). הסיבה: כשליונוויל שולח webhook של השלמת מסירה בלי driver_id — נפוץ במשימות קבלן/partner — ה-DELIVERY visit נשמר עם driverId=null, ואז נופל לגמרי מדוח השכר (computeManagerTenantEarnings משייך רק לפי driverId/managedByDriverId), ולוקח איתו גם את תוספת החבילות הנוספות. /tasks/show של ליונוויל כן מחזיק את הנהג גם כשה-webhook השמיט אותו, וסנכרון ה-POD ממילא מושך את ה-payload הזה — ולכן נוסף forward-guard חינמי (אפס קריאות ליונוויל נוספות) שמשלים את הנהג החסר במסירה באופן לא-הרסני (רק כשהנהג null, לעולם לא דורס שיבוץ קיים; managedByDriverId דרך הפותר הקנוני). בנוסף: תיקון נתונים חד-פעמי למסירות יתומות שנמצאו, וסקריפט תחזוקה backfill-completed-orphan-drivers לשחזור היסטורי (dry-run כברירת מחדל). רוב המסירות ה'יתומות' הן דווקא מסירות שבוצעו ע"י ספק חיצוני ואין להן נהג גם בליונוויל — אלו נכון שיישארו ללא שיוך ומחוץ לדוחות השכר.
v01.169.004תיקוןבוט קבוצות / Green API webhookבוט הקבוצות — תשובה בציטוט (swipe-to-reply) נשמטה ולא הועברה חזרה
כשקבלן דיווח 'אין מענה' והבוט שאל את הלקוח בקבוצה, תשובת הלקוח לא הועברה חזרה לקבלן.
פרטים נוספים ↓הסתר ↑
כשקבלן דיווח 'אין מענה' והבוט שאל את הלקוח בקבוצה, תשובת הלקוח לא הועברה חזרה לקבלן. הסיבה: הלקוח ענה בציטוט השאלה (swipe-to-reply) — ו-Green API שולח הודעה כזו עם typeMessage='quotedMessage', שה-webhook לא זיהה כהודעת טקסט. ההודעה נשמטה בשקט לפני שהגיעה למנוע הרלייז (tryHandleScenarioRelayReply). אירוני, כי תשובה בציטוט היא דווקא האות החזק ביותר — היא מאפשרת שיוך דטרמיניסטי של התשובה ל-relay לפי ה-stanzaId המצוטט. התיקון: הוספת quotedMessage לענף הטקסט ב-webhook, כך שתשובות מצוטטות מנותבות כרגיל (הטקסט כבר יושב ב-extendedTextMessageData.text וה-stanzaId כבר חולץ).
v01.169.003תיקוןאפליקציית שליח / דף משלוחאפליקציית שליח — 'הערות לקוח' הציגה את הודעת הוואטסאפ במקום הערה
בדף פרטי המשלוח באפליקציית השליח, הבלוק שכותרתו 'הערות לקוח' הציג את גוף הודעת הוואטסאפ שנשלחת ללקוח בעת הקמת המשלוח (שדה message) — טקסט תבנית ארוך ולא רלוונטי לשליח.
פרטים נוספים ↓הסתר ↑
בדף פרטי המשלוח באפליקציית השליח, הבלוק שכותרתו 'הערות לקוח' הציג את גוף הודעת הוואטסאפ שנשלחת ללקוח בעת הקמת המשלוח (שדה message) — טקסט תבנית ארוך ולא רלוונטי לשליח. הבלוק היה ממופה בטעות ל-shipment.message. הוראות המסירה/האיסוף האמיתיות ממילא כבר מוצגות בכרטיס הכתובת (address.notes), והערות השולח בבלוק 'הערות שולח' (shipmentNote/orgNote), כך שלבלוק לא היה תוכן לגיטימי להציג. התיקון: הסרת הבלוק לגמרי.
v01.169.002תיקוןסנכרון ליונוויל / שיבוץ נהגיםשיבוץ שליח לאיסוף נמחק בסנכרון הבא מליונוויל
שליח ששיבץ על עצמו משימת איסוף בשיפנסט (דרך מסך השיבוץ במובייל, או עמוד האיסופים כשאין לו lionwheelId) גילה שהאיסוף נעלם מהאפליקציה.
פרטים נוספים ↓הסתר ↑
שליח ששיבץ על עצמו משימת איסוף בשיפנסט (דרך מסך השיבוץ במובייל, או עמוד האיסופים כשאין לו lionwheelId) גילה שהאיסוף נעלם מהאפליקציה. הסיבה: השיבוץ הזה לא נדחף לליונוויל, ולכן הסנכרון הבא של המשלוח החזיר את ה-PICKUP visit ללא נהג (driver_id = null) — וקוד ה-upsert דרס את השליח המקומי ל-null. ההגנה שמונעת דריסה כזו הייתה קיימת עד כה ל-DELIVERY בלבד (data-service.ts). התיקון: מרחיב את ההגנה גם ל-PICKUP — driver ריק נכנס על איסוף פירושו תמיד 'ליונוויל לא הכיר את השליח' ולא ביטול שיבוץ לגיטימי, ולכן שומרים תמיד על השיבוץ המקומי. שיבוץ מסירה לא הושפע.
v01.169.001תיקוןפורטל לקוחות / דף משלוחפורטל לקוחות — הערת היעד לא זוהתה בדף המשלוח
לקוחות פורטל דיווחו שאינם רואים את 'הערת היעד' בדף פרטי המשלוח.
פרטים נוספים ↓הסתר ↑
לקוחות פורטל דיווחו שאינם רואים את 'הערת היעד' בדף פרטי המשלוח. ההערה למעשה כן הוצגה — אך ללא תווית, כטקסט אפור-מעומעם קטן עם אייקון גנרי בתחתית כרטיס היעד, כך שלא ניתן היה לזהות אותה כ'הערת יעד'. בצד הצוות, וגם בבלוק 'הערות למשלוח' שממש מתחתיו בפורטל, יש תווית ברורה. התיקון: הוספת תווית 'הערת יעד' מפורשת והצגת ההערה בצבע טקסט רגיל (לא מעומעם), בעקביות עם 'הערות למשלוח'. התיקון חל גם על מגירת התצוגה-המהירה ברשימת המשלוחים, שמשתמשת באותו רכיב.
v01.169.000חדשעוזר AI פנימיminorעוזר AI — מחירון שליחים, הבחנת עיר יעד מול מוצא, וספירת חריגות ימי הפצה
תיקון ושדרוג של העוזר הפנימי בעקבות שיחה אמיתית שבה נתן תשובת מחיר שגויה: על 'מה עלות המסירה הממוצעת לצפת' הוא ענה ₪18 במקום ₪22.
פרטים נוספים ↓הסתר ↑
תיקון ושדרוג של העוזר הפנימי בעקבות שיחה אמיתית שבה נתן תשובת מחיר שגויה: על 'מה עלות המסירה הממוצעת לצפת' הוא ענה ₪18 במקום ₪22. שתי סיבות שורש תוקנו. (1) הוא סינן לפי עיר המוצא (מאיפה המשלוח נאסף) במקום עיר היעד — נוסף סינון destinationCity נפרד לכל כלי החיפוש/הספירה/העלות, וההנחיות מבהירות ש'נשלח/נמסר ל-X' = יעד ואילו 'נאסף ב-X' = מוצא. ההבדל דרמטי: לצפת 2093 משלוחים לפי יעד מול 60 בלבד לפי מוצא. (2) לא היה לעוזר כלי מחירון — נוסף getDriverPricing שמציג את התעריף המוגדר של שליח/חברת שליחויות: תעריפי בסיס (מסירה, איסוף, איסוף עסקי, חבילה נוספת, החזרה) וחריגות תעריף פר-אזור/קו חלוקה. למשל זיפ: בסיס מסירה ₪18 אך אזור 12 (שכולל את צפת) = ₪22. ההנחיות מדגישות שערים שייכות לאזורי חלוקה, ושהמחירון המוגדר (getDriverPricing) שונה מעלות ממוצעת שנמדדה בפועל (getCostSummary, המושפעת מ-outliers ומהמדגם). בנוסף: getZoneDistributionDays יודע כעת לספור כמה משלוחים בקו חרגו מסף ימי-עסקים נתון (minBusinessDays → exceededCount/exceededPct). הכלי החדש מוגן בהרשאת פיננסים.
- כלי מחירון שליח חדש (getDriverPricing) — תעריפי בסיס + חריגות פר-אזור, מוגן בהרשאת פיננסים
- הבחנה בין עיר יעד (destinationCity) לעיר מוצא (sourceCity) — 'מסירה לצפת' כבר לא מסונן לפי עיר האיסוף
- getZoneDistributionDays סופר חריגות מסף ימי-עסקים (minBusinessDays) — 'כמה בקו X חרגו מ-3 ימים'
- שורש התקלה אומת בפרודקשן: זיפ בסיס ₪18, אזור 12 = ₪22; תשובת ₪18 לצפת הייתה שגויה
v01.168.005תיקוןבחירת רחוב / טופס משלוחבחירת רחוב — ישובים כמו 'קרית אתא' החזירו רשימת רחובות ריקה
בטופס יצירת משלוח, בחירה בישובים מסוימים (למשל 'קרית אתא', 'הרצליה', 'קרית גת', 'קרית מוצקין') לא הציגה שום רחוב — רק ההודעה 'אין רחובות לישוב זה'.
פרטים נוספים ↓הסתר ↑
בטופס יצירת משלוח, בחירה בישובים מסוימים (למשל 'קרית אתא', 'הרצליה', 'קרית גת', 'קרית מוצקין') לא הציגה שום רחוב — רק ההודעה 'אין רחובות לישוב זה'. הסיבה: מאגר הישובים הפנימי שומר את השם עם דיגרף כפול ('קריית אתא'), בעוד מאגר הרחובות של data.gov.il שומר אותו בכתיב יחיד ('קרית אתא'). החיפוש ה-full-text מול data.gov.il אינו מגשר על הפרש ה-יי/וו, ולכן שאילתה עם השם הקנוני החזירה אפס רשומות. התיקון: שולחים שתי שאילתות — גם עם הכתיב הקנוני וגם עם גרסת הדיגרף המכווצת (יי→י, וו→ו) — וממזגים את התוצאות, וכן מכווצים את אותם דיגרפים בסינון הצד-שרת כך ששני הכתיבים משתווים. מיזוג (ולא החלפה) חיוני: 'פתח תקווה' דווקא נמצא רק בכתיב הכפול במאגר data.gov.il. אומת מול ה-API החי — קרית אתא: 0→352 רחובות, הרצליה: 0→775, קרית גת: 0→437.
v01.168.004תיקוןעוזר AI פנימיעוזר AI — תיבת הכתיבה במצב כהה נראתה כאינפוט בתוך אינפוט
במצב כהה תיבת הכתיבה של העוזר הפנימי הציגה שתי מסגרות מקוננות — האינפוט הפנימי (ה-textarea) קיבל רקע כהה משלו (dark:bg-input/30 של רכיב ה-Textarea הבסיסי) שלא הוטמע ברקע של המכל החיצוני, מה שיצר מראה של 'אינפוט בתוך אינפ…
פרטים נוספים ↓הסתר ↑
במצב כהה תיבת הכתיבה של העוזר הפנימי הציגה שתי מסגרות מקוננות — האינפוט הפנימי (ה-textarea) קיבל רקע כהה משלו (dark:bg-input/30 של רכיב ה-Textarea הבסיסי) שלא הוטמע ברקע של המכל החיצוני, מה שיצר מראה של 'אינפוט בתוך אינפוט' עם טבעת כפולה. במצב בהיר לא הייתה בעיה כי אין וריאנט רקע כהה. תוקן בהוספת dark:bg-transparent! ל-textarea כך שהוא מתמזג ברקע המכל בשני המצבים, עם טבעת פוקוס יחידה על המכל בלבד — בדיוק כמו שכבר תוקן בשתי תיבות הכתיבה של האינבוקס.
v01.168.003שיפוראינבוקס עסקיאינבוקס עסקי — כפתור גלילה להודעה האחרונה עם מונה הודעות חדשות
נוסף כפתור צף לגלילה מהירה לתחתית הצ'אט (להודעה האחרונה) באינבוקס העסקי (business-inbox, Green API), בדיוק כמו שכבר קיים באינבוקס ההודעות (/messages/inbox).
פרטים נוספים ↓הסתר ↑
נוסף כפתור צף לגלילה מהירה לתחתית הצ'אט (להודעה האחרונה) באינבוקס העסקי (business-inbox, Green API), בדיוק כמו שכבר קיים באינבוקס ההודעות (/messages/inbox). הכפתור מופיע רק כשהנציג גלל למעלה והתרחק מהתחתית (מעל ~200px), ולחיצה עליו גוללת בצורה חלקה להודעה האחרונה. ממוקם בפינה השמאלית-תחתונה מעל תיבת הכתיבה, בעיצוב זהה לכפתור באינבוקס השני. בנוסף: כשמגיעות הודעות חדשות מהלקוח בזמן שהנציג גלל למעלה, הכפתור מציג מונה של מספר ההודעות החדשות שטרם נראו (נספרות רק הודעות נכנסות — הודעות שהנציג עצמו שולח לא נספרות), והמונה מתאפס עם ההגעה לתחתית או בלחיצה על הכפתור.
v01.168.002שיפוראינבוקס WhatsAppאינבוקס — הצגת הודעות מיוחדות: 'לא נתמך' כנה וכרטיס איש קשר מעוצב
שני שיפורים בהצגת הודעות באינבוקס ההודעות (Meta): (1) הופיע לעיתים 'קובץ מצורף' שלא ניתן לפתוח או להציג.
פרטים נוספים ↓הסתר ↑
שני שיפורים בהצגת הודעות באינבוקס ההודעות (Meta): (1) הופיע לעיתים 'קובץ מצורף' שלא ניתן לפתוח או להציג. הסיבה: כשלקוח שולח תוכן ש-WhatsApp Cloud API אינו מסוגל להעביר — מדיה לצפייה חד-פעמית (view once), סקר, או סוג הודעה לא-נתמך — מטא מוסרת את ההודעה עם type='unsupported' וללא שום מדיה (אין mediaId ואין קובץ להביא). ה-UI נפל ל-branch הגנרי והציג תיבת 'קובץ מצורף' מטעה, כאילו יש קובץ שנכשל להיפתח. כעת מוצגת הודעה ברורה: 'הודעה שאינה נתמכת בוואטסאפ — ייתכן שנשלחה מדיה לצפייה חד-פעמית או סוג הודעה שוואטסאפ אינו מעביר. לא ניתן להציג את התוכן.' שורש התקלה אומת בלוגי הפרודקשן (הודעת type='unsupported' שהגיעה מיד אחרי תמונה תקינה באותה שיחה). (2) עיצוב מחדש של כרטיס איש קשר משותף: במקום שורת טקסט אחת של 'שם · טלפון', מוצג כעת כרטיס עם ראשי-תיבות של השם, שם איש הקשר, וכל מספר טלפון בשורה נפרדת עם כפתורי פעולה — התקשרות (tel:), פתיחה בוואטסאפ (wa.me), והעתקת המספר ללוח. תומך בכמה אנשי קשר ובכמה מספרים לכל איש קשר, ומנרמל מספרים ישראליים לפורמט בינלאומי עבור wa.me.
v01.168.001שיפורתמונת מחסןתמונת מחסן — שם שולח וברקוד לחיץ במודל העגלה
שיפור המודל שנפתח בלחיצה על עגלה בתמונת המחסן.
פרטים נוספים ↓הסתר ↑
שיפור המודל שנפתח בלחיצה על עגלה בתמונת המחסן. שני שינויים ברשימות המשלוחים (גם ב'כרגע במחסן' וגם בהיסטוריה השבועית): (1) מוצג כעת שם השולח (פרטי האיסוף) במקום שם הנמען — מתאים יותר לזרימת העבודה במחסן שבה מזהים משלוח לפי מקור; (2) ברקוד המשלוח הפך ללחיץ ופותח את דראוור פרטי המשלוח (BarcodeDisplay המשותף), בדיוק כמו בכל שאר האפליקציה — כולל העתקת מזהה ופתיחת דף המשלוח. נוסף השדה sourceName ל-API של היסטוריית המחסן.
v01.168.000חדשעוזר AI פנימיminorהעוזר הפנימי — שיבוץ שליח, סיכום עלויות, ו-7 יכולות חדשות מניתוח כלל השיחות
השלמת ניתוח כל 54 שיחות העוזר הפנימי (24 השיחות הישנות שנותרו) חשפה שורת יכולות שהמשתמשים ביקשו שוב ושוב והעוזר סירב להן — למרות שהנתונים קיימים במערכת.
פרטים נוספים ↓הסתר ↑
השלמת ניתוח כל 54 שיחות העוזר הפנימי (24 השיחות הישנות שנותרו) חשפה שורת יכולות שהמשתמשים ביקשו שוב ושוב והעוזר סירב להן — למרות שהנתונים קיימים במערכת. בהמשך נוספו שתי יכולות דומיין: (א) getZoneDistributionDays — ממוצע וחציון ימי הפצה (ימי עסקים בפועל מהאיסוף עד המסירה, ללא שישי/שבת, חגים וערבי חגים, ולא כולל יום האיסוף) לפי קו/אזור הפצה, בשונה מ-getDeliveryTimeStats שסופר ימים קלנדריים לפי עיר; (ב) זיהוי 'כפולה' (משלוח הלוך-חזור: מסירה + איסוף חזרה) — getShipmentDetails מחזיר כעת isRoundtrip, כך ש'זה כפולה?' נענה. בנוסף תוקן סינון הקו להיות עמיד לרווחים ('11ב' = '11 ב', מה שהחזיר 0 קודם וכעת 5,160). נוספו שבע היכולות הקודמות, כל אחת אומתה מול נתוני פרודקשן: (1) שיבוץ שליח למשלוח (assignDriverToShipment) — היכולת המבוקשת ביותר, נדחתה 4+ פעמים ('תשבץ', 'אתה יכול ללמוד?'); מבצע שיוך ביקור, סנכרון לליונוויל וקידום סטטוס, מאחורי הרשאת עריכת משלוחים ואישור מהמשתמש. (2) סיכום עלויות ורווח (getCostSummary) — 'כמה עלות המסירה של לקוח X בחודש קודם' נדחה קודם כ'אין גישה לפיננסים', למרות שעמודות העלות מלאות על ~81 אלף משלוחים; מסכם עלות מסירה/איסוף, מחיר ליונוויל ורווח מוערך, מאחורי הרשאת פיננסים. (3) סינון לפי תאריך מסירה בפועל (deliveredFrom/deliveredTo) — 'נמסרו בחודש X' לא היה ניתן לסינון (רק לפי תאריך קליטה). (4) סינון לפי אזור/קו הפצה (zone/regionCode) — 'משלוחים בקו 11ב'. (5) סינון לפי שם שליח (driverName) — 'דוח משלוחים של נהג X'. (6) שליחה לקבוצת WhatsApp לפי שם ('שלח לקבוצת מישל') — קודם נדרש מזהה מספרי; כעת מתאים לפי שם הקבוצה/השליח, וגם חיפוש שליח לפי שם מזהה שם קבוצה. (7) getShipmentDetails מחזיר כעת את שליח האיסוף ואת כתובת המוצא — 'מי נהג האיסוף' / 'שנה יעד לכתובת המוצא' עובדים. במקביל תוקנו דפוסי כשל שחזרו בשיחות: העוזר סירב ליכולות שכבר היו לו (סימון נמסר, הערה פנימית, פנייה למחסן, חיפוש שליח בשם) — נוסף כלל מפורש 'אל תסרב ליכולת שיש לך'; הצגת קודי PENDING/SUCCESS כסטטוס מסירה (SUCCESS הוא סטטוס שליחת הודעה, לא מסירה) נאסרה; שאלות זהות והרשאה ('איך קוראים לי', 'יש לי גישה לפיננסים') נענות מההנחיות במקום 'אין לי גישה'; וסיבת כשל נרשמת בדיוק כפי שהמשתמש כתב, בלי ברירת מחדל ('אין מענה' ≠ 'תא קולי'). חילוץ helper משותף לפילטרים של כלי החיפוש מונע מהם להיפרד (באג drift שנתפס קודם).
- כלי חדש: שיבוץ שליח למשלוח מהצ'אט (מסירה/איסוף) — כולל סנכרון לליונוויל וקידום סטטוס, מאחורי הרשאה ואישור
- כלי חדש: סיכום עלויות ורווח ללקוח/טווח (מאחורי הרשאת פיננסים) — שאלה שנדחתה קודם למרות שהנתונים קיימים
- סינונים חדשים: תאריך מסירה בפועל, אזור/קו הפצה, ושם שליח — בחיפוש, בספירה ובדוח האקסל
- שליחה לקבוצת WhatsApp לפי שם ('שלח לקבוצת מישל') במקום מזהה מספרי; חיפוש שליח לפי שם מזהה גם שם קבוצה
- פרטי המשלוח כוללים כעת את שליח האיסוף וכתובת המוצא — 'מי נהג האיסוף' ו'החזרה לכתובת מוצא' עובדים
- כלל 'אל תסרב ליכולת שיש לך' — סימון נמסר, הערה פנימית, פנייה למחסן וחיפוש שליח לא נדחים יותר
- בלי הצגת PENDING/SUCCESS כסטטוס מסירה; שאלות זהות/הרשאה נענות מההנחיות; סיבת כשל בדיוק כפי שנכתב
- כל השבע אומתו מול נתוני פרודקשן (למשל עלות מסירה של לקוח בננה ליוני: 652 משלוחים, ₪10,930)
- ביקורת אדוורסרית לפני הדחיפה תפסה 6 באגים ותוקנו: שיבוץ שליח לפי שם עמום היה יכול לשבץ ולחייב את השליח הלא-נכון (כעת שגיאת ריבוי-התאמות), חישוב רווח מנופח, וסתירות בפרומפט
- כלי חדש: ימי הפצה בפועל (ימי עסקים מאיסוף עד מסירה) לפי קו/אזור הפצה; זיהוי 'כפולה' בפרטי המשלוח; סינון קו עמיד לרווחים
- ביקורת נוספת תפסה התאמת-קו רחבה מדי (קו '1' משך את 10–19) — עוגן לקוד מדויק או תת-קו, ואוחד בין שני מסלולי הסינון
v01.167.000חדשעוזר AI פנימיminorהעוזר הפנימי — חיפוש לקוחות, אמינות ביצוע פעולות, וסטטיסטיקת זמני מסירה
המשך שיפור העוזר הפנימי על בסיס ניתוח מקיף של 29 שיחות אמיתיות מהחודש האחרון.
פרטים נוספים ↓הסתר ↑
המשך שיפור העוזר הפנימי על בסיס ניתוח מקיף של 29 שיחות אמיתיות מהחודש האחרון. סבב ראשון — שיחת 'לקוח בירושלים': העוזר ענה עם נמען במקום לקוח עסקי, הבטיח לזכור הוראה בלי לשמור אותה, לא היה לו כלי לחפש לקוחות לפי עיר, ו'התוודה' בשקר על המצאת תשובה שהייתה נכונה. תוקן: (1) כלי חדש לחיפוש וספירת לקוחות עסקיים לפי שם/אימייל/טלפון/עיר; (2) מילון ישויות: 'לקוח' תמיד = הלקוח העסקי, שדה שם-הנמען שונה שמו; (3) כלל עמידה מאחורי נתונים ואיסור דוגמאות בדיוניות; (4) הוראות מתמשכות נשמרות כתובנה לפני המענה; (5) פירוש שגיאות הקלדה לפי הקשר. סבב שני — ניתוח רוחבי של כלל השיחות חשף שני באגי תשתית שגרמו ללולאות 'עדכנתי ✅ / לא עדכנת' מתסכלות: מטמון הפעולות (idempotency) שמר גם כישלונות, כך ש'נסה שוב' החזיר את הכישלון השמור בלי להריץ מחדש — תוקן כך שכישלון לא נשמר; וכלי הכתיבה (עדכון סטטוס/כתובת/פנייה) איתרו משלוח רק לפי ברקוד מדויק או מזהה פנימי, בעוד שכלי הקריאה מאתרים גם לפי מזהי partner — אוחד האיתור כך שמה שנמצא בקריאה נמצא גם בעדכון, כולל זיהוי ברקוד שהועבר בטעות כמזהה. נוספו: כלי סטטיסטיקת זמני מסירה (ממוצע וחציון ימים מקליטה עד מסירה, לפי עיר או השוואת ערים — שאלה שחזרה שוב ושוב וגרמה לקריסת השיחה); סינון לפי עיר מוצא ('משלוחים שנאספו בירושלים'); העלאת תקרת סבבי הכלים מ-5 ל-8 והחלפת הודעת 'לא הצלחתי לעבד את הבקשה' הסתמית בהסבר כן עם הצעה לפצל; וכללי כנות דיווח: הצלחה מדווחת רק מתוצאת הכלי של אותו סבב, אסור למחזר מזהי רשומה מפעולות קודמות, ו'לא עדכנת' מפעיל אימות מחדש במקום חזרה על הודעת ההצלחה. זרימות שהצוות לימד בשטח שוב ושוב קובעו כברירת מחדל: ברקוד + סיבת כשל → סימון נכשל + הודעה לשולח (לא לשליח); עדכון פרטים → הצעת עדכון לשליח בכל סטטוס; הודעות לשליחים בלי 'שלום' ו'תודה' ותמיד עם מספר המשלוח. סבב הביקורת האדוורסרי על השינויים תפס וסגר שלושה באגים לפני הדחיפה: עדכון כתובת שכתב למזהה הגולמי במקום למזהה שנפתר (נתיב הברקוד קרס וגם חסר סינון tenant); קריסת overflow כשברקוד בן 10–12 ספרות הועבר כמזהה מספרי (INT4); ואיתור לא-דטרמיניסטי כשאותו מספר הוא ברקוד של משלוח אחד ומזהה-partner של אחר — נפתר עם קדימות לברקוד (אומת מול 3 התנגשויות חיות בפרודקשן). בנוסף נוקו 21 רשומות כישלון שכבר היו במטמון.
- תוקנו שני באגי תשתית שגרמו ללולאות 'עדכנתי ✅ / לא עדכנת': מטמון פעולות ששמר כישלונות, ואיתור משלוח שונה בין קריאה לכתיבה
- כלי חדש: סטטיסטיקת זמני מסירה — ממוצע וחציון מקליטה עד מסירה, לפי עיר או השוואת ערים בקריאה אחת
- כלי חדש: חיפוש וספירת לקוחות עסקיים לפי שם / אימייל / טלפון / עיר
- כנות דיווח: הצלחה מדווחת רק מתוצאת הכלי בפועל; 'לא עדכנת' מפעיל אימות מחדש במקום חזרה על אותה הודעה
- זרימות שהצוות לימד קובעו כברירת מחדל: דיווח כשל → הודעה לשולח; עדכון פרטים → עדכון לשליח בכל סטטוס; הודעות בלי נימוסים מיותרים
- סינון חדש לפי עיר מוצא ('נאסף בירושלים'), תקרת שלבי עיבוד הועלתה, והודעת הכישלון הסתמית הוחלפה בהסבר שימושי
- 'לקוח' תמיד = הלקוח העסקי; הוראות מתמשכות נשמרות כתובנה לפני המענה; בלי דוגמאות בדיוניות
- ביקורת אדוורסרית לפני הדחיפה תפסה 3 באגים: כתיבה למזהה הלא-נכון, קריסת INT4 על ברקוד ארוך, ואיתור לא-דטרמיניסטי בהתנגשות ברקוד/מזהה-partner (אומת מול פרודקשן)
v01.166.000חדשעוזר AI פנימיminorהעוזר הפנימי — דוחות אקסל מלאים, מודעות לתאריך ופחות שאלות הבהרה
שדרוג מקיף לעוזר ה-AI הפנימי, בעקבות ניתוח שיחה אמיתית שבה משתמשת ביקשה 'דוח של כל המשלוחים שנאספו בחודש קודם' והעוזר נתקע: הוא לא ידע מה התאריך הנוכחי (ניחש 'נובמבר 2024'), לא היה לו סינון לפי תאריכים, הוא הוגבל ל-50 שו…
פרטים נוספים ↓הסתר ↑
שדרוג מקיף לעוזר ה-AI הפנימי, בעקבות ניתוח שיחה אמיתית שבה משתמשת ביקשה 'דוח של כל המשלוחים שנאספו בחודש קודם' והעוזר נתקע: הוא לא ידע מה התאריך הנוכחי (ניחש 'נובמבר 2024'), לא היה לו סינון לפי תאריכים, הוא הוגבל ל-50 שורות בלי יכולת ייצוא, והוא חזר על אותן שאלות הבהרה פעמיים. מה שתוקן: (1) הזרקת התאריך הנוכחי (שעון ישראל) להנחיות העוזר, כולל חישוב מפורש של 'חודש קודם' — ביטויי זמן יחסיים מחושבים מעכשיו לבד ואסור לו לשאול עליהם; (2) כלי חדש exportShipmentsReport — העוזר מפיק דוח אקסל מלא (עד 20,000 שורות, כל עמודות המשלוח, RTL) ומחזיר קישור הורדה בצ'אט; ההורדה עוברת דרך מסלול מאובטח שגוזר את ה-tenant מה-session ודורש הרשאת צפייה במשלוחים; (3) סינון תאריכים חדש (dateFrom/dateTo, שעון ישראל) וסינון החרגת-סטטוסים (excludeDeliveryStatuses) בכלי הספירה, החיפוש והדוח — 'לא כולל חדשים ומבוטלים' עובד עכשיו באמת; (4) כללי התנהגות חדשים: סבב הבהרה אחד לכל היותר עם ברירת מחדל מומלצת, איסור לחזור על שאלה אחרי תשובה כללית ('הכל'), איסור להציג למשתמש קודי סטטוס פנימיים או שמות כלים/מגבלות API, והעדפת ניסוח ניטרלי מגדרית; (5) תצפיתיות: קריאות הכלים ומספר הטוקנים של כל תשובת עוזר נשמרות עכשיו על ההודעה — מסך מעקב שיחות ה-AI של מנהלי הפלטפורמה מציג מעתה מה העוזר באמת עשה מאחורי הקלעים.
- העוזר יודע מה התאריך היום (שעון ישראל) ומחשב לבד 'חודש קודם' / 'אתמול' / 'השבוע'
- כלי חדש: הפקת דוח אקסל מלא מהצ'אט — עד 20,000 שורות עם כל פרטי המשלוח וקישור הורדה מאובטח
- הדוח מכבד הרשאות: נדרשת הרשאת 'ייצוא משלוחים', ועמודת המחיר מוצגת רק לבעלי הרשאת פיננסים
- סינון לפי טווח תאריכים והחרגת סטטוסים בכל כלי השליפה של העוזר
- סבב הבהרה אחד לכל היותר — תשובה כללית ('הכל') מפעילה ברירת מחדל במקום שאלה חוזרת
- בלי מונחים פנימיים מול המשתמש — סטטוסים בעברית בלבד, בלי שמות כלים ומגבלות API
- מעקב שיחות AI מציג כעת את קריאות הכלים והטוקנים של כל תשובה
- השינויים עברו ביקורת רב-סוכנית אדוורסרית לפני הדחיפה — 18 ממצאים אומתו ותוקנו (כולל דיוק תאריכים בימי מעבר שעון קיץ)
v01.165.000ייעולכלל-מערכתיminorמתקפת מהירות רוחבית — בסיס נתונים, שרת, דפדפן ואפליקציית השליחים
סבב אופטימיזציה מקיף שמכסה את כל שכבות המערכת, על בסיס אודיט אוטומטי של עשרה ממדי ביצועים שכל ממצא בו אומת פרטנית מול הקוד ומול בסיס-הנתונים החי לפני היישום — 43 שיפורים בסך הכול, כולם ללא שינוי התנהגות.
פרטים נוספים ↓הסתר ↑
סבב אופטימיזציה מקיף שמכסה את כל שכבות המערכת, על בסיס אודיט אוטומטי של עשרה ממדי ביצועים שכל ממצא בו אומת פרטנית מול הקוד ומול בסיס-הנתונים החי לפני היישום — 43 שיפורים בסך הכול, כולם ללא שינוי התנהגות. בסיס נתונים: נוספו 8 אינדקסים חדשים בפרודקשן — הבולט שבהם על מזהה המעקב הציבורי של משלוח (public_id): עד היום כל לחיצה של נמען על קישור מעקב ב-WhatsApp סרקה את טבלת המשלוחים כולה (453MB); כעת זו שליפה נקודתית. אינדקסים נוספים: רשימת המשלוחים בפורטל הלקוחות לפי לקוח+תאריך, פריטי הזמנה לפי משלוח (רץ בכל webhook של ליונוויל), זיהוי שיחה בכל הודעת WhatsApp נכנסת/יוצאת, זיהוי לקוח מקבוצת WhatsApp בבוט, ציר 'תאריך מסירה' בטבלת המשלוחים, לולאת האישורים של תרחישי הבוט, ורשימת הגוביינא. שרת: שאילתות בלתי-תלויות שרצו ברצף הוסבו לריצה מקבילה בכל המסלולים החמים (משלוחים, איסופים, ליקוט, גוביינא, אנליטיקות שליחים, אינבוקס עסקי, שכר); הוסרו שליפות של ה-JSON הכבד של ליונוויל במקומות שקוראים רק סטטוס (פורטל, הודעות, לקוחות); חושב-שכר ומסך-לקוח שרצו שאילתה-פר-שורה אוחדו לשאילתות מקובצות; גזירת מפתח ההצפנה (PBKDF2, 100 אלף איטרציות, ~14ms של CPU חסום) נשמרת כעת בזיכרון במקום להיגזר מחדש בכל פענוח סוד — מורגש בכל webhook ובכל קריאת API לליונוויל; ה-webhook של Meta עונה 200 מיידית ומעבד את האירועים (תמלול, סיווג AI, הורדת מדיה) אחרי התשובה — כמו אחיו של ליונוויל ו-Green API; אימות ההרשאות (auth) עבר memoization פר-בקשה; cron סנכרון-המשלוחים-האחרונים שוכתב — 3 קריאות ליונוויל במקביל במקום טורית עם השהיות, וחלון הסריקה מתקדם לפי סנכרון-אחרון במקום לחזור על אותם 50 הישנים. דפדפן: מסך פרטי-המשלוח (533KB) נטען עד היום בכל עמוד ועמוד דרך רכיבי ה-layout — כעת הוא נטען רק בפתיחה ראשונה, מה שמקטין את ה-JS ההתחלתי של כל 121 עמודי המערכת; מעבד ה-Markdown של הצ'אטים (142KB) ויצוא האקסל של הרווחיות (430KB) נטענים רק בשימוש; עמוד יומן-העדכונים הפסיק לארוז את כל קובץ היומן (955KB) לדפדפן; החיפוש הגלובלי הפסיק לגרור את שכבת ה-API לתוך ה-bundle של כל עמוד; כל מנגנוני ה-polling (אינבוקס עסקי, נוכחות, התראות, באנרים) מושהים כשהטאב מוסתר; חיפוש במבט-המחסן ממומש כעת עם memoization במקום למיין מחדש את כל האזורים בכל הקשה. אפליקציית שליחים: ציור פוליגון במפה הפסיק לרנדר מחדש את כל המרקרים בכל תזוזת אצבע (memoization מלא של שכבות המפה); ריקון תור הפעולות באופליין מרענן את רשימת היום פעם אחת בסוף במקום פעם לכל פעולה. נסגר גם דוח הביקורת: סריקת code-review רב-זוויתית על כל השינויים לפני הדחיפה, עם תיקוני המשך (מטמון רכיבים שנטענו, איחוד helper של 'היום הישראלי', ביטול סריקת regex חוזרת בהודעות סטרימינג). בהמשך היום נכנס הסבב השני — פריטי ה-backlog שדרשו שינוי התנהגות מבוקר: שיבוץ שליח המוני עונה כעת מיידית (העדכון המקומי, יומן הפעולות ורשומת-השחזור נשמרים לפני העבודה האיטית; סנכרון ליונוויל, שידורים וקידום סטטוס רצים ברקע אחרי התשובה — סוף להמתנה של דקות על לאסו של מאות משלוחים); רשימת המשלוחים בפורטל הלקוחות והחיפוש הגלובלי קוראים את עמודת הסטטוס הממופתחת במקום ה-JSON הכבד; אישורי ליונוויל ו-Summit נשמרים במטמון ל-5 דקות עם פינוי מיידי בשמירת הגדרות; אישור התחשבנות מעדכן את כל הגוביינות בפעולה אחת במקום עד 100; ה-webhook של ליונוויל חוסך משיכות /tasks/show כפולות ומדלג על שכתוב פריטי הזמנה שלא השתנו; מנוע העלויות מדלג על כתיבות זהות במקום לשכתב את כל יום-הנהג בכל אירוע; מילון היישובים לאוטו-השלמה במטמון משותף (גם לפורטל); ובאפליקציית השליחים — polling נעצר במסכים שאינם בפוקוס, הטוקן נשמר בזיכרון במקום קריאת keychain בכל בקשה, נקודות GPS נשלחות ב-batch אחד, וספינר הרענון מופיע רק במשיכה ידנית. חולצו גם שני hooks משותפים (polling מודע-נראוּת שחונה את הטיימר בטאב מוסתר, ו-lazy-loading של רכיבים) שהחליפו ~12 עותקים ידניים. גם סבב זה עבר code-review רב-זוויתי לפני הדחיפה, כולל תיקון רגרסיה שנתפסה בביקורת (תגי סינון 'מצב משלוח' בגוביינא הראו 0 במצב ברירת-מחדל — הוחזר). לסיום נסגר גם הפריט הכבד האחרון: אימות ההרשאות רץ עד היום כמעט בכל בקשה (2 שאילתות DB טוריות לכל קריאת auth של משתמש צוות, ואחת לכל קריאה של משתמש פורטל) כי מנגנון ההשהיה של פעם-בדקה לא נשמר בפועל; כעת מטמון בזיכרון אוכף את הקצב המתוכנן — בדיקה אחת לכל היותר בדקה פר משתמש — עם שמירה מלאה על הסמנטיקה האבטחתית (משתמש מושבת לעולם לא נשמר במטמון, ושינוי הרשאות פורטל מפנה את המטמון מיידית). השינוי עבר סקירת אבטחה אדוורסרית ייעודית (נעילת משתמש מושבת, דליפת תפקידים בין טננטים, התחזות, החלפת טננט) — ואושר. הסבב הרביעי סגר את השאריות: האינבוקס העסקי עבר בידוד רינדור — תיבת הכתיבה הופרדה לרכיב עם state מקומי, כך שהקלדה מרנדרת רק אותה ולא את כל רשימת השיחות וציר ההודעות (שגם קיבלו memo ובניית ציר ממוזכרת) — ההקלדה בצ'אט חלקה גם בשיחות ארוכות; רשימת ההודעות הפסיקה לשלוף את ה-JSON הכבד (אומת שאף צרכן חי לא קורא ממנו); ארבע לולאות הסנכרון הידניות מול ליונוויל אוחדו ל-helper אחד עם knob קצב יחיד; ובונוס אבטחה — משתמש פורטל שהושבת מנותק כעת מיידית (במקום להמשיך עד תפוגת ה-token), וביטול הרשאה תופס בבקשה הבאה — באפס עלות, על גב שאילתה שכבר רצה בכל בקשה.
- 8 אינדקסים חדשים בפרודקשן — עמוד המעקב הציבורי ירד מסריקת 453MB לשליפה נקודתית בכל קליק על קישור מעקב
- 533KB ירדו מה-JS ההתחלתי של כל 121 עמודי המערכת — מסך פרטי-המשלוח נטען רק בפתיחה בפועל
- גזירת מפתח הצפנה נשמרת בזיכרון — חוסך ~14ms של CPU חסום בכל webhook וכל קריאת ליונוויל
- שאילתות מקביליות בכל המסלולים החמים — משלוחים, איסופים, ליקוט, גוביינא, אנליטיקות, אינבוקס, שכר
- ה-webhook של Meta עונה מיידית ומעבד ברקע — סוף ל-retries של Meta על תשובות איטיות
- כל ה-polling מושהה בטאבים מוסתרים — פחות עומס על השרת ועל הסוללה
- אפליקציית שליחים: ציור אזור במפה חלק (בלי רינדור כל המרקרים בכל תזוזה), וסנכרון אופליין מרענן פעם אחת במקום N פעמים
- cron הסנכרון מתקדם בחלון במקום לחזור על אותם 50 משלוחים, עם 3 קריאות ליונוויל במקביל
v01.164.000חדשפורטל שליחיםminorפורטל שליחים — טאב 'יעד שבת' של הפרשה הקרובה
לפורטל השליחים נוסף טאב שלישי — 'יעד שבת' — שמציג לשליח את משלוחי יעד-השבת של הפרשה הקרובה שטרם נמסרו.
פרטים נוספים ↓הסתר ↑
לפורטל השליחים נוסף טאב שלישי — 'יעד שבת' — שמציג לשליח את משלוחי יעד-השבת של הפרשה הקרובה שטרם נמסרו. הפרשה הקרובה נגזרת ממקור האמת היחיד במערכת (getUpcomingShabbat מ-@workspace/shared, שעון ישראל), וכותרת הטאב מציגה את שם הפרשה. כלל הנראות זהה לטאב המשלוחים המעוכבים: (1) משלוח המשובץ על השליח או על שליחי המשנה שלו — בכל אזור; (2) משלוח שאינו משובץ על אף שליח — רק אם הוא באחד מאזורי האחריות שלו; (3) משלוח המשובץ על שליח אחר — לא מוצג. מוצגים רק משלוחים פתוחים (שטרם נמסרו). כל שורה לחיצה ופותחת מגירת פרטים עם ניווט (Waze / Google Maps) והתקשרות, בדיוק כמו בטאב המעוכבים, וקיימים אותם סינון-קטגוריה (הכל / משובצים עליי / באזורי האחריות) וסינון-אזור. אגב כך חולצה תשתית תצוגת-הרשימה המשותפת (PortalShipmentList) המשמשת כעת גם את המעוכבים וגם את יעד השבת.
- טאב 'יעד שבת' בפורטל, עם שם הפרשה הקרובה ומונה משלוחים
- אותו כלל נראות של המעוכבים: משובץ עליי/צוות (כל אזור) או לא-משובץ באזורי האחריות; משובץ על אחר מוסתר
- רק משלוחים פתוחים (שטרם נמסרו) של הפרשה הקרובה
- לחיצה על משלוח → פרטים + ניווט Waze/Google Maps + התקשרות, וסינון לפי אזור
v01.163.000חדשפיננסים / שליחים / נוכחותminorעלות שליח שכיר ברווחיות — שכר יומי מהנוכחות מחולק אוטומטית למשימות
עד היום עלות איסוף/מסירה פר-משלוח חושבה אך ורק ממחירון השליח, ולשליח שכיר (שעתי) בלי מחירון נרשמה עלות 0 — כך שהמשלוחים שהוא ביצע נראו ברווחיות כאילו לא עלו כלום, בעוד השכר שלו חי רק בדוח השכר.
פרטים נוספים ↓הסתר ↑
עד היום עלות איסוף/מסירה פר-משלוח חושבה אך ורק ממחירון השליח, ולשליח שכיר (שעתי) בלי מחירון נרשמה עלות 0 — כך שהמשלוחים שהוא ביצע נראו ברווחיות כאילו לא עלו כלום, בעוד השכר שלו חי רק בדוח השכר. מעכשיו, שליח מסוג 'שכיר' עם רשומת עובד מקושרת ותעריף שעתי — וללא מחירון — מקבל תמחור אוטומטי לפי שכר: עלות היום מחושבת מהמשמרות שהחתים בנוכחות (שעות נטו × תעריף שעתי, כולל שעות נוספות 125%/150% לפי כללי העבודה של הארגון ונסיעות יומיות), ומתחלקת שווה-בשווה בין נקודות האיסוף והמסירה שהשלים באותו יום. דוגמה: שכר יום של 500 ₪ על 25 נקודות = 20 ₪ לנקודה. החלוקה נשמרת כ-snapshot על כל משלוח (עלות איסוף/מסירה) ומזינה את כל תחשיבי הרווחיות בדיוק כמו עלות מבוססת-מחירון. העלות מתעדכנת אוטומטית בסיום משמרת (החתמת יציאה), בעריכת/מחיקת/אישור/דחיית משמרת ובהוספת משמרת רטרואקטיבית — ברקע, בלי להאט את ההחתמה — וריצת איזון לילית מתקנת את שלושת הימים האחרונים ליתר ביטחון. בריחוף על עלות בכרטיסיית התמחור של משלוח מוצג הפירוק המלא: שכר היום, שעות נטו, תעריף, ומספר המשימות שהשכר חולק ביניהן. מחירון מוגדר תמיד גובר (גם לשכיר), שכיר במשכורת חודשית גלובלית אינו מחולק (אין פילוח יומי משמעותי), ושליח-מנהל עם סאב-שליחים מוחרג — חיוב מנהל מחייב מחירון. אגב העבודה אוחד גם חישוב 'היום הישראלי' (עוגן אזור-זמן Asia/Jerusalem) ל-helper משותף אחד בין מנוע הרווחים למנוע ה-snapshots, ומשלוחים שנמחקו (סל מיחזור) הוחרגו מחלוקת השכר כדי שחלק מהעלות לא ייעלם מהדוחות. בהמשך תוקנה תקלה שהתגלתה בשטח מיד אחרי ההמרה של שליח קיים לשכיר: עריכת שליח ששמרה שדה 'מזהה ליונוויל' ריק ניתקה את השליח מליונוויל, וה-webhook הבא יצר אוטומטית שליח כפול — וכל המשלוחים החדשים שובצו לכפיל במקום לשכיר. שלושה תיקונים: (1) סנכרון הנהגים מזהה כעת מזהה ליונוויל לא-מוכר ששייך לשליח קיים (התאמת טלפון מנורמלת) ומקשר אותו מחדש במקום ליצור כפיל; (2) בעדכון שליח, שדה מזהה ליונוויל שלא נשלח כלל שומר על הערך הקיים (רק ריקון מפורש מנתק); (3) הוולידציה מקבלת כעת גם מזהה מספרי — כפתור הפעיל/לא-פעיל בדף השליח שלח מספר ונפל על ולידציה. הנתונים בפרודקשן תוקנו ידנית: הכפיל אוחד חזרה לשליח המקורי (29 ביקורים הוחזרו, המזהה שוחזר). בהמשך היום תוקן באג בטבלת המשלוחים: ספירות הפילטרים בחלונית הסינון (למשל 'שובץ לשליח איסוף — 78') לא תאמו את מספר השורות שהוצגו בפועל אחרי בחירת הפילטר. הספירות חושבו תמיד לפי תאריך יצירת המשלוח, בעוד הטבלה כיבדה את בורר שדה-התאריך (תאריך מסירה / איסוף / קליטה במחסן) — כך שבכל בחירה של שדה תאריך שאינו ברירת המחדל המספרים בפילטר לא שיקפו את התוצאות. כעת הספירות מסוננות לפי אותו שדה תאריך בדיוק כמו הטבלה, ובנוסף הן מביאות בחשבון גם את מסנן סטטוס התפעול ואת מסנני השדות המותאמים-אישית, שעד כה הוחלו על הטבלה בלבד. אגב התיקון אוחדה התנהגות מסנן השדות המותאמים-אישית לחיפוש שאינו רגיש לאותיות גדולות/קטנות בכל המסלולים, ועדכוני שורות חיים (SSE) מכבדים כעת גם את מסנני סוג-המשימה וסטטוס-התפעול — משלוח חדש שלא תואם את הפילטר הפעיל לא יתווסף יותר לטבלה המסוננת בזמן אמת. בנוסף (התראות מערכת): חוזק ערוץ ההתראות למנהל נגד הצפה — מפתח מניעת-הכפילויות מנורמל כך ש-request-id ומספרים דינמיים בהודעת השגיאה לא עוקפים עוד את חלון ההשתקה של שעה, ונוספה תקרת פרץ (עד 4 התראות ב-5 דקות) כך שתקרית תשתית רוחבית, כמו מיצוי connection pool, לא מציפה את המנהל במטח הודעות. בהמשך נוספו שני שיפורים שצפו מחקירת 'השליח הנעלם': (א) רמז חיפוש חוצה-טאבים בטבלת השליחים — כשחיפוש לא מוצא תוצאות בטאב הנוכחי אך קיימות התאמות בטאבים אחרים (פעילים / לא פעילים / קבלנים חיצוניים), מוצג באנר עם צ'יפים לחיצים שמעבירים ישירות לטאב הרלוונטי עם מונה התאמות — כך שליח לא 'נעלם' רק כי הוא מסווג בטאב אחר. (ב) הקשחת multi-tenancy בקריאת משלוחים: מסלול שליפת משלוח לפי ברקוד לא סינן לפי ארגון — משתמש מחובר של ארגון אחר יכול היה לקרוא משלוח זר לפי ברקוד (הברקוד ייחודי כלל-מערכתית); נוסף סינון tenant מחייב. בנוסף, בכל מסלולי הקריאה של משלוח/ביקור, נהג שמשויך לביקור אך שייך לארגון אחר (driverId פגום/היסטורי) מוסתר מהתשובה במקום להדליף שם וטלפון של שליח זר — הביקור מוצג כלא-משובץ. בהמשך טופלה מן היסוד גם האיטיות של סינון בטבלת המשלוחים ובדף שיבוץ האיסופים (סימון סטטוס בפילטרים 'חשב' שניות ארוכות, ובעומס אף הפיל בקשות אחרות): כל שאילתות הסטטוס חילצו את הסטטוס מתוך ה-JSON הגולמי הכבד של ליונוויל בכל שורה מועמדת (כ-5KB לשורה על פני מאות אלפי שורות), במקום להשתמש בעמודת הסטטוס הממופתחת שקיימת בבסיס הנתונים מאז יוני ומסונכרנת אוטומטית. שש נקודות קצה (רשימת משלוחים, ספירות פילטרים, מפה — וכן שלישיית שיבוץ האיסופים) הוסבו לעמודה הממופתחת: ספירת הסטטוסים ירדה מ-16 שניות לשנייה אחת, וסינון סטטוס מ-4.4 שניות ל-0.2 שניות — פי 20 ומעלה, עם תוצאות זהות (אומת מול נתוני הפרודקשן). נוסף אינדקס חדש לסינון לפי 'תאריך קליטה במחסן' (1.6 שניות → 0.5), ושאילתות ספירת הפילטרים פוצלו לשתי קבוצות כך שבקשה בודדת לא תתפוס עוד את כל מאגר חיבורי בסיס-הנתונים — הגורם לתקלות העומס החוזרות של החודש האחרון. תוקן גם החיפוש הגלובלי: הדבקת מספר ארוך (טלפון ללא מקפים, מזהה שותף) הפילה את כל החיפוש בשגיאת שרת במקום להחזיר תוצאות — כעת ערך מספרי שגדול מדי בשביל להיות מזהה משלוח פנימי פשוט מדולג, והחיפוש הטקסטואלי (ברקוד/טלפון/מזהי שותף) ממשיך לעבוד כרגיל. שופר גם ייצוא האקסל של טבלת המשלוחים, שסבל מאותה איטיות ביתר שאת (ייצוא מסונן ארך יותר מ-10 דקות): מלבד האצת השאילתות עצמן, מנגנון הדפדוף של הייצוא הפסיק להריץ מחדש את שאילתת ספירת-הכול הכבדה על כל עמוד ועמוד (היא רצה כעת פעם אחת בלבד בתחילת הייצוא), נוסף טיפול חינני במגבלת קצב הבקשות — ייצוא גדול ממתין ומנסה שוב במקום להיכשל באמצע — והטוסט מציג התקדמות חיה: 'מייצא X מתוך Y שורות'. בנוסף (אפליקציית שליחים — תשתית בנייה): יושרו ממצאי expo-doctor לקראת הבנייה הבאה לחנות — הוסר מפתח supportsRtl לא-חוקי מ-app.json (תבנית ה-manifest של Expo כבר כוללת אותו כברירת מחדל, ה-RTL נשמר), תצורת Metro משמרת את תיקיות המעקב של ברירת המחדל, וחמש חבילות Expo יושרו לגרסאות ה-SDK — 18/18 בדיקות עוברות. בנוסף (נוכחות — עובדים מזדמנים): לכל כניסת משמרת נוסף שדה חובה 'סוג עבודה' — ליקוט / עבודת מחסן / שירות לקוחות / אחר. בבחירת ליקוט נפתחת בחירת לקוח חובה מתוך קומבובוקס עם חיפוש שמציג רק לקוחות עם ליקוט פעיל (נגיש גם לתפקיד מנהל עובדים, בלי לחשוף את מודול הלקוחות המלא), ולכל משמרת ניתן לצרף הערה חופשית — למשל פירוט כשנבחר 'אחר'. סוג העבודה ולקוח הליקוט מוצגים בטבלת הכניסות, בהיסטוריה החודשית ובכרטיסי המובייל, והחיפוש בטבלה מאתר כניסות גם לפי שם לקוח הליקוט. בנוסף (סנכרון חנויות — בריאות חיבורים): נבנה מנגנון בריאות לחיבורי חנויות (קונימבו, אישופ, WooCommerce, nopCommerce, CashCow) — חיבור שנכשל שוב ושוב (טוקן שבוטל בחנות, חסימת Cloudflare) נכנס ל-backoff מדורג של עד שעה במקום לירות את אותה שגיאה כל 5 דקות ולהציף את יומן הפרודקשן ואת ערוץ ההתראות למנהל (התראה אחת בתחילת רצף כשל; החזרות יורדות לרמת אזהרה). השגיאה מסווגת להודעה קצרה וברורה בעברית — למשל 'חסימת Cloudflare — ה-IP עדיין לא ברשימה הלבנה' במקום עמוד HTML שלם — נשמרת על החיבור ומוצגת בפורטל הלקוח על כרטיס החנות. סנכרון מוצלח, עדכון פרטי חיבור, בדיקת חיבור מוצלחת או הפעלה מחדש של החיבור מאפסים את המנגנון מיידית כך שברגע שהתקלה נפתרת (אצלנו או אצל הספק) הסנכרון חוזר תוך דקות. בנוסף (ביצועים — השלמת מיגרציית עמודת הסטטוס): כל שאילתות הסטטוס שנותרו על ה-JSON הכבד של ליונוויל הוסבו לעמודת הסטטוס הממופתחת — 17 קבצים נוספים: מבט מחסן (+debug), פערי הפצה, אנליטיקות שליחים (כללי ופר-שליח), משלוחים מעוכבים בפורטל השליחים, טעויות מיון (+מפה), משלוחי כרטיס לקוח, ניקוי היסטורי, סנכרון משלוחים פתוחים, משיכת תמונות מסירה, דף הליקוט (+סטטיסטיקות) וכלי ה-AI (מנהל ולקוח) — נסגר סופית שורש תקלות מיצוי מאגר החיבורים של החודש האחרון. אגב כך תוקן באג שבו חיפוש בדף הליקוט דרס בשקט את פילטר הקטגוריה (שוטף/מזדמן) — שני הפילטרים חיים כעת יחד. כמו כן אובחן מקור מטח שגיאות ה-401 של קונימבו ביומן — חיבור בדיקה ישן עם טוקן מת שכבר הושבת; ואומת שחסימת ה-Cloudflare של אישופ עדיין פעילה מצד הספק (ממתינים לרישום ה-IP הקבוע שלנו ברשימה הלבנה).
- שליח שכיר שעתי ללא מחירון: עלות המשלוחים נגזרת מהשכר בפועל — שכר היום מהמשמרות מחולק שווה-בשווה בין המשימות שביצע
- החישוב זהה למנוע השכר: שעות נטו אחרי הפסקות, שעות נוספות 125%/150% לפי הגדרות הארגון, נסיעות יומיות
- עדכון אוטומטי בהחתמת יציאה ובכל שינוי משמרת (עריכה/מחיקה/אישור/דחייה/רטרו) — ברקע, בלי להאט את ההחתמה
- ריצת איזון לילית (cron) מתקנת את 3 הימים האחרונים — עמידות לעריכות בדיעבד
- tooltip פירוק מלא בכרטיסיית התמחור: שכר יום, שעות, תעריף שעתי ומספר המשימות בחלוקה
- מחירון מוגדר תמיד גובר; משכורת חודשית גלובלית ושליח-מנהל מוחרגים במכוון
- משלוחים בסל המיחזור מוחרגים מהחלוקה — העלות לא נעלמת מהדוחות
- רמז חיפוש חוצה-טאבים בטבלת השליחים — באנר עם קפיצה ישירה לטאב שבו נמצאו ההתאמות
- אבטחה: שליפת משלוח לפי ברקוד מסוננת כעת לפי ארגון, ונהג זר (cross-tenant) לעולם לא מוצג על ביקור
- עובדים מזדמנים: שדה חובה 'סוג עבודה' לכל משמרת (ליקוט / עבודת מחסן / שירות לקוחות / אחר), בחירת לקוח ליקוט חובה בקומבובוקס עם חיפוש, והערה חופשית אופציונלית
- סנכרון חנויות: חיבור כושל נכנס ל-backoff מדורג עם שגיאה מסווגת שמוצגת בפורטל — סוף להצפת יומן והתראות כל 5 דקות; מתאפס אוטומטית ברגע שהתקלה נפתרת
- הושלמה מיגרציית עמודת הסטטוס ב-17 הקבצים שנותרו (מחסן, פערים, אנליטיקות, ליקוט, AI, סנכרונים) — סגירה סופית של שורש תקלות מיצוי מאגר החיבורים
v01.162.000חדששליחים / אפליקציית שליחיםminorחשבון אפליקציה לשליח — המנהל קובע סיסמה התחלתית
עד היום פתיחת חשבון לשליח חייבה שליחת מייל הפעלה שבו השליח קובע סיסמה בעצמו — חסם תפעולי משמעותי בקליטת שליחים.
פרטים נוספים ↓הסתר ↑
עד היום פתיחת חשבון לשליח חייבה שליחת מייל הפעלה שבו השליח קובע סיסמה בעצמו — חסם תפעולי משמעותי בקליטת שליחים. נוסף כפתור 'חשבון אפליקציה' בדף השליח: המנהל מזין אימייל וסיסמה התחלתית (או מייצר סיסמה אקראית בלחיצה), מוסר לשליח את פרטי הכניסה — והשליח נכנס לאפליקציה מיידית. השליח יכול להחליף סיסמה בכל שלב דרך 'שכחתי סיסמה'. בנוסף תוקן פער קריטי: חשבונות שנוצרו דרך זרימת הפורטל נוצרו ללא שיוך ארגון (TenantUser) ולכן לא יכלו להתחבר לאפליקציית השליחים כלל — מעכשיו כל יצירת חשבון (בשתי הזרימות) יוצרת את השיוך, ועדכון סיסמה ע"י מנהל מתקן אוטומטית חשבונות ותיקים חסרי שיוך. בהמשך היום תוקנה קריסת אפליקציה בפתיחת פרטי משלוח: ביקורים אמיתיים ללא שם איש-קשר (Visit.name ריק) הפילו את מסך הפרטים בחישוב ראשי-תיבות — ה-API מחזיר כעת נפילה לשם הלקוח מהמשלוח, והמסכים (פרטי משלוח, גוביינא) הוקשחו מול שם/טלפון ריקים כולל נטרול כפתורי חיוג/וואטסאפ כשאין טלפון. תוקנו גם ייבואים שבורים של TODAY_QUERY_KEY (רענון נתונים אחרי מסירה/כשל/גבייה לא עבד), נוסף גוון primary-400 חסר לפלטה, ותוקנו שגיאות טיפוסים — typecheck של אפליקציית המובייל נקי לחלוטין. בהמשך היום תוקנו שני ליקויים בדף פרטי השליח: (1) כרטיסיית 'פרטים אישיים' לא הציגה כתובת אימייל לשליחים שאינם שכירים — האימייל נשמר רק על רשומת העובד שקיימת לשכירים בלבד; כעת, כשאין רשומת עובד, מוצג האימייל של חשבון המשתמש המקושר (פורטל/אפליקציה). (2) כפתור 'עריכה' בדף השליח ניווט לטבלת השליחים הראשית ופתח שם את דיאלוג העריכה — כעת הדיאלוג נפתח ישירות בדף השליח, בלי לצאת ממנו. בנוסף (הודעות — צ'אט עסקי): כל הודעה יוצאת בצ'אט העסקי (business-inbox) מציגה כעת מי כתב אותה — אווטר ושם של הנציג ששלח מתוך המערכת (כמו בצ'אט הלקוחות), תג AI סגול להודעות שהבוט חיבר, חיווי ייעודי להודעות שהוקלדו ידנית בטלפון של העסק, וחיווי 'הודעה אוטומטית' להודעות טריגר/בוט שנשלחו דרך ה-API. גם ציטוט של הודעת נציג מציג כעת את שם הנציג במקום 'צוות' גנרי. הודעות ישנות (שקדמו לשינוי) ממשיכות להיות מוצגות עם אייקון צוות כללי. בהמשך היום תוקן כשל בהמרת שליח קיים לשליח שכיר: כאשר כבר הייתה רשומת עובד עם אותה תעודת זהות במודול העובדים, השמירה קרסה עם שגיאת מערכת גולמית באנגלית. כעת ההמרה מזהה את העובד הקיים ומקשרת אליו את השליח (תוך שמירה על פרטי ההתחברות של העובד), ואם הת"ז שייכת לעובד שכבר מקושר לשליח אחר — מוצגת הודעת שגיאה ברורה בעברית על שדה הת"ז. בנוסף, כל שגיאת כפילות נתונים במערכת (unique constraint) מוצגת מעתה כהודעה ידידותית בעברית במקום טקסט שגיאה טכני באנגלית. סבב תיקונים נוסף מבדיקות שטח של אפליקציית השליחים: (1) תור הסנכרון הלא-מקוון לא הופעל אחרי ביצוע פעולה — מסירה/גוביינא/הוכחת-מסירה המתינו עד מעבר רקע-חזית של האפליקציה; נוסף טריגר שמסנכרן מיידית עם כל פעולה, והתור ממשיך לעבד עד ריקון. זה היה גם השורש לכך שכפתור 'דווח על כשל' נשאר פעיל אחרי מסירה ושכפתורי הוכחת-המסירה ננעלו אחרי שמירה. (2) העלאת הוכחת מסירה פוצלה לבקשה-נפרדת-לכל-תמונה — בקשה מרובת תמונות (base64) חצתה את מגבלת גוף-הבקשה של Vercel (4.5MB) וה-413 שהוחזר תקע את התור כולו; 413 מסווג כעת ככשל קבוע שאינו חוסם את התור. (3) ציור פוליגון במפה היה בלתי-נראה (אך הבחירה עבדה) — טעינת סגנון MapTiler אחרי עליית המפה מחקה את שכבות הציור; המפה עולה כעת רק אחרי שהסגנון נטען, והחלפת סגנון גוררת רינדור נקי מחדש. (4) יכולת חדשה: שליח יכול להוסיף ולהסיר משלוח מהמסלול הפעיל — בלחיצה ארוכה על משלוח ברשימה או מתפריט מסך המשלוח (endpoint חדש /api/v1/mobile/route/stops). (5) לחיצה ארוכה על משלוח פותחת כעת גיליון פעולות מעוצב (התקשר / וואטסאפ / נווט / הוספה-הסרה מהמסלול) במקום דיאלוג נייטיבי שלא ניתן היה לסגור, וכפתור שלוש-הנקודות במסך המשלוח — שלא עשה דבר — מחווט לתפריט פעולות מלא כולל שיתוף פרטי משלוח. (6) כפתור הניווט פותח כעת Waze ישירות — canOpenURL מחזיר false באנדרואיד 11+ ולכן תמיד נפתחה Google Maps.
- כפתור 'חשבון אפליקציה' בדף השליח — יצירת חשבון עם אימייל + סיסמה התחלתית, ללא תלות במייל הפעלה
- מחולל סיסמאות אקראיות + כפתור 'העתק פרטי התחברות' למסירה מהירה לשליח בוואטסאפ
- מנהל יכול לאפס סיסמה לשליח קיים בכל שלב; השליח יכול להחליף אותה בעצמו אחר כך
- תוקן: חשבונות שליח שנוצרו דרך הפורטל לא יכלו להתחבר לאפליקציה (חסר שיוך ארגון) — נוצר אוטומטית בכל הזרימות
- תוקן: קריסת אפליקציית השליחים בפתיחת משלוח ללא שם איש-קשר + הקשחת מסכי פרטים/גוביינא מול נתונים חסרים
- תוקן: אימייל לא הוצג בפרטים אישיים לשליח קבלן (נופל כעת לאימייל חשבון המשתמש) + כפתור 'עריכה' פותח את הדיאלוג בדף השליח במקום לנווט לטבלה
- צ'אט עסקי: חיווי 'מי כתב מה' על כל הודעה יוצאת — אווטר + שם הנציג ששלח מהמערכת, תג AI לבוט, וחיווי נפרד להודעות מהטלפון של העסק ולהודעות אוטומטיות
- תוקן: המרת שליח לשכיר קרסה כשכבר קיים עובד עם אותה ת"ז — כעת השליח מקושר לרשומת העובד הקיימת, ושגיאות כפילות מוצגות בעברית
- אפליקציית שליחים: סנכרון מיידי של מסירות/גוביינא/הוכחות-מסירה (התור נתקע עד מעבר רקע-חזית) + העלאת תמונות מפוצלת שלא נתקעת במגבלת Vercel
- אפליקציית שליחים: שליח מוסיף/מסיר משלוח מהמסלול הפעיל, גיליון פעולות מעוצב בלחיצה ארוכה ובכפתור שלוש-הנקודות, ניווט נפתח ישירות ב-Waze, וציור אזור במפה נראה שוב
v01.161.001שיפוראפליקציית שליחיםאפליקציית שליחים — הכנות לפרסום ב-Google Play
(1) המיני-מפה בתצוגת פרטי המשלוח השתמשה במפות Google (react-native-maps + PROVIDER_GOOGLE) ודרשה מפתח Google Maps API שלא הוגדר — כך שבבנייה לפרודקשן המפה הייתה מוצגת ריקה.
פרטים נוספים ↓הסתר ↑
(1) המיני-מפה בתצוגת פרטי המשלוח השתמשה במפות Google (react-native-maps + PROVIDER_GOOGLE) ודרשה מפתח Google Maps API שלא הוגדר — כך שבבנייה לפרודקשן המפה הייתה מוצגת ריקה. הוחלפה למנוע MapLibre + MapTiler בסגנון העברית, בדיוק כמו מסך המפה הראשי; בוטלה התלות ב-Google Maps SDK, וחבילת react-native-maps והגדרת android.config.googleMaps הוסרו. (2) משתני הסביבה (EXPO_PUBLIC_API_BASE_URL, EXPO_PUBLIC_MAPTILER_KEY) חוברו ל-eas.json ל-profiles preview+production, כדי שבניית ה-AAB בענן לא תצא בלי כתובת השרת/מפתח המפה. (3) כפתור 'המשך עם Google' במסך הכניסה הפך למותנה — מוצג רק כשמוגדר EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID, כך שבודקים לא נתקלים בכפתור לא-פעיל עד שה-Google Sign-In יחווט במלואו. (4) versionCode קודם ל-2.
v01.161.000חדשפורטל שליחיםminorפורטל שליחים — תצוגת 'משלוחים מעוכבים' + אזורי אחריות בכרטיס השליח
באזור האישי של השליחים נוסף מתג עליון 'הדוח שלי / משלוחים מעוכבים' (עם מונה אדום).
פרטים נוספים ↓הסתר ↑
באזור האישי של השליחים נוסף מתג עליון 'הדוח שלי / משלוחים מעוכבים' (עם מונה אדום). התצוגה החדשה מציגה לשליח את המשלוחים המעוכבים הרלוונטיים אליו, לפי אותה הגדרת 'עיכוב' כמו דף פערי ההפצה של המשרד (סטטוס מסירה פתוח + חלפו ≥ סף ימי-עסקים של הטננט). כלל הנראות: (1) כל משלוח מעוכב שמשובץ עליו או על שליחי המשנה שלו — בכל אזור; (2) משלוח מעוכב שאינו משובץ על אף שליח — רק אם הוא באחד מ'אזורי האחריות' שלו; (3) משלוח המשובץ על שליח אחר — לא מוצג. לכל משלוח מוצג סטטוס: 'משובץ עליך' / 'במחסן' / 'בכשל' (או תרגום הסטטוס), מספר ימי העיכוב, העיר, האזור והברקוד. נוסף גם סינון פנימי: הכל / משובצים עליי / באזורי האחריות. לצורך כך נוסף שדה חדש בכרטיס השליח — 'אזורי אחריות' (מקביל ל'אזורים מורשים', בפורמט אזורי ליונוויל).
- מתג עליון בפורטל: 'הדוח שלי' / 'משלוחים מעוכבים' עם מונה אדום חי
- שדה חדש בכרטיס השליח: 'אזורי אחריות' — אזורי הפצה שהשליח מחוייב עליהם (נפרד מ'אזורים מורשים')
- משלוח מעוכב לא-משובץ מופיע לשליח רק אם הוא באזורי האחריות שלו; משלוח שמשובץ על שליח אחר לא מופיע
- משלוחים המשובצים על השליח או על שליחי המשנה שלו מופיעים בכל אזור
- סטטוס לכל משלוח: 'משובץ עליך' / 'במחסן' / 'בכשל', עם מספר ימי עיכוב וסינון לפי קטגוריה
v01.160.000חדשמשלוחים / טבלהminorסכום עמודה בטבלת המשלוחים — לחיצה על כותרת עמודת מחיר מציגה את הסך הכולל
בעמודות הכספיות של טבלת המשלוחים (מחיר בסיס, סה"כ לחיוב, עלות ליונוויל, עלות איסוף, עלות מסירה, סה"כ עלות, רווח) — הדרופדאון שנפתח בלחיצה על כותרת העמודה מציג כעת את סכום כל הערכים בעמודה.
פרטים נוספים ↓הסתר ↑
בעמודות הכספיות של טבלת המשלוחים (מחיר בסיס, סה"כ לחיוב, עלות ליונוויל, עלות איסוף, עלות מסירה, סה"כ עלות, רווח) — הדרופדאון שנפתח בלחיצה על כותרת העמודה מציג כעת את סכום כל הערכים בעמודה. הסכום מחושב על *כל* המשלוחים התואמים לסינון הפעיל (כל העמודים, לא רק העמוד המוצג), ומכבד גם סינון-בכותרת-עמודה. כדי לא לעכב את טעינת הטבלה, הנתונים המלאים נשלפים באופן עצל רק בפתיחת הדרופדאון הראשון של עמודה כספית (עם אינדיקציית טעינה), ואז נשמרים ב-cache לשאר העמודות עד לשינוי סינון. הסכום כולל גם עלויות משוערות (projected) בדיוק כמו התצוגה, ומסומן ב-'~' ובהערה 'כולל אומדנים' כשיש בו ערכים משוערים.
- לחיצה על כותרת עמודת מחיר/עלות/רווח → סכום כל העמודה בראש הדרופדאון
- הסכום מחושב על כל המשלוחים המסוננים (כל העמודים), לא רק העמוד המוצג
- מכבד סינון-בכותרת-עמודה; כולל עלויות משוערות עם סימון '~'
- שליפה עצלה + cache — אפס עלות על טעינת הטבלה עד שפותחים סכום
v01.159.002תיקוןמשלוחים / טבלה / ייצוא Excelטבלת המשלוחים: תיקונים
(1) ייצוא ל-Excel: עמודות העלות (עלות איסוף, עלות מסירה, סה"כ עלות) והרווח ייצאו ריק כשהמשלוח עדיין לא סיים ביקור והעלות הייתה 'עלות משוערת' בלבד (projected) — למרות שהערך מוצג בבירור בטבלה.
פרטים נוספים ↓הסתר ↑
(1) ייצוא ל-Excel: עמודות העלות (עלות איסוף, עלות מסירה, סה"כ עלות) והרווח ייצאו ריק כשהמשלוח עדיין לא סיים ביקור והעלות הייתה 'עלות משוערת' בלבד (projected) — למרות שהערך מוצג בבירור בטבלה. הייצוא קרא רק את העלות הבפועל והתעלם מהצפי. כעת הייצוא נופל חזרה לעלות המשוערת בדיוק כמו הטבלה, כולל סימון '~' לפני ערך שהוא צפי. (2) הטולטיפ של עלות משוערת ('צפי — מבוסס על מחירון השליח/אזור') נתקע פתוח: ריחוף מהיר על תאים רצופים פתח ערימת טולטיפים שלא נסגרו. הסיבה — ה-Tooltip נטען לא-מבוקר (defaultOpen) רק אחרי שהעכבר כבר נכנס לתא, כך ש-Radix פספס את אירוע הכניסה ולא סגר ביציאה. כעת ה-Tooltip מבוקר (open/onOpenChange) ונסגר ודאית ביציאת העכבר. (3) עמודת 'עלות ליונוויל' שונתה ל'מחיר ליונוויל' (זהו המחיר שהתקבל מליונוויל, לא עלות ביצוע).
v01.159.001תיקוןנוכחות / חישוב שכרחישוב שכר: שכר חודשי קבוע + חיווי על עובדים שדולגו
שני תיקונים במנוע חישוב השכר (/attendance/payroll): (1) עובד עם 'שכר חודשי' (monthlyRate) קיבל עד כה ₪0 — החישוב הכפיל תמיד שעות×תעריף-שעתי והתעלם לחלוטין מה-monthlyRate.
פרטים נוספים ↓הסתר ↑
שני תיקונים במנוע חישוב השכר (/attendance/payroll): (1) עובד עם 'שכר חודשי' (monthlyRate) קיבל עד כה ₪0 — החישוב הכפיל תמיד שעות×תעריף-שעתי והתעלם לחלוטין מה-monthlyRate. כעת עובד עם שכר חודשי מקבל את הסכום החודשי הקבוע ללא תלות במספר השעות שעבד (השעות עדיין נרשמות לתצוגה), בתוספת בונוסים וקצובת נסיעות. (2) כשלא הוגדר תעריף לאף עובד, 'חישוב שכר' דילג על כולם בשקט והחזיר '0 עובדים' בלי הסבר — מה שנראה כאילו הדף שבור. כעת המערכת מחזירה ומציגה בדיוק אילו עובדים דולגו ומדוע (לא הוגדר תעריף שעתי או שכר חודשי), כך שברור שצריך להשלים תעריף בכרטיס העובד.
v01.158.000תיקוןפערי הפצה / משלוחים / היסטוריית פעולותminorבטיחות שינוי סטטוס מרובה: 'בחר הכל' מכבד סינון-בכותרת, אישור לפני שינוי, ושחזור מ-bulk-history
בעקבות תקלה שבה סינון בתוך כותרת עמודה בדף 'פערי הפצה' צמצם תצוגתית ל-~20 שורות, אך 'בחר הכל' סימן את כל ~120 המשלוחים שברשימה ושינוי הסטטוס ל'הושלם' חל על כולם.
פרטים נוספים ↓הסתר ↑
בעקבות תקלה שבה סינון בתוך כותרת עמודה בדף 'פערי הפצה' צמצם תצוגתית ל-~20 שורות, אך 'בחר הכל' סימן את כל ~120 המשלוחים שברשימה ושינוי הסטטוס ל'הושלם' חל על כולם. שלושה תיקונים: (1) ב'פערי הפצה', 'בחר הכל' בוחר כעת רק את השורות הגלויות בפועל אחרי הסינון-בכותרת (getFilteredRowModel) במקום את כל הרשימה המסוננת-בשרת — כך שלא יסומנו שורות שהמשתמש לא רואה. (2) שינוי סטטוס מרובה דורש כעת אישור בדיאלוג עם ספירה מדויקת ('הפעולה תשנה את הסטטוס של N משלוחים ל...'), כפי שכבר קיים במחיקה. (3) שינוי סטטוס מרובה נרשם כעת כפעולת מאסה (BulkOperation, action=SET_STATUS) עם snapshot של הסטטוסים הקודמים — ולכן מופיע ב-/management/bulk-history וניתן לשחזור בלחיצת כפתור; השחזור מחזיר את additionalData.status לכל משלוח ודוחף את הסטטוס המשוחזר חזרה לליונוויל (מקבילות חסומה, best-effort).
- 'בחר הכל' בפערי הפצה מכבד את הסינון בכותרת העמודה — לא בוחר עוד שורות מוסתרות
- אישור חובה עם ספירה לפני שינוי סטטוס מרובה
- שינוי סטטוס מרובה ניתן כעת לשחזור מ-/management/bulk-history (כולל דחיפה חזרה לליונוויל)
v01.157.003תיקוןמשלוחים / סנכרון ליונווילתיקון: סנכרון נכנס מליונוויל מחק שיבוץ שליח מסירה (קבלן) שבוצע בסריקה
באג איבוד-נתונים: שיבוץ שליח מסירה שבוצע בסריקת מחסן נמחק אצלנו אך נשאר בליונוויל.
פרטים נוספים ↓הסתר ↑
באג איבוד-נתונים: שיבוץ שליח מסירה שבוצע בסריקת מחסן נמחק אצלנו אך נשאר בליונוויל. השיבוץ נשמר על ה-Visit (visit.driverId) ונדחף לליונוויל; אך כשהמשלוח משובץ לקבלן, ליונוויל מנהל אותו כמשימת partner נפרדת, ולכן ה-DELIVERY visit חוזר בסנכרון (webhook ו-cron sync-recent-shipments) ללא driver_id שניתן לפענח. נתיב ה-upsert ב-data-service דרס את visit.driverId המקומי ל-null על כל סנכרון — כך שבליונוויל הופיע הקבלן כשליח מסירה, ואצלנו 'אין שליח משובץ'. ה-cron מרענן מחזורית את כל המשלוחים האחרונים, ולכן הבאג פגע בהרבה משלוחים. התיקון: הסנכרון הנכנס כבר לא מאפס שליח מסירה מקומי קיים כאשר המשלוח נמצא בסטטוס 'יצא למסירה' (OUT_INVENTORY/IN_TRANSFER) גם לפני הסנכרון וגם אחריו וה-visit הנכנס בלי נהג ממופה — הוא רק קובע/מעדכן נהג כשיש נהג ודאי. מעבר ל'נקלט במחסן' עם שדה שליח ריק (החזרה למחסן) ממשיך לאפס שליח כרגיל, כי זה ביטול שיבוץ לגיטימי. נוסף סקריפט שחזור (backfill-wiped-delivery-drivers, dry-run כברירת מחדל) שמשחזר שיבוצים שכבר נמחקו, מתוך ה-audit log של הסריקות (driverId המקומי + זמן השיבוץ האמיתי).
v01.157.002תיקוןמשלוחים / תמחור ורווחיותתיקון: עמודות העלות/רווח בטבלת המשלוחים הציגו ₪0 למשלוח פתוח במקום הצפי שמוצג בכרטיס התמחור
בכרטיסיית 'תמחור ורווחיות' של דף המשלוח, עלות מסירה/איסוף לביקור שטרם הושלם מוצגת כ'צפי' (לפי מחירון השליח שהוקצה, או אומדן אזורי כשאין שליח/מחירון) — אך בטבלת המשלוחים עצמה אותן עמודות (עלות איסוף/מסירה/סה"כ עלות/רווח) …
פרטים נוספים ↓הסתר ↑
בכרטיסיית 'תמחור ורווחיות' של דף המשלוח, עלות מסירה/איסוף לביקור שטרם הושלם מוצגת כ'צפי' (לפי מחירון השליח שהוקצה, או אומדן אזורי כשאין שליח/מחירון) — אך בטבלת המשלוחים עצמה אותן עמודות (עלות איסוף/מסירה/סה"כ עלות/רווח) קראו רק את ה-snapshot השמור ב-DB, שעדיין NULL/0 עד השלמת הביקור. התוצאה: משלוח שבדף שלו מוצגת עלות ~20 ₪ הראה בטבלה עלות 0 ורווח מנופח (הכנסה פחות 0). כעת ה-API של רשימת המשלוחים מחשב את הצפי בצורה מקובצת (projectPendingCostsForList — טוען ביקורים, מחירוני שליחי-החיוב ואת השליחים המורשים-לאזור פעם אחת לכל העמוד, במקום לולאה פר-משלוח) ומצרף projectedPickupCost/projectedDeliveryCost. הטבלה מציגה עלות אפקטיבית = snapshot ?? צפי, מסומנת ב-~ עם הסבר בריחוף, והרווח נגזר ממנה — כך שהטבלה והכרטיס תואמים. הצפי מחושב רק כשהעלות השמורה NULL, ורק תחת הרשאת FINANCE_VIEW. שיפור ביצועים (המשך): חישוב החיוב (computeShipmentListBilling) ואומדן הצפי (projectPendingCostsForList) רצים כעת במקביל (Promise.all) במקום בטור על הנתיב החם של רשימת המשלוחים — אחרי שחרור הפיצ'ר העמוד הואט, כי שתי סדרות ה-round-trips מול Accelerate נצברו זו אחר זו על כל טעינה אצל משתמשי פיננסים. בנוסף, העבודה הכבדה (חיוב + אומדן) רצה כעת רק כשעמודת תמחור/עלות/רווח גלויה בפועל — כשאף עמודה כזו אינה מוצגת הטבלה שולחת withPricing=0 וה-API מדלג על החישוב לגמרי (ברירת המחדל היא לחשב, כך ששאר צרכני ה-API לא הושפעו). ובצד-הלקוח: הטבלה אינה virtualized, וכל תא-אומדן עטף את הערך ב-Tooltip של Radix — מה שיצר עד אלפי אינסטנסים בו-זמנית בעמוד עמוס והאט מאוד את הרינדור; כעת ה-Tooltip נטען בעצלתיים, רק כשמרחפים מעל התא בפועל, כך שאפס עלות mount עד אז.
v01.157.001ייעולרווחיות לקוחות / ביצועיםשיפור ביצועים וחיווי טעינה בכרטיסיית רווחיות הלקוח
כרטיסיית הרווחיות (P&L) בדף הלקוח הייתה איטית מאוד ו'תקעה' את המסך בעת חישוב, גם בניווט מחודש לחודש.
פרטים נוספים ↓הסתר ↑
כרטיסיית הרווחיות (P&L) בדף הלקוח הייתה איטית מאוד ו'תקעה' את המסך בעת חישוב, גם בניווט מחודש לחודש. הסיבה: אומדן העלות למשלוחים הפתוחים (projectedCostForCustomer) הריץ את projectPendingCostsForShipment בלולאה סדרתית — עד 150 משלוחים, כל אחד בכמה שאילתות DB דרך Accelerate — כלומר מאות round-trips ברצף. כעת האומדן רץ במקביל ב-batches חסומים (concurrency=12), כך שזמן הקיר יורד מסכום-כל-הקריאות למקסימום-batch. בנוסף, רכיב הכרטיסייה הציג ספינר רק בטעינה הראשונה; בניווט חודש הוא הציג את הנתון הישן בלי שום חיווי ולכן נראה תקוע. כעת מוצג ספינר בכל שליפה (כולל מעבר חודש), עם עמעום עדין של הנתון הקודם — כך שתמיד יש משוב למשתמש. הרחבה (לשונית 'רווחיות' ב-פיננסים): הטבלה של כל-הלקוחות נכשלה לעיתים בשגיאת 500 כי שליפת כל משלוחי החודש בבת אחת חרגה ממגבלת התגובה של Accelerate (5MB) — והקליינט בלע את השגיאה ונשאר על נתון ישן ('תקוע'). כעת השליפה מחולקת ל-batches לפי cursor (כל תגובה קטנה מהמגבלה); חיפושי אזור-לפי-עיר (~30 ברצף) וחישובי עמלות-הסוכן רצים במקביל עם תקרת מקביליות ונשמרים במטמון; ובלשונית עצמה נוסף חיווי טעינה בכל שליפה ומצב-שגיאה גלוי, במקום מסך שנראה תקוע.
v01.157.000חדשפיננסים / רווחיות לקוחותminorלשונית 'רווחיות' חדשה במודול פיננסים — טבלת רווחיות לכל הלקוחות עם פילטרים, סיכום וייצוא
נוספה לשונית ייעודית 'רווחיות' תחת פיננסים (לצד תזרים ומאזן), המרכזת את דוח הרווח-וההפסד החודשי של כל הלקוחות בטבלה אחת — כל שורה היא סיכום ה-P&L של לקוח (הכנסת שילוח + מחסן מול עלות נהגים/קבלנים + עמלת סוכן + זיכויים, ר…
פרטים נוספים ↓הסתר ↑
נוספה לשונית ייעודית 'רווחיות' תחת פיננסים (לצד תזרים ומאזן), המרכזת את דוח הרווח-וההפסד החודשי של כל הלקוחות בטבלה אחת — כל שורה היא סיכום ה-P&L של לקוח (הכנסת שילוח + מחסן מול עלות נהגים/קבלנים + עמלת סוכן + זיכויים, רווח נטו), בדיוק כמו בכרטיס הרווחיות שבעמוד הלקוח, עם שורת פירוט נפתחת. מעל הטבלה שורת סיכום (סך הכנסה / עלות / רווח נטו) שמתעדכנת לפי הפילטרים הפעילים. ארבעה פילטרים, כולם ברמת הלקוח: לפי עיר בית-העסק, לפי אזור חלוקה (נגזר מעיר העסק דרך טבלת הישובים), לפי סוכן, ולפי רווח/הפסד. בשורת הסיכום ניתן להוסיף 'תוספות מזדמנות' — שורות עלות או הכנסה חד-פעמיות (למשל שכירות, פיצוי נקודתי) שאינן נשמרות אלא משוקללות בסיכום ובייצוא בלבד. כפתור 'ייצוא לאקסל' מפיק קובץ xlsx של השורות המסוננות + התוספות המזדמנות + שורת הסיכום. העיר נגזרת מנתוני הספק (lionwheelData) עם נפילה לכתובת החופשית; לקוחות ללא עיר ידועה מקובצים תחת 'ללא עיר/אזור'. הכל מאחורי הרשאת FINANCE_VIEW. תצוגת 'רווחיות לפי לקוח' המקוצרת תחת אנליטיקס→לקוחות נשמרה כפי שהיא.
- לשונית 'רווחיות' חדשה תחת פיננסים — טבלת P&L חודשי לכל הלקוחות, עם שורת פירוט נפתחת
- שורת סיכום (הכנסה/עלות/רווח נטו) שמתעדכנת לפי הפילטרים
- פילטרים ברמת-לקוח: עיר בית-העסק, אזור חלוקה, סוכן, רווח/הפסד
- תוספות מזדמנות חד-פעמיות (עלות/הכנסה) בשורת הסיכום — לסיכום ולייצוא בלבד
- ייצוא לאקסל (xlsx) של השורות המסוננות + המזדמנות + הסיכום
- עיר/אזור נגזרים מכתובת בית-העסק; הכל מאחורי FINANCE_VIEW
- נוספה עמודת 'חבילות' (סך packages ?? 1 לכל משלוח) לצד עמודת 'משלוחים', בטבלה, בשורת הסיכום ובייצוא — כמו בשאר טבלאות המערכת
- הפילטרים אוחדו לפאנל אחד (FiltersPopover) עם בחירה-מרובה, חיפוש וספירות פר-אפשרות, במקום ארבעה תפריטים נפרדים
- חישוב העלות/הרווח כולל כעת אומדן עלות למשלוחים פתוחים (טרם תומחרו סופית) — לפי השליח המשובץ, או לפי שליחי האזור כשאין — בדיוק כמו בכרטיס הלקוח ובטבלת המשלוחים. שורות שכוללות אומדן מסומנות ב-'~' עם פירוט בריחוף, ולייצוא נוספה עמודת 'מזה אומדן'. האומדן מחושב מקובץ (projectPendingCostsForList) בצ'אנקים כדי לא להאט את הדוח
- תג 'חלקי' בעמודת המשלוחים מוצג כעת רק כשלמשלוח אין עלות כלל — לא סופית ולא אומדן (אין שליח משובץ ואין שליח-אזור מתומחר); משלוח פתוח שקיבל אומדן נחשב מכוסה ומסומן ב-'~' בלבד, כך שהתג לא מופיע כפול ומיותר לצד ה-'~'
- נוספה עמודת 'מסירה/חבילה' — עלות מסירה ממוצעת לחבילה (עלות מסירה כולל אומדן חלקי מספר החבילות, לא למשלוח). מסומנת ב-'~' כשכוללת אומדן, ונוספה גם לייצוא לאקסל כולל ממוצע משוקלל בשורת הסיכום
- תיקון: משלוחים מבוטלים (סטטוס 'בוטל') הוחרגו מכל תחשיב הרווחיות — הכנסה, עלות, ספירת משלוחים/חבילות ואומדן — כי הלקוח אינו מחויב עליהם (גם כשקיים מחיר בסיס). חל על טבלת הרווחיות בפיננסים, על תצוגת האנליטיקס ועל כרטיס הרווחיות בעמוד הלקוח
- תיקון קריטי: בטבלת הרווחיות הטננטית האומדן לא נכנס בפועל לחלק מהלקוחות (עמודת עלות הראתה ₪0 אף שבטבלת המשלוחים היה אומדן) — מסנן המועמדים לאומדן היה רחב מדי (כל משלוח מסירה-בלבד נושא pickupCost=null לצמיתות ולכן נספר), ~18K מועמדים חצו את תקרת ההגנה, ומשלוחים פתוחים אמיתיים נחתכו. כעת המועמדים נשלפים מה-DB עם סינון לרגל-פתוחה בלבד (visits.some(isDone:false)), והתקרה הועלתה — כך שכל משלוח פתוח מקבל את האומדן שלו
- שינוי מדיניות: ההכנסה בתחשיב הרווחיות נגזרת אך ורק מהמחירון שהוגדר ללקוח — בסיס (כולל כללי REPLACE/ADD) × מכפיל דחיפות + תוספות (יעד חריג, גוביינא, כפולה) + חבילות נוספות עם הנחת חבילה שנייה/שלישית; זיכויים מנוכים בצד העלות. לקוח **ללא מחירון** מוצג כעת עם הכנסה 0 (במקום נפילה למחיר הספק השמור), כדי שלא תיווצר הכנסה שאינה נגזרת מהתמחור שלנו — וכך בולט שצריך להגדיר לו מחירון. זהה למנוע החיוב של computeShipmentListBilling
- נוספו עמודות 'עלות איסוף' ו'עלות מסירה' (עלות אפקטיבית = סופית + אומדן, מסומנות ב-'~' כשכוללות אומדן) לצד עמודת 'עלות' הכוללת, וכן לייצוא לאקסל — כך שרואים את פירוק עלות הנהגים/קבלנים לפי רגל, בדומה לטבלת המשלוחים
- שיוך משלוח לחודש בתחשיב הרווחיות עבר להתבסס על **תאריך הקליטה** (delayClockStartedAt) — התאריך הגורם שממנו מתחיל מניין ימי ההפצה, זהה לבסיס בדף פערי-ההפצה — במקום commissionableAt. משלוח שטרם נקלט או שורה ישנה ללא השדה נופלים ל-createdAt כדי לא ליפול בין החודשים (כך שחודשים היסטוריים נשמרים). חל על הכנסת השילוח ועלות הנהג; עמלת סוכן/מחסן/זיכויים נשארים על בסיס ההכרה שלהם
- בהירות מונחים בטבלת המשלוחים ובפילטר התאריך: עמודת 'מועד האיסוף' (delayClockStartedAt) שונתה ל'תאריך קליטה מלקוח', ו'תאריך קליטה במחסן' (inInventoryAt) שונתה ל'תאריך כניסה למחסן' — כדי להבחין ברור בין קליטת המשלוח מהלקוח (שממנה נגזרת הרווחיות וימי ההפצה) לבין כניסתו הפיזית למחסן
v01.156.002תיקוןלקוחות / מחירוןתיקון: מחירון לקוח שכלל בו כלל מיובא בתאריך ישן לא ניתן היה לשמירה + השלמת שם-כלל חסמה הקלדה חופשית
שני באגים שמנעו עדכון מחירון ללקוח שכבר בוצע לו 'ייבוא מחירון' עם תאריך תחולה היסטורי.
פרטים נוספים ↓הסתר ↑
שני באגים שמנעו עדכון מחירון ללקוח שכבר בוצע לו 'ייבוא מחירון' עם תאריך תחולה היסטורי. (1) שמירה חסומה: בעת שמירת המחירון נשלחים לשרת כל הכללים הקיימים, כולל הכלל שנוצר מהייבוא עם validFrom היסטורי (למשל 30/04/2026). הגנת ה-45-יום בשרת בדקה כל כלל בבקשה, ולכן דחתה את כל השמירה בשגיאה 'מנסה לחול מתאריך ישן מהמותר' — גם כשהשינוי החדש תוארך להיום. כעת הגנת הרטרואקטיביות חלה רק על כללים חדשים או כללים שתאריך התחולה שלהם שונה — כלל קיים שתאריכו לא נגע בו לא חוסם עוד עריכה לא-קשורה. (2) שדה 'שם הכלל': הצעות ההשלמה רונדרו ב-Popover של Radix שגזל את הפוקוס מתיבת הקלט ברגע שנפתח, כך שלא ניתן היה להקליד טקסט חופשי. הוחלף ברשימת הצעות פשוטה שאינה גוזלת פוקוס, מסוננת לפי מה שהוקלד (אם אין התאמה — אין הצעות), ובחירת הצעה מתבצעת ב-onMouseDown כדי לא להתבטל מול ה-blur. בנוסף, אזהרת 'חל על תאריך בעבר' לא תוצג עוד כשנבחר היום (השוואה מול תחילת היום במקום מול הרגע הנוכחי).
יוני 2026
v01.156.001תיקוןמשלוחים / תמחור ורווחיותתיקון: עלות מסירה של משלוח שנמסר ע"י סאב-שליח חושבה 0 במקום לפי מחירון המנהל
עלות המסירה/איסוף הפר-משלוח (כרטיסיית תמחור ורווחיות) תומחרה לפי מבצע הביקור בפועל.
פרטים נוספים ↓הסתר ↑
עלות המסירה/איסוף הפר-משלוח (כרטיסיית תמחור ורווחיות) תומחרה לפי מבצע הביקור בפועל. כשהמבצע היה סאב-שליח ללא מחירון משלו, העלות יצאה 0 — למרות שה-tenant משלם בפועל למנהל שמעליו (managedByDriverId), שיש לו מחירון. כעת העלות מתומחרת לפי 'שליח החיוב' = managedByDriverId ?? driverId, בדיוק כמו דו"ח התשלום החודשי tenant→manager (computeManagerTenantEarnings) — כך שה-snapshot הפר-משלוח שווה למה שה-tenant באמת משלם. תוקנו כל מסלולי החישוב: recomputeCostsForDriverDay (קיבוץ ותמחור לפי המנהל + טעינת ביקורי הסאבים שלו באותו OR של הדו"ח החודשי), recomputeCostsForShipment (קיבוץ לפי managedByDriverId ?? driverId), recomputeCostsForDriver (עריכת מחירון מנהל מרעננת גם את המשלוחים שהסאבים שלו מסרו), והצפי (projectAssignedLeg מתמחר אף הוא לפי המנהל). בוצע באקפיל לחודשיים אחורה: 7,222 משלוחים שנמסרו ע"י סאבים בחלון עודכנו לעלות הנכונה (0 נותרו שגויים).
v01.156.000חדשאנליטיקס / רווחיות לקוחותminorרווחיות לקוח → דוח רווח-והפסד (P&L) חודשי מלא: הכנסות מול כל העלויות
עד היום מסך הרווחיות (בכרטיס הלקוח ובטבלת האנליטיקס) הציג רק 'שולי שילוח' — הכנסת השילוח פחות עלות הנהג — על פני טווח תאריכים חופשי.
פרטים נוספים ↓הסתר ↑
עד היום מסך הרווחיות (בכרטיס הלקוח ובטבלת האנליטיקס) הציג רק 'שולי שילוח' — הכנסת השילוח פחות עלות הנהג — על פני טווח תאריכים חופשי. זו הייתה תמונה חלקית: היא התעלמה מהכנסות מחסן/לוגיסטיקה, מעמלות הסוכן ומזיכויים שניתנו ללקוח, ולכן הרווח שהוצג היה מנופח כלפי מעלה. כעת המסך מציג דוח רווח-והפסד מלא ברמת הלקוח, פר חודש קלנדרי: ההכנסה מצרפת את הכנסת השילוח (מנוע התמחור הקיים) עם חיובי המחסן/3PL (WhBillingEvent — אחסון/ליקוט/קליטה); העלות מצרפת את עלות הנהגים/קבלנים (snapshot של תשלום השליח — קבלן מוגדר כשליח עם מחירון), עמלת הסוכן המיוחסת ללקוח (ממנוע computeAgentEarnings), ותעודות זיכוי מאושרות שיוחסו לחודש (שבר/אובדן/איחור/פיצוי). הרווח הנטו נגזר ביניהם. בסיס התאריך הוא חודש קלנדרי בזמן ישראל, וההכרה בהכנסת השילוח עברה ל-commissionableAt (תאריך החיוב) כדי להתיישר בדיוק עם אופן ההכרה בעמלת הסוכן — כך שכל שורות ה-P&L מתייחסות לאותה תקופה. בכרטיס הלקוח נוסף ניווט חודשי (חיצים) ופירוט מלא של שורות ההכנסה והעלות, ולמשלוחים פתוחים שטרם תומחרו סופית מוצג אומדן עלות (כדי שהרווח לא ינופח באפס עלות). בטבלת 'רווחיות לפי לקוח' באנליטיקס נוסף טור 'רווח נטו', שורת פירוט נפתחת לכל לקוח (שילוח/מחסן מול נהגים/סוכן/זיכויים), ובורר חודש עצמאי. עלויות סוכן שאינן ניתנות לייחוס ללקוח בודד (בונוס חודשי כללי, התאמות חד-פעמיות) מושמטות מה-P&L הפר-לקוח ונשארות עלות ברמת הטננט. כל המסך נותר מאחורי הרשאת FINANCE_VIEW.
- מעבר מ'שולי שילוח' ל-P&L מלא: הכנסת שילוח + מחסן/3PL מול עלות נהגים/קבלנים + עמלת סוכן + זיכויים מאושרים
- בסיס חודש קלנדרי (זמן ישראל); הכרה בהכנסה לפי commissionableAt — מיושר עם דוח עמלות הסוכן
- כרטיס הלקוח: ניווט חודשי + פירוט מלא של ההכנסות והעלויות, כולל אומדן עלות למשלוחים פתוחים
- טבלת 'רווחיות לפי לקוח': טור 'רווח נטו' + שורת פירוט נפתחת לכל לקוח, עם בורר חודש עצמאי
- עלויות סוכן שאינן ניתנות לייחוס ללקוח (בונוס/התאמה כללית) מושמטות מה-P&L הפר-לקוח
- הכל מאחורי הרשאת FINANCE_VIEW
v01.155.000חדשמשלוחים / תמחור ורווחיותminorעלות ורווח צפויים בכרטיסיית תמחור ורווחיות — עוד לפני המסירה
עד היום עלות האיסוף/מסירה בכרטיסיית 'תמחור ורווחיות' חושבה ונשמרה רק לאחר שהביקור סומן כ'בוצע' — כך שמשלוח שכבר הוקצה לקבלן עם מחירון, אך טרם נמסר, הציג עלות מסירה 0 ורווח חסר, למרות שהעלות ידועה מראש.
פרטים נוספים ↓הסתר ↑
עד היום עלות האיסוף/מסירה בכרטיסיית 'תמחור ורווחיות' חושבה ונשמרה רק לאחר שהביקור סומן כ'בוצע' — כך שמשלוח שכבר הוקצה לקבלן עם מחירון, אך טרם נמסר, הציג עלות מסירה 0 ורווח חסר, למרות שהעלות ידועה מראש. כעת, כשביקור איסוף/מסירה משויך לשליח בעל מחירון אך עדיין לא הושלם, המערכת מחשבת 'עלות צפויה' באמצעות אותו מנוע חישוב בדיוק (computeEarningsLines) שמייצר את העלות הסופית — כך שהצפי זהה למה שייקבע בפועל עם השלמת המסירה. השורה מסומנת בתג 'צפי', וגם סך העלות, הרווח ושולי הרווח מחושבים לפי הצפי ומסומנים בהתאם. הצפי מוצג רק כשיש מחירון לשליח; ביקור שטרם שויך, או שליח ללא מחירון, ממשיכים להציג '—'. בנוסף, כשעדיין לא שובץ אף שליח למסירה — המערכת נותנת 'צפי משוער' לעלות המסירה לפי השליחים המורשים לאזור ההפצה (DriverAllowedZone): לוקחת את כל השליחים הפעילים עם מחירון שמורשים מפורשות לאזור (התאמה מדויקת או לפי מספר-אזור-בסיס), ומציגה לחומרא את המחיר הגבוה מביניהם. ברגע ששובץ שליח בפועל (גם הזול מבין המורשים) — הצפי מתעדכן מיד לערך המדויק שלו, והצפי-המשוער-לפי-אזור נדחה. הצפי המשוער מסומן בתג 'צפי משוער' (להבדיל מ'צפי' המדויק) עם הסבר ב-tooltip על מספר השליחים המורשים והאזור. גם כששובץ שליח שאין לו מחירון כלל — במקום להציג '—', המערכת נופלת לצפי המשוער לפי האזור, ומציינת ב-tooltip ובשורה ששם השליח המשובץ ללא מחירון (כך שגם רואים את הצפי וגם מקבלים חיווי לתקן את מחירון השליח).
- עלות מסירה/איסוף צפויה מוצגת מרגע שיוך השליח, לא רק אחרי השלמת הביקור
- הצפי מחושב במנוע התשלומים הקיים → זהה לעלות הסופית (למעט קיבוץ איסוף-עסקי שמתגבש על פני יום שלם)
- כשאין שליח משובץ — צפי משוער לעלות המסירה לפי השליחים המורשים לאזור (לחומרא: המחיר הגבוה), שמתעדכן לערך מדויק ברגע השיבוץ
- תג 'צפי' (מדויק, שליח משובץ) מול 'צפי משוער' (לפי אזור) — על שורת העלות, סך העלות והרווח
- שובץ שליח ללא מחירון? נופלים לצפי המשוער לפי האזור (במקום '—') + חיווי שלשליח אין מחירון
- אין שליח מורשה לאזור עם מחירון — לא מוצג צפי שגוי (נשאר '—')
v01.154.003תיקוןמשלוחים / ייצוא אקסלתיקון: עמודת הסטטוס בייצוא האקסל הופיעה באנגלית + עמודת סטטוס תפעולי
בהורדה לאקסל מטבלת מעקב המשלוחים הראשית, עמודת הסטטוס יוצאה בערך הגולמי באנגלית (COMPLETED, FAILED וכו') במקום בתווית העברית שמוצגת בטבלה.
פרטים נוספים ↓הסתר ↑
בהורדה לאקסל מטבלת מעקב המשלוחים הראשית, עמודת הסטטוס יוצאה בערך הגולמי באנגלית (COMPLETED, FAILED וכו') במקום בתווית העברית שמוצגת בטבלה. כעת הערך מתורגם לעברית ("הושלם", "נכשל", "יצא להפצה"…) דרך getStatusDisplayText — אותו מיפוי שמזין את תגי הסטטוס במסך — כך שהקובץ תואם למוצג. תיקון זה גם מיישר את פילטר-הטקסט של עמודת הסטטוס: חיפוש לפי טקסט עברי בעמודה תואם כעת לערך המוצג. בנוסף נוספה עמודה חדשה "סטטוס תפעולי" (מוסתרת כברירת מחדל, ניתנת להפעלה מתפריט העמודות) — הסטטוס המשני המוגדר פר-חברה שמוצג כתגית נוספת לצד הסטטוס הראשי בטבלה, וכעת זמין גם בייצוא ובפילטר-הטקסט, כשהוא מתורגם משם-המפתח לתווית העברית המוגדרת.
v01.154.002תיקוןמשלוחים / פורטל לקוחות / חיפוש רחובותתיקון: רשימת רחובות לא נטענת לאחר בחירת עיר
בטופס יצירת משלוח חדש (גם בממשק הצוות וגם בפורטל הלקוחות) רשימת הרחובות הופיעה ריקה עבור ערים ששמן ב-data.gov.il שונה במעט מהשם אצלנו — בעיקר תל אביב, שאצלנו "תל אביב יפו" ובמאגר הממשלתי "תל אביב - יפו" (עם מקף).
פרטים נוספים ↓הסתר ↑
בטופס יצירת משלוח חדש (גם בממשק הצוות וגם בפורטל הלקוחות) רשימת הרחובות הופיעה ריקה עבור ערים ששמן ב-data.gov.il שונה במעט מהשם אצלנו — בעיקר תל אביב, שאצלנו "תל אביב יפו" ובמאגר הממשלתי "תל אביב - יפו" (עם מקף). הסינון הקודם דרש התאמה מדויקת של שם הישוב ולכן החזיר 0 רחובות. כעת החיפוש מבוצע כ-full-text ממוקד-שדה על שם הישוב (שמגשר על הבדלי מקף/רווחים), והתוצאות מסוננות לפי השוואה מנורמלת של שם הישוב — כך שעיר עם שם-על כמו "גן יבנה" לא נכנסת בטעות לחיפוש על "יבנה". בנוסף, שם העיר נפתר תחילה דרך resolveSettlement (אותו מנגנון שמות חלופיים של ייבוא האקסל) לשם הקנוני — כך שעיר שנשמרה כשם חלופי ("נצרת עילית" → "נוף הגליל", "ת\"א" וכו'), בין אם מילוי-אוטומטי מכתובת לקוח/כתובת שמורה ובין אם ממשלוח ישן, עדיין מוצאת את רחובותיה. הוסר גם תקרת ה-3000 שחתכה ערים גדולות (ירושלים — ~4,400 רחובות). הלוגיקה רוכזה ב-lib/streets/gov-streets.ts המשותף לשני ה-endpoints. בנוסף, בבורר העיר — כשהחיפוש תואם שם חלופי ולא את השם הרשמי — מוצגת מתחת לשם תווית קטנה ומעומעמת "נקרא גם \"…\"", כך שמשתמש שמחפש "נצרת עילית" מבין מיד שעליו לבחור ב"נוף הגליל".
v01.154.001תיקוןפורטל לקוחות / סנכרון ליונוויל / היסטוריית פעולותתיקון אובדן עדכון מספר חבילות בעריכה מהפורטל
תוקן באג שגרם לאובדן שקט של שינוי מספר חבילות: עריכת פרטי משלוח דרך פורטל הלקוחות (מספר חבילות, משקל, כתובת) לא סונכרנה כלל לליונוויל, ובמקביל כל webhook סטטוס מליונוויל דרס את הערך המקומי בערך המקורי שלו — כך שלקוח ששינ…
פרטים נוספים ↓הסתר ↑
תוקן באג שגרם לאובדן שקט של שינוי מספר חבילות: עריכת פרטי משלוח דרך פורטל הלקוחות (מספר חבילות, משקל, כתובת) לא סונכרנה כלל לליונוויל, ובמקביל כל webhook סטטוס מליונוויל דרס את הערך המקומי בערך המקורי שלו — כך שלקוח ששינה 1→2 והדפיס מדבקות ראה את המשלוח חוזר ל-1, בעוד הקבלן קיבל שתי מדבקות. כעת: (1) עריכה בפורטל מסתנכרנת לליונוויל מיד, כמו במסך העריכה של הצוות; (2) webhook מעדכן מספר חבילות מקומית רק כשליונוויל באמת שינה אותו מול ה-snapshot הקודם — כך שעריכה מקומית שטרם הסתנכרנה אינה נדרסת, אך שינוי אמיתי שבוצע בליונוויל עדיין מסתנכרן אלינו ב-webhook הקרוב; (3) עריכות והדפסות מדבקה מהפורטל נרשמות כעת כראוי ביומן הפעולות — תוקנה הפרת מפתח-זר (FK) שבלעה בשקט את רישום ההדפסה (מזהה משתמש-פורטל נכתב לעמודה שמצביעה על טבלת משתמשי הצוות).
v01.154.000חדשמשלוחים / היסטוריית פעולות / פורטל לקוחותminorתיעוד יוצר המשלוח — מי פתח את המשלוח
כל משלוח חדש מתעד מעתה מי יצר אותו: משתמש פורטל הלקוחות (לפי שם) או משתמש צוות.
פרטים נוספים ↓הסתר ↑
כל משלוח חדש מתעד מעתה מי יצר אותו: משתמש פורטל הלקוחות (לפי שם) או משתמש צוות. עד כה משלוחים שנוצרו דרך פורטל הלקוחות יוחסו ב-audit ל-"Lionwheel" (כי רישום היצירה הגיע מה-webhook של הסנכרון), והיוצר האמיתי לא נשמר בשום מקום. כעת היוצר נשמר על שורת המשלוח ומוצג בשני מקומות: בהיסטוריית הפעולות בדף המשלוח (צד צוות) — שורת "יצירה" מציגה "פורטל לקוחות · <שם המשתמש>" במקום Lionwheel; ובפורטל הלקוחות עצמו — שורת "נוצר ע״י" בכותרת פרטי המשלוח. נוסף actorType חדש 'customer' למערכת ה-audit, המדורג מעל ה-webhook כדי שסנכרון ליונוויל המאוחר לא ידרוס את ייחוס היוצר.
- שדות חדשים על המשלוח: created_by_user_id / created_by_name / created_by_type
- היסטוריית הפעולות בדף המשלוח מציגה את משתמש הפורטל שיצר ("פורטל לקוחות · <שם>") במקום Lionwheel
- פורטל הלקוחות מציג "נוצר ע״י <שם>" בכותרת פרטי המשלוח ובמגירת התצוגה המהירה
- actorType='customer' חדש ב-audit, מדורג מעל webhook כדי שהסנכרון לא ידרוס את היוצר
- הייחוס נשמר גם למשלוחי צוות (createdByType='user'); משלוחים ישנים / ייבוא מחנות נשארים ללא ייחוס
v01.153.000חדשאינטגרציות / WooCommerceminorWooCommerce — ייבוא הזמנות מסונן לפי שיטת משלוח
חנות WooCommerce שמציעה כמה שיטות משלוח (למשל משלוח רגיל שיוצא איתנו, אקספרס שיוצא עם מוביל אחר, ונקודות איסוף) — ניתן כעת להגדיר אילו שיטות בלבד ייובאו לשיפנסט.
פרטים נוספים ↓הסתר ↑
חנות WooCommerce שמציעה כמה שיטות משלוח (למשל משלוח רגיל שיוצא איתנו, אקספרס שיוצא עם מוביל אחר, ונקודות איסוף) — ניתן כעת להגדיר אילו שיטות בלבד ייובאו לשיפנסט. רשימת-היתר נשמרת לכל חיבור חנות; הזמנה ששיטת המשלוח שלה אינה ברשימה לא נמשכת ולא משוגרת ל-Lionwheel. הסינון חל גם על ה-webhook בזמן אמת וגם על סנכרון ה-cron כל 5 דקות. בטופס חיבור החנות בפורטל נוסף בורר שטוען את שיטות המשלוח ישירות מהחנות (מאזורי המשלוח + הזמנות אחרונות) ופאנל אימות שמראה מה נשלף מהזמנות אמיתיות — כדי לוודא שהשיטה אכן נמצאת בשדה התקני (shipping_lines) ולא מוסתרת ב-meta של תוסף צד-שלישי כמו Datalogics. בנוסף נוסף בורר 'מתי לייבא הזמנה' לכל חיבור: אוטומטי (מיד עם התשלום) או 'רק כשמסומנת הושלמה' — מצב ידני לחנויות שמכינות את המוצר לפני המשלוח (חריטה/אריזה), כך שהמשלוח נוצר ונשלח רק כשהצוות מסמן את ההזמנה Completed.
- רשימת-היתר של שיטות משלוח לכל חיבור חנות — ברירת מחדל: ייבוא כל השיטות (תאימות לאחור)
- בורר שיטות שטוען אוטומטית מהחנות (Shipping Zones + הזמנות אחרונות)
- פאנל אימות PII-safe: shipping_lines + שמות מפתחות meta של הזמנות אחרונות (ערכים לא נחשפים)
- fail-safe: הזמנה עם רשימת-היתר מוגדרת אך ללא שיטת משלוח כלל — לא מיובאת
- הסינון חל בצומת המשותף לשני המסלולים (webhook בזמן אמת + cron כל 5 דקות)
- בורר 'מתי לייבא הזמנה': אוטומטי (processing/on-hold) או ידני — רק כשההזמנה מסומנת 'הושלמה' (completed), לחנויות שמכינות את המוצר לפני המשלוח
v01.152.000חדשפורטל שליחיםminorאזור אישי לשליחים — דוח יומי/שבועי/חודשי + עיצוב מחדש עשיר במידע
האזור האישי של השליחים (פורטל מנהלי השליחים) עוצב מחדש כדשבורד עשיר.
פרטים נוספים ↓הסתר ↑
האזור האישי של השליחים (פורטל מנהלי השליחים) עוצב מחדש כדשבורד עשיר. נוסף מתג יום / שבוע / חודש בראש המסך, עם ניווט מתאים לכל מצב (יום ספציפי, טווח שבוע, או חודש) — קודם לכן היה דוח חודשי בלבד. כל הנתונים נשלפים מטווח התאריכים החופשי שכבר נתמך ב-API, ללא שינוי לוגיקת חישוב או DB. הקיבוץ היומי מחושב בצד הלקוח לפי שעון ישראל, בהתאמה למתמטיקת השרת.
- מתג יום / שבוע / חודש עם ניווט מתאים וכפתור 'הבא' שמושבת בתקופה הנוכחית
- גרף עמודות של הכנסה יומית (בתצוגת שבוע/חודש) — לחיצה על יום מציגה את הסכום ומספר הביקורים שלו
- תג השוואה לתקופה הקודמת (▲/▼ אחוז) על כרטיס 'סה״כ לתשלום'
- ממוצע הכנסה ליום פעיל, היום החזק ביותר, ומספר ימי העבודה בתקופה
- סך כל החבילות שטופלו מוצג לצד מספר הביקורים
- תיקון: בכרטיס השליחים מוצג שם השליח (כולל המנהל עצמו ושליחים שקישורם הפך ללא-פעיל) במקום מזהה מספרי; שורת המנהל מסומנת '(אני)'
- פס הפקדים (יום/שבוע/חודש + ניווט תאריך) הפך דביק בראש המסך — אפשר להחליף תקופה ולדפדף בין תאריכים מכל מיקום גלילה בלי לחזור למעלה
- תיקון פריסת דסקטופ: התוכן ממורכז במרכז המסך (קודם נצמד לימין), והבורדר העליון רוכך לקו עדין עם רקע מטושטש
v01.151.004חדשצ'אט לקוחות עסקייםצ'אט עסקי — הצמדת שיחה לראש הרשימה (Pin)
בתפריט הלחיצה-ימנית על שיחה נוספו 'הצמד' / 'בטל הצמדה'.
פרטים נוספים ↓הסתר ↑
בתפריט הלחיצה-ימנית על שיחה נוספו 'הצמד' / 'בטל הצמדה'. שיחות מוצמדות צפות לראש רשימת השיחות (המוצמדת-אחרונה ראשונה), מעל שאר השיחות הממוינות לפי פעילות, ומסומנות באייקון נעץ קטן. עובד גם בחיפוש וגם בגלילה האינסופית (המוצמדות נשלפות בנפרד בעמוד הראשון כדי שתמיד יישבו למעלה, ללא תלות בזמן הפעילות).
v01.151.003שיפורבוט תרחישים / גישור צפישאלת צפי על משלוח שנמסר — הבוט סוגר את הלולאה ומודיע ללקוח 'נמסר'
שני תיקונים משלימים לגישור-הצפי, בעקבות תקרית 25640198.
פרטים נוספים ↓הסתר ↑
שני תיקונים משלימים לגישור-הצפי, בעקבות תקרית 25640198. (1) אם המשלוח כבר נמסר ברגע שהלקוח שואל — הבוט עונה ישירות 'המשלוח כבר נמסר ✓' מנתוני המסירה שלנו, במקום לשאול את השליח לחינם (סטטוס סופי אחר כמו נכשל/בוטל → שתיקה, נציג מטפל). (2) אם המשלוח נמסר *תוך כדי* שהבוט ממתין לתשובת השליח: במקרה 25640198 המשלוח נמסר כ-12 דקות אחרי שקקאו שאלו צפי — ליונוויל עדכן COMPLETED, ואז cron הנדנוד ביטל את הגישור בשקט, כך שקקאו לא קיבלו כל תשובה (וגם תשובת הקבלן זיפ בציטוט 'זה כבר בוצע' נפלה על גישור מבוטל). כעת כשהנדנוד סוגר גישור-צפי בגלל מסירה בפועל, הוא מודיע ללקוח 'נמסר ✓' (תבנית delivered_to_customer הניתנת לעריכה) — סוגר את הלולאה גם בלי תשובת השליח.
v01.151.002חדשצ'אט לקוחות עסקייםצ'אט עסקי — סימון שיחה כנקראה / כלא-נקראה מתפריט הלחיצה-ימנית
בתפריט הלחיצה-ימנית על שיחה ברשימה נוספו 'סמן כנקרא' ו'סמן כלא נקרא' (בנוסף ל'העבר לארכיון' הקיים).
פרטים נוספים ↓הסתר ↑
בתפריט הלחיצה-ימנית על שיחה ברשימה נוספו 'סמן כנקרא' ו'סמן כלא נקרא' (בנוסף ל'העבר לארכיון' הקיים). 'סמן כנקרא' מנקה את תג הלא-נקראו ושולח ✓✓ כחול ללקוח (ReadChat). 'סמן כלא נקרא' מסמן ידנית בסגנון וואטסאפ — האינדיקטור נשאר דלוק גם בלי הודעות נכנסות חדשות, ומוצג כנקודה ירוקה כשאין מונה. שני הסימונים מתנקים אוטומטית כשפותחים את השיחה.
v01.151.001תיקוןבוט תרחישים / יידוע טיפולבוט תרחישים — 'מברר/בודק' נשלח רק כשהשאלה לצד השני באמת נמסרה
תיקון לפיצ'ר ה'בודק': עד כה הבוט רשם 'מברר מול הלקוח...
פרטים נוספים ↓הסתר ↑
תיקון לפיצ'ר ה'בודק': עד כה הבוט רשם 'מברר מול הלקוח... אעדכן בהקדם' ברגע ש-Green API החזיר 200 על השאלה שנשלחה ללקוח/שליח. אבל 200 אומר רק שהבקשה התקבלה לתור — לא שההודעה נמסרה. במקרה אמיתי (משלוח 25739886) השאלה ללקוח 'כביסכל' נשמטה בשקט (Green API החזיר מזהה אך לא הגיע webhook מסירה כלל, ההודעה לא נרשמה ב-inbox של הלקוח, וה-relay נשאר PENDING) — אך הבוט כבר הבטיח 'מברר', ובן-אדם נאלץ להתערב ידנית. כעת ה-ack נשמר כ'ממתין' על ה-relay ונשלח לקבוצת המקור רק כשמסירת השאלה מאומתת דרך webhook סטטוס המסירה (sent/delivered/read); אם המסירה נכשלת (notInGroup/noAccount/failed) או שלא מגיע סטטוס כלל — ה'מברר' לא נשלח בכלל. כך ההודעה 'מברר/בודק' מופיעה אך ורק כשהבוט באמת פנה לצד השני בהצלחה.
v01.151.000חדשצ'אט לקוחות עסקייםminorצ'אט עסקי — גל פיצ'רים בסגנון וואטסאפ: נקראו/לא-נקראו, העברה·מחיקה·עריכה, ריאקציות, חיווי הקלדה
המשך הבאת ה-Business Inbox לפריטי וואטסאפ.
פרטים נוספים ↓הסתר ↑
המשך הבאת ה-Business Inbox לפריטי וואטסאפ. (1) קריאה: פתיחת צ'אט מסמנת אותו כנקרא ושולחת ✓✓ כחול ללקוח (Green API ReadChat), ותג מונה 'לא נקראו' ירוק מופיע ברשימת השיחות, עם הדגשת שיחות שיש בהן הודעות נכנסות חדשות. (2) פעולות על הודעה (תפריט בלחיצה-ימנית בדסקטופ / לחיצה-ארוכה במובייל): העברה לצ'אט אחר (ForwardMessages, עם בורר צ'אט מחופש), מחיקה לכולם (DeleteMessage — מוצגת כ'ההודעה נמחקה'), עריכת טקסט שנשלח (EditMessage — מקבל תג 'נערך'), והעתקה. (3) ריאקציות נכנסות מוצגות כצ'יפים על הבועה (שמות המגיבים ב-hover). (4) חיווי 'מקליד…' ללקוח בזמן שהנציג כותב (sendTyping, מווסת לכ-פעם ב-3.5 שניות). הכל נשען על תשתית ה-externalId שכבר נשמרת לכל הודעה. מגבלת ספק: שליחת ריאקציה מאיתנו אינה נתמכת ב-Green API — לכן רק הצגת ריאקציות נכנסות.
- קריאה: סימון נקרא בפתיחה + ✓✓ כחול ללקוח, ותג 'לא נקראו' ברשימה
- העברת הודעה לצ'אט אחר (בורר צ'אט עם חיפוש)
- מחיקה לכולם → מוצגת כ'ההודעה נמחקה'
- עריכת הודעה שנשלחה → תג 'נערך' (בכפוף לחלון הזמן של וואטסאפ)
- העתקת תוכן הודעה מהתפריט
- ריאקציות נכנסות מוצגות כצ'יפים (שמות המגיבים ב-hover)
- חיווי 'מקליד…' ללקוח בזמן הקלדה
- מגבלה: שליחת ריאקציה מאיתנו אינה נתמכת ב-Green API (רק הצגה)
v01.150.000חדשצ'אט לקוחות עסקייםminorצ'אט עסקי — מענה בציטוט (reply) להודעות, בסגנון וואטסאפ
נציגי השירות יכולים כעת להשיב מתוך ה-Business Inbox תוך ציטוט הודעה ספציפית — בדיוק כמו בוואטסאפ.
פרטים נוספים ↓הסתר ↑
נציגי השירות יכולים כעת להשיב מתוך ה-Business Inbox תוך ציטוט הודעה ספציפית — בדיוק כמו בוואטסאפ. במובייל מחליקים (סווייפ) על ההודעה, ובדסקטופ לוחצים על אייקון ↩ שמופיע בריחוף; נפתח סרגל 'משיב ל...' מעל תיבת הכתיבה (ביטול ב-X או ב-Esc), וההודעה נשלחת כ-quoted reply אמיתי דרך Green API — אותו מנגנון שהבוט כבר משתמש בו בתרחישים. בלוק הציטוט מוצג בראש הבועה, ולחיצה עליו קופצת להודעה המקורית ומדגישה אותה לרגע. דו-כיווני: גם כשלקוח/קבלן מצטט הודעה בוואטסאפ, הציטוט מוצג עכשיו באינבוקס (זוהה מ-quotedMessage.stanzaId וקושר להודעה אצלנו לפי externalId). נשען על התשתית הקיימת: כל הודעה כבר שומרת את ה-idMessage של Green API, ולכן לא נדרש backfill.
- סווייפ על הודעה במובייל / אייקון ↩ בריחוף בדסקטופ → מענה מצוטט
- סרגל 'משיב ל...' מעל ההקלדה, עם ביטול מהיר (X או Esc)
- בלוק ציטוט בראש הבועה; לחיצה קופצת להודעה המקורית ומדגישה אותה
- דו-כיווני — גם ציטוטים נכנסים מלקוח/קבלן מוצגים באינבוקס (טקסט ומדיה)
- נשלח כ-quoted reply אמיתי דרך Green API
v01.149.010שיפורבוט תרחישים / גישורהקשחת גישור תשובות — שמירת התשובה ב-inbox + מניעת שיוך למשלוח שגוי
שני שיפורים בעקבות תקרית 25691571.
פרטים נוספים ↓הסתר ↑
שני שיפורים בעקבות תקרית 25691571. (1) כשהבוט קולט הודעה כתשובה לתרחיש גישור פתוח (relay) ומעביר אותה חזרה — ההודעה הנקלטת נשמרת כעת ב-inbox כך שהצוות רואה אותה. עד כה הנתיב הזה היה מחזיר לפני השמירה, ולכן ההודעה שעליה הבוט הגיב (למשל תמונת הקבלן 'הלקוח לא מעוניין לקבל') לא הופיעה בשיחה כלל — מה שיצר מצב הזוי שבו הבוט 'רואה' הודעה שהנציגים לא רואים. (2) אם תשובת הגישור מזכירה במפורש מספר משלוח אמיתי *אחר* מזה של ה-relay הפתוח — הבוט כבר לא משייך אותה אוטומטית, אלא משאיר את ה-relay פתוח ושותק (במקום לגשר תשובה על משלוח שגוי). חריג: תשובה שמצטטת ישירות את שאלת הבוט (quoted reply) ממשיכה כרגיל, כי הציטוט הוא איתות כוונה חד-משמעי.
v01.149.009שיפורצוות / זיהוי שולח בוואטסאפזיהוי איש צוות גם מהטלפון השני שלו (טלפונים נוספים למשתמש)
כעת אפשר להגדיר למשתמש 'טלפונים נוספים' (מכשיר שני) בטופס עריכת המשתמש, והמערכת תזהה הודעות שהוא כותב בקבוצות הוואטסאפ כצוות — גם כשהן נשלחות מהמספר המשני.
פרטים נוספים ↓הסתר ↑
כעת אפשר להגדיר למשתמש 'טלפונים נוספים' (מכשיר שני) בטופס עריכת המשתמש, והמערכת תזהה הודעות שהוא כותב בקבוצות הוואטסאפ כצוות — גם כשהן נשלחות מהמספר המשני. רקע: איש צוות ענה בקבוצת לקוח מהטלפון השני שלו 'הלקוח לא מעוניין לקבל', והבוט לא זיהה אותו כצוות (מפת הצוות הכירה רק טלפון יחיד לכל משתמש) — לכן קלט את ההודעה כתשובת-הלקוח לתרחיש 'אין מענה' פתוח, וגישר אותה בטעות חזרה לקבוצה אחרת על משלוח שגוי. כעת getTenantStaffPhoneMap ממפה את הטלפון הראשי ואת כל הטלפונים הנוספים לאותו משתמש, כך שמחסום 'תשובת צוות אינה תשובת הלקוח' תופס משני המספרים. נוסף שדה additionalPhones ל-User (גלובלי), נתמך ביצירה/עריכה דרך /api/users.
v01.149.008שיפורתיבת שיחות עסקית / חיווי מסירהתיבת השיחות העסקית — חיווי מסירה ברור (שולח · ממתין למסירה · נמסר · נקרא)
שיפור חיווי הסטטוס של הודעות יוצאות בתיבת השיחות (business-inbox), כדי שהודעה שנמצאת בתור המסירה של Green API לא תיראה כאילו 'לא נשלחה'.
פרטים נוספים ↓הסתר ↑
שיפור חיווי הסטטוס של הודעות יוצאות בתיבת השיחות (business-inbox), כדי שהודעה שנמצאת בתור המסירה של Green API לא תיראה כאילו 'לא נשלחה'. עד כה הודעה בזמן שליחה (אופטימית) הוצגה ללא שום אייקון — bubble ריק שנקרא כ'נכשל', והאייקון ✓ הבודד ('נשלח') לא הובהר. כעת לכל הודעה יוצאת יש מצב ברור עם tooltip: 'שולח…' (ספינר בזמן שהבקשה בדרך), '✓ נשלח · ממתין למסירה' (Green API קיבל, ממתין בתור), '✓✓ נמסר', '✓✓ נקרא' (כחול), ו'⚠ נכשל — ההודעה לא נמסרה'. ההודעה האופטימית מתחילה כעת כ'שולח…' במקום bubble חסר-חיווי. רקע: שליחה ידנית לקבוצה שאינה מקושרת ללקוח נראתה למשתמש כ'לא נשלחה' למרות שבפועל הצליחה ונקראה — העיכוב היה בתור המסירה של Green API, לא אצלנו.
v01.149.007תיקוןתשתית UI / dropdown במודאליםתיקון גלילה ב-dropdown בתוך חלונות מודאליים (שיוך שליח + מקומות נוספים)
תוקנו שלוש בעיות במודל 'שיוך שליח' שנפתח מסרגל הפעולות של בחירה מרובה בדף המשלוחים: (1) הלייבל הציג 'נהג' במקום 'שליח' — אוחדה הטרמינולוגיה ל'שליח' בכל המודל (כותרת, לייבל, הודעות).
פרטים נוספים ↓הסתר ↑
תוקנו שלוש בעיות במודל 'שיוך שליח' שנפתח מסרגל הפעולות של בחירה מרובה בדף המשלוחים: (1) הלייבל הציג 'נהג' במקום 'שליח' — אוחדה הטרמינולוגיה ל'שליח' בכל המודל (כותרת, לייבל, הודעות). (2) רשימת השליחים לא נתנה לגלול — הרשימה רונדרה כ-dropdown מרחף (portal) שנחת מחוץ ל-scroll-lock של הדיאלוג ולכן אירועי גלילה נחסמו; הוחלפה ברשימה inline נגללת בתוך גוף הדיאלוג. (3) החיפוש לא היה יעיל — מכיוון שרוב השליחים נושאים את שם החברה (למשל 'שליח מישל') בשם התצוגה, חיפוש 'מישל' הציף עשרות שמות והקבר את השליח ששמו מישל; נוסף דירוג רלוונטיות שמקדים התאמה מדויקת → מילה ראשונה → מילה שלמה → תחילית, כך שהשליח המבוקש מופיע ראשון. בנוסף בוצעה סריקה של כל האפליקציה לאיתור אותו באג (dropdown נגלל-נייטיב שמרונדר ב-portal בתוך חלון נועל-גלילה) ותוקנו כל המופעים החיים: בחירת שליח בכרטיס המשימות (TasksCard) כשהוא נפתח במגירת פרטי-המשלוח, ובוררי אזורים/תבניות מבוססי Command בתוך טפסים מודאליים (טופס נהג, טופס יישוב, ובורר תבניות WhatsApp). תיקון עיצובי קטן: נוסף ריווח אופקי לאזור התוכן הגולל במודל 'שיוך שליח' כדי שטבעת הפוקוס סביב שדה החיפוש לא תיחתך בקצוות (overflow-y-auto חותך את ציר ה-X). בעקבות כך בוצעה סריקה נוספת בכל האפליקציה לאיתור אותה בעיית-חיתוך-טבעת, ותוקנו כל המודלים שבהם שדה-קלט/בחירה ברוחב-מלא יושב באזור גולל ללא ריווח אופקי: דיאלוגי האינטגרציות (חיבור כללי, חברת משלוחים, הנהלת חשבונות), תמחור מרובה (לקוחות + נהגים), ייבוא לידים, החלת-מנהל-רטרו לנהג, יצירת מפתח API בפורטל וניהול תוויות. עוטף-התוכן בקונבנציית-הדיאלוג ב-CLAUDE.md עודכן לכלול px-1 כדי שדיאלוגים עתידיים לא יחזירו את הבאג (ב-FormDialog המשותף זה כבר היה מובנה דרך px-6).
v01.149.006תיקוןבוט תרחישים / שידורבקשת שידור בקבוצת-שליח (לא מקושרת ללקוח) נשמטה לסירוגין
תוקן באג שבו בקשת שידור (למשל צילום מדבקה + 'לשדר') בקבוצה שמקושרת כשליח אך לא כלקוח (כמו קבוצת 'זיפ') לא שודרה — לסירוגין.
פרטים נוספים ↓הסתר ↑
תוקן באג שבו בקשת שידור (למשל צילום מדבקה + 'לשדר') בקבוצה שמקושרת כשליח אך לא כלקוח (כמו קבוצת 'זיפ') לא שודרה — לסירוגין. נתיב השידור רץ ברקע עם debounce של 8 שניות ועטוף ב-after() כדי שוורסל ישאיר את הפונקציה חיה, אבל ה-after() עקב רק אחרי נתיב סוכן-הלקוח. בקבוצה שאינה מקושרת ללקוח, סוכן הלקוח יוצא מיד ('שולח לא מזוהה') ללא ה-debounce — ולכן הפונקציה הוקפאה באמצע ה-sleep של השידור והשידור נשמט בשקט (נרשם רק סיווג 'silent', אף פעם לא החלטת broadcast_request). זה היה לסירוגין כי תעבורה מקבילה לעיתים השאירה את האינסטנס חם מספיק. כעת routeInboundUserMessage ממתין גם לנתיב הקבוצה/שידור (במקביל, ללא תוספת latency), כך שהבטחת ה-after() מכסה אותו והשידור תמיד מסתיים. משפיע על שני המסלולים — טקסט ומדיה.
v01.149.005שיפוראפליקציית שליחים / סורק מחסןאפליקציית שליחים — משוב סריקה עשיר בסורק המחסן (כמו בווב)
הועברה חבילת המשוב מסורק הווב לסורק המחסן באפליקציה (קליטה/מיון): רכיב ScanFeedbackOverlay חדש מציג ברגע זיהוי הברקוד טוסט אפור-ניטרלי עם ספינר ('ממתין לשרת…'), שמתמרמר עם תשובת השרת לטוסט ירוק (הצלחה) / אדום (כישלון) / …
פרטים נוספים ↓הסתר ↑
הועברה חבילת המשוב מסורק הווב לסורק המחסן באפליקציה (קליטה/מיון): רכיב ScanFeedbackOverlay חדש מציג ברגע זיהוי הברקוד טוסט אפור-ניטרלי עם ספינר ('ממתין לשרת…'), שמתמרמר עם תשובת השרת לטוסט ירוק (הצלחה) / אדום (כישלון) / כתום (טעות מיון) עם הודעה מתאימה — 'נקלט בהצלחה' (כולל 'בוטל שיוך ל…' כשהשיוך נוקה), 'שובץ לשליח X', טקסט השגיאה, או הסבר טעות המיון (איזה אזור אינו באזורי הנהג). הטוסטים נערמים ונעלמים אוטומטית, ניתנים לסגירה ידנית, ובמקביל מהבהבת מסגרת צבעונית סביב המצלמה ומופעל רטט (קליק קל בזיהוי, ורטט הצלחה/אזעקה/שגיאה בתוצאה דרך expo-haptics). רשימת ההיסטוריה תחת המצלמה עודכנה לזהות גם טעות מיון (כתום). מימוש pure-JS (Animated + expo-haptics קיים) — ללא תלות נייטיב חדשה, כך שזה מתפרסם כעדכון OTA ללא בנייה מחדש. צליל לא נוסף (דורש expo-av = בנייה נייטיב).
v01.149.004תיקוןאינטגרציות / WooCommerceWooCommerce — הזמנה עם כתובת בפורמט 'מספר, רחוב' נפלה ל'ממתין' במקום להשתדר לליונוויל
הזמנה של GL Glow עם כתובת 'רקפת 10' שנשמרה ב-WooCommerce כ-'10, רקפת' (מספר הבית ראשון) לא שודרה לליונוויל אלא נקלטה כ'ממתין' עם ברקוד סינתטי — ונאלצנו להמתין שליונוויל תקים אותה דרך האינטגרציה שלה.
פרטים נוספים ↓הסתר ↑
הזמנה של GL Glow עם כתובת 'רקפת 10' שנשמרה ב-WooCommerce כ-'10, רקפת' (מספר הבית ראשון) לא שודרה לליונוויל אלא נקלטה כ'ממתין' עם ברקוד סינתטי — ונאלצנו להמתין שליונוויל תקים אותה דרך האינטגרציה שלה. שתי סיבות תוקנו: (1) ה-parser של הכתובת זיהה מספר בית רק בסוף ('הרצל 10') ולא בהתחלה ('10, רקפת'), ולכן נשאר ללא מספר בית; (2) ה-validation של יצירת-המשלוח דרש מספר בית גם בייבוא, בעוד שליונוויל מקבלת כתובת מלאה ללא מספר נפרד. כעת ה-parser מזהה מספר בית בשני הצדדים (כולל פסיק), ובמסלול הייבוא מספר בית חסר כבר לא חוסם שידור. הזמנות חדשות כאלה ישודרו ישירות עם ברקוד אמיתי של ליונוויל.
v01.149.003ייעולביצועים / תשתיתהפחתת עומס: סטרים 'מי מחובר' נסגר לעתים רחוקות + סינון רעש התראות שגיאה
שני ייעולים שמקטינים עומס מיותר על השרת.
פרטים נוספים ↓הסתר ↑
שני ייעולים שמקטינים עומס מיותר על השרת. (1) הסטרים של 'מי מחובר' (presence, /api/users/online/stream) נסגר קודם כל 25 שניות וגרם לכל דפדפן מחובר להתחבר מחדש בערך כל 26 שניות — סופת חיבורים-מחדש ושאילתות DB מיותרות. כעת הוא נשאר פתוח ~4.5 דקות (כמו סטרימי ההתראות/משלוחים/ליקוט), מה שמקטין את כמות החיבורים-מחדש פי ~10. (2) נתיב התראות השגיאה ל-WhatsApp של המנהל ניסה לשלוח הודעה על כל שגיאה גם כשלא הוגדר מספר טלפון מנהל (TEST_PHONE ריק), ונכשל ב-validation עם 'Failed to send error notification: Invalid phone number format' — רעש שקפץ על כל כשל cron חיצוני (konimbo/eshop/woocommerce). כעת אם אין מספר מנהל תקין, ההתראה מדולגת בשקט ללא ניסיון שליחה מבוזבז.
v01.149.002שיפורמחסן / סורק ברקודיםקליטת מחסן משחררת שיוך נהג/קבלן וחוזרת למלאי נקי
כשמשלוח שמשובץ לשליח או משודר לקבלן עובר סריקת 'קליטה במחסן' (כלומר חזר למחסן), המערכת מנקה כעת אוטומטית את השיוך: הנהג מוסר מביקור המסירה (driverId/managedByDriverId/driverAssignedAt מאופסים) ומסומני השידור היוצא (targe…
פרטים נוספים ↓הסתר ↑
כשמשלוח שמשובץ לשליח או משודר לקבלן עובר סריקת 'קליטה במחסן' (כלומר חזר למחסן), המערכת מנקה כעת אוטומטית את השיוך: הנהג מוסר מביקור המסירה (driverId/managedByDriverId/driverAssignedAt מאופסים) ומסומני השידור היוצא (targetPartnerTaskId + snl_broadcast_at/snl_barcode/snl_task_type) נמחקים — כך שהמשלוח חוזר למצב 'נקלט במחסן' נקי וניתן לשדרו/לשבצו מחדש (קודם הגנת ה-idempotency הייתה חוסמת שידור חוזר). במקביל מתעדכן ליונוויל ברקע (after()): הסטטוס נדחף ל'נקלט במחסן', והנהג מוסר מהביקור (driver_id: null) כשיש מזהה ביקור. הסורק מציג בטוסט הקליטה גם את ביטול השיוך (למשל 'בוטל שיוך למשה כהן'). הערה: ההזמנה אצל הקבלן (SNL) עצמה אינה מבוטלת אוטומטית — רק השיוך המקומי וליונוויל מתעדכנים.
v01.149.001תיקוןנוכחות / דיווח משמרותדיווח משמרת רטרואקטיבי — תיקון זיהוי חפיפה שגוי עקב אזור זמן
תוקן באג שבו עובד שדיווח משמרת רטרואקטיבית קיבל בטעות 'קיימת משמרת חופפת בתאריך זה' למרות שלא הייתה חפיפה אמיתית.
פרטים נוספים ↓הסתר ↑
תוקן באג שבו עובד שדיווח משמרת רטרואקטיבית קיבל בטעות 'קיימת משמרת חופפת בתאריך זה' למרות שלא הייתה חפיפה אמיתית. הסיבה: השעות שהוזנו פורשו לפי אזור הזמן של השרת (UTC ב-Vercel) ולא לפי שעון ישראל, כך שדיווח על 09:30–10:30 נשמר בפועל כ-12:30–13:30 והתנגש במשמרת שנרשמה בזמן אמת. כעת התאריך והשעה מתפרשים כשעון ישראל (מודע לשעון קיץ/חורף) דרך helper חדש israelLocalToUtc. בנוסף תוקנה לוגיקת בדיקת החפיפה עצמה לבדיקת-טווחים תקנית אחת (חפיפה אמיתית בלבד, כולל הכלה דו-כיוונית; משמרות צמודות גב-אל-גב כבר לא נחשבות חופפות).
v01.149.000חדשמחסן / סורק ברקודיםminorסורק המחסן — שני מצבים חדשים: 'חיפוש משלוח' ו'פעולות מרובות'
דף הסריקה (shipments/scan) הורחב משני מצבים לארבעה.
פרטים נוספים ↓הסתר ↑
דף הסריקה (shipments/scan) הורחב משני מצבים לארבעה. נוסף מצב 'חיפוש משלוח': סריקת ברקוד (סורק USB, הקלדה + Enter, או מצלמת הנייד) פותחת מיד את דף המשלוח של הברקוד שנסרק — ללא עדכון סטטוס וללא פעולת שרת. בנוסף נוסף מצב 'פעולות מרובות': סורקים קבוצת משלוחים לרשימה ואז מחילים עליהם פעולה מרובה אחת — שיבוץ שליח, הדפסת מדבקות, העברה לסל מיחזור, הוספה לליקוט, שינוי סטטוס, וכן יעד שבת/אקספרס, שכפול, העתקה וסנכרון מליונוויל. הרשימה נבנית תוך כדי סריקה (כל ברקוד נשלף ומוצג עם נמען, כתובת וסטטוס, עם אפשרות להסרה פרטנית), ומופעל בה אותו סרגל הפעולות המרובות של דף המשלוחים — כך שכל הפעולות והאישורים זהים בדיוק. סיומת חבילה בברקוד (למשל '1234-2') מקוצצת אוטומטית לברקוד-האב בשני המצבים, כמו בשאר פעולות הסריקה. נוסף endpoint קליל (scan-lookup) לשליפת משלוח בודד לפי ברקוד לצורך בניית הרשימה. שיפורים נוספים למצב 'פעולות מרובות' למניעת טעויות: כל משלוח שכבר נמסר/בוטל/נכשל-סופית מסומן בכתום עם אזהרה כשהוא נכנס לרשימה (כדי לא לפעול עליו בטעות); שורת פילוח מעל הרשימה מציגה סה"כ משלוחים+חבילות, מספר המשלוחים בסטטוס סופי, ופיזור לפי אזורי חלוקה (לתפיסת טעויות מיון לפני שיבוץ שליח); הרשימה הסרוקה נשמרת ב-sessionStorage ושורדת רענון דף באמצע באצ'; סריקה חוזרת של משלוח שכבר ברשימה מקבלת חיווי מובחן (צליל דו-טוני + טוסט כתום); לחיצה על שורה סרוקה פותחת את דף המשלוח; ונוסף משוב רטט (haptics) במובייל לכל סריקה. ה-dedup של מצב הפעולות הופרד לחלוטין מזה של קליטה/שיבוץ. נוסף גם **דוח סריקות יומי** (shipments/scan-report, נגיש מכפתור 'דוח יומי' בסורק): מציג את כל היסטוריית הסריקות של היום הנבחר — הצלחות, שגיאות וטעויות מיון — עם בורר תאריך, כרטיסי סיכום לחיצים (סה"כ/הצלחות/שגיאות/טעויות מיון) המשמשים גם כמסננים, סינון לפי סוג (קליטה/שיבוץ), וייצוא ל-Excel/CSV והדפסה. כדי שגם השגיאות יתועדו, סריקות שנכשלו (משלוח לא נמצא, אין ביקור מסירה פתוח, נהג לא נמצא, חסר מזהה נהג) נרשמות כעת ל-audit trail תחת פעולה נפרדת 'scan_failed', וטעויות מיון מסומנות ברשומת ה-scan — כך שהדוח מציג תמונה מלאה. הדוח אינו משנה את לוג הסריקות הפר-משלוחי הקיים.
- מצב 'חיפוש משלוח' — סריקה פותחת מיד את דף המשלוח, ללא פעולת שרת
- מצב 'פעולות מרובות' — סריקת קבוצת משלוחים והחלת פעולה מרובה על כולם
- פעולות נתמכות: שיבוץ שליח, הדפסת מדבקות, סל מיחזור, ליקוט, שינוי סטטוס ועוד (שימוש חוזר בסרגל הפעולות של דף המשלוחים)
- מניעת טעויות: אזהרה כתומה על משלוח שכבר נמסר/בוטל, ופילוח קבוצה לפי אזור לפני שיבוץ
- שמירת הרשימה הסרוקה ברענון דף, חיווי לסריקה כפולה, פתיחת משלוח בלחיצה, ורטט במובייל
- דוח סריקות יומי — כל היסטוריית הסריקות (הצלחות + שגיאות + טעויות מיון) עם סיכום, סינון וייצוא ל-Excel/CSV
- עובד בסורק USB, בהקלדה ידנית ובמצלמת הנייד; קיצוץ אוטומטי של סיומת חבילה לברקוד-האב
v01.148.004שיפורמחסן / סורק ברקודיםסורק המחסן — טוסט 'ממתין' לכל ברקוד שמתמרמר לתוצאה
מאחר שהסורק קולט את הברקוד מיידית בעוד תגובת השרת לוקחת זמן, שונתה לוגיקת החיווי: ברגע זיהוי הברקוד קופץ מיד טוסט אפור-ניטרלי עם מספר הברקוד וספינר ('ממתין לשרת…'), וכשהתשובה חוזרת הוא מתמרמר במקום (morph) לירוק/אדום/כתו…
פרטים נוספים ↓הסתר ↑
מאחר שהסורק קולט את הברקוד מיידית בעוד תגובת השרת לוקחת זמן, שונתה לוגיקת החיווי: ברגע זיהוי הברקוד קופץ מיד טוסט אפור-ניטרלי עם מספר הברקוד וספינר ('ממתין לשרת…'), וכשהתשובה חוזרת הוא מתמרמר במקום (morph) לירוק/אדום/כתום עם טקסט התוצאה המלא — והטיימר של 3 שניות, מסגרת המסך והצליל מופעלים רק ברגע ה-morph. הטוסטים נערמים, כך שניתן לעקוב במקביל אחרי מספר ברקודים שעדיין ממתינים. החיווי הגנרי 'מעבד…' בתחתית הוסר (מיותר). נוסף gate ברמת המצלמה שמונע פתיחת טוסט-ממתין חוזר לברקוד שכבר טופל ונשאר מול המצלמה. נוסף timeout ל-fetch של הסריקה והשידור (15/20 שניות) כך שבקשה תקועה תיפתר לשגיאה ולא תשאיר ספינר תקוע — והשרת idempotent ולכן ניסיון חוזר אחרי timeout לא יוצר כפילות. בנוסף שונתה תצוגת הטוסטים לפי משוב: טוסטים של הצלחה/המתנה נערמים כעת כקלפים שמבצבצים חלקית זה מאחורי זה (כדי לא לתפוס גובה מעל אזור הסריקה), בעוד טוסטים של שגיאה/טעות-מיון 'יוצאים החוצה' ומוצגים במלואם (חיווי קריטי שמותר לו להסתיר את התצוגה). שופר גם המשוב על כשלים: כשל שידור מציג כעת את סיבת הכשל האמיתית שהשרת החזיר (במקום 'השידור נכשל' גנרי), וטעות מיון מציגה הסבר מפורש — איזה אזור אינו באזורי החלוקה של הנהג, ושבמקרה של קבלן החבילה לא שודרה. תוקן רגרסיה: כפתור הפנס שנעלם לגמרי (בעקבות gate שהסתיר אותו כשלא זוהתה תמיכה) — הכפתור מוצג שוב תמיד, וההפעלה מנסה את ה-constraint ישירות (חלק ממכשירי אנדרואיד לא מדווחים תמיכה אך כן מפעילים); אם באמת לא נתמך (iOS Safari) מוצגת הודעה קצרה 'הפנס אינו נתמך'. נוסף משוב רטט (Vibration API): רטט קצר ברגע זיהוי הברקוד (כדי שהמשתמש ידע מיד שנקלט ויעבור לחבילה הבאה), ורטט כפול מובחן בכשל/טעות מיון. נתמך בדפדפני אנדרואיד; ב-iOS Safari אין Vibration API ולכן זה no-op שם.
v01.148.003שיפורמחסן / סורק ברקודיםסורק המחסן במובייל — חיווי תוצאה מלא (טוסט, מסגרת צבעונית, צליל) + מניעת שידור כפול + תיקוני פנס ומקלדת
שיפורים לסורק הברקודים בדפדפן הנייד בדף קליטת/הוצאת מחסן (shipments/scan).
פרטים נוספים ↓הסתר ↑
שיפורים לסורק הברקודים בדפדפן הנייד בדף קליטת/הוצאת מחסן (shipments/scan). תוקן הפנס: כעת מזוהה תמיכת torch ברגע שהמצלמה עולה — הכפתור מוצג רק במכשירים שבהם הוא באמת עובד (ב-iOS Safari אין גישת פנס דרך הדפדפן, ולכן הכפתור הוסתר במקום להישאר כפתור מת), וההפעלה עוטפה ב-try/catch שמקרין כשל. תוקן באג שבו מקלדת הטלפון נפתחה באמצע סריקה — שדה הקלט הנסתר קיבל inputMode=none (קולט סורק USB ללא העלאת מקלדת רכה), ולוגיקת ה-focus האוטומטי הושבתה במכשירי מגע. נוסף חיווי תוצאה בתוך מסך המצלמה: לכל סריקה מוצג טוסט נערם בראש המסך (כדי לא להסתיר את אזור הסריקה) עם מספר הברקוד, אזור ההפצה והעיר, וכותרת לפי הפעולה — 'נקלט בהצלחה' בקליטה, 'שובץ לשליח X' בשיבוץ, 'שודר בהצלחה ל-X' בשידור לקבלן, או טקסט הכישלון בכישלון. טוסט הצלחה ירוק, כישלון אדום, וטעות מיון בכתום; כל טוסט נעלם אחרי 3 שניות ויש כפתור X להסתרה מיידית. במקביל מוארת מסגרת צבעונית סביב המסך לחצי שנייה ומושמע צליל הצלחה/כישלון/אזעקה. צלילי הביפ/אזעקה בצד העמוד מושתקים כשהמצלמה פתוחה כדי למנוע כפילות. תוקנה בעיה קריטית של שידור כפול לקבלן (= חיוב כפול): כשתגובת השרת איטית והמשתמש המתין על אותו ברקוד, ה-debounce (1.5 שניות) פג והסריקה נשלחה שוב — וכל שליחה יצרה הזמנה נפרדת אצל הקבלן. נוספה הגנה דו-שכבתית: (1) בצד הלקוח — דה-דופ פר-סשן שלא שולח את אותו הברקוד פעמיים לאחר שנשלח/הצליח (כישלון מאפשר ניסיון חוזר; 'נקה סשן' מאפס); (2) בצד השרת — broadcastShipmentsToSnl הפך ל-idempotent: אם המשלוח כבר שודר לאותו רגל (targetPartnerTaskId/pickupOutboundTaskId קיים) הקריאה ל-API מדולגת ומוחזר 'כבר שודר', כך שאף מסלול שידור (סורק, שידור מרוכז, שיוך נהגים, סוכן AI) לא יכול ליצור הזמנה כפולה. נוסף גם חיווי 'מעבד…' מיידי בסורק כדי שהמשתמש יידע שהסריקה נקלטה ולא יסרוק שוב. בנוסף הואצה תגובת הסריקה: סנכרון הסטטוס ל-Lionwheel (שה-API שלו איטי, ~1-2 שניות) הוצא מנתיב הבקשה הקריטי — הסטטוס נשמר מקומית והתגובה חוזרת מיד, והדחיפה ל-Lionwheel מתבצעת ברקע דרך after() של Next. חל גם על קליטה (IN_INVENTORY) וגם על שיוך (סנכרון הנהג לביקור ב-Lionwheel).
v01.148.002שיפורעיצוב / אייקוניםאחידות אייקון הלקוח בכל המערכת — אייקון 'חנות' (Store)
בעקבות הבחירה באייקון 'חנות' (Store) ללקוח בטופס הקמת המשלוח, אוחד אייקון הלקוח בכל המערכת — בכל מקום שמייצג לקוח.
פרטים נוספים ↓הסתר ↑
בעקבות הבחירה באייקון 'חנות' (Store) ללקוח בטופס הקמת המשלוח, אוחד אייקון הלקוח בכל המערכת — בכל מקום שמייצג לקוח. הוחל ב: ניווט הצד (קבוצת 'לקוחות' + הקישור למצבת), דף הלקוחות (כולל מצב ריק), טופס הוספת/עריכת לקוח, אווטאר/עמודת הלקוח בטבלה, בוררי הלקוח בהצעות מחיר ובהסכמים, קיבוץ לפי לקוח באיסופים, סינון לפי לקוח בליקוט, כרטיסי ה-KPI של לקוחות (אנליטיקס, דשבורד סוכן, דף סוכן, דף טננט באדמין), הגדרות לקוחות בטריגרים, ובורר סקופ הלקוח במחסן. הוחלפו Building2/Users/User באייקון Store בהקשרי לקוח בלבד — לא נגעו אייקוני עיר/טננט/צוות/משתמשים. הוחרגו במכוון: פילטר 'לקוחות' בתיבת השיחות (מייצג משתתפי צ'אט) וסקופ 'הכל (טננט + לקוחות)' במחסן.
v01.148.001תיקוןמחירוני לקוחות / רווחיותרווחיות לקוח — חישוב ההכנסה לפי מספר החבילות + הנחת חבילה נוספת
חישוב ההכנסה למשלוח לקח בחשבון רק חבילה אחת — מחיר הבסיס לא הוכפל במספר החבילות.
פרטים נוספים ↓הסתר ↑
חישוב ההכנסה למשלוח לקח בחשבון רק חבילה אחת — מחיר הבסיס לא הוכפל במספר החבילות. ההכפלה הסתמכה כל כולה על תוספת 'חבילה נוספת' שנשמרה מראש ב-priceSurcharges, וכאשר היא חסרה (משלוח ישן, ללא מחירון בעת היצירה, או שינוי מספר חבילות לאחר ההקמה) ההכנסה ירדה למחיר חבילה בודדת והוצג הפסד מדומה (למשל משלוח של 4 חבילות שחושב כ-25 ₪ במקום 100 ₪). כעת תוספת החבילות הנוספות מחושבת חיה ישירות ממספר החבילות ומהמחירון בכל חישוב הכנסה — כך שהתיקון חל רטרואקטיבית על כל המשלוחים לפי המחירון שלהם, ללא צורך בעדכון נתונים. החישוב מכבד את הנחת החבילה הנוספת (כללית ופר-אינדקס), ותוספת ה-extra_package השמורה מנוכה כדי שלא תיספר פעמיים. בנוסף תוקן שורש עמוק יותר: תוספת החבילות חושבה לפי שדה התעריף הגולמי בפרופיל (deliveryRate/pickupRate), אך אצל לקוחות שהתעריף שלהם מוגדר דרך כללי REPLACE השדות האלה הם 0 — ולכן התוספת התאפסה לחלוטין. כעת היא מחושבת מתעריף הבסיס המחושב (resolveCustomerBaseRate, כולל כללים), בדיוק כמו חבילה ראשונה. חל על פאנל התמחור הפר-משלוח, עמודת ההכנסה/רווח בטבלת המשלוחים, סיכום הרווחיות הפר-לקוח (כרטיס הלקוח + אנליטיקס) ובסיס חישוב עמלות הסוכנים.
v01.148.000שיפורהקמת משלוחים / טופסminorטופס הקמת משלוח — בורר לקוח בולט בראש הטופס + נעילת כתובת בית העסק
בורר הלקוח (משלח) בטופס הקמת המשלוח היה קבור בתחתית הטופס (אחרי המוצא, הנמען, היעד והמפה), כך שהזרימה הייתה הפוכה — מילוי כתובות ידני ורק בסוף בחירת לקוח שדורסת אותן — ורבים כלל לא הבחינו בו.
פרטים נוספים ↓הסתר ↑
בורר הלקוח (משלח) בטופס הקמת המשלוח היה קבור בתחתית הטופס (אחרי המוצא, הנמען, היעד והמפה), כך שהזרימה הייתה הפוכה — מילוי כתובות ידני ורק בסוף בחירת לקוח שדורסת אותן — ורבים כלל לא הבחינו בו. כעת בורר הלקוח הוא השדה הראשון והבולט בראש הטופס, בעיצוב זהה לזה שבדף ייבוא המשלוחים. בחירת לקוח ממלאת אוטומטית את צד 'בית העסק' לפי סוג המשלוח ונועלת אותו לעריכה: ב'מסירה' כתובת המוצא ננעלת; ב'איסוף' פרטי הנמען וכתובת היעד ננעלים; רק ב'חופשי' שתי הכתובות פתוחות. הנעילה משתמשת ב-readOnly כך שהערכים שמולאו אוטומטית עדיין נשלחים. השינוי חל על אותו רכיב טופס בכל ההקשרים — ממשק הניהול, ממשק הסוכנים ופורטל הלקוחות.
- בורר הלקוח (משלח) הועבר לראש טופס ההקמה כשדה ראשון ובולט, בעיצוב התואם את בורר הלקוח בדף ייבוא המשלוחים
- בחירת לקוח ממלאת אוטומטית את צד בית העסק: במסירה — כתובת המוצא; באיסוף — שם/טלפון הנמען וכתובת היעד
- הצד שמולא אוטומטית ננעל לעריכה (readOnly — הערכים עדיין נשלחים בתקין); רק במצב 'חופשי' שתי הכתובות פתוחות לעריכה חופשית
- כפתורי 'כתובות מועדפות' מוסתרים בצד הנעול, וטקסטי העזרה וכותרות הסקציות עודכנו לשקף נעילה
- חל על ממשק הניהול, ממשק הסוכנים ופורטל הלקוחות (אותו רכיב ShipmentForm). סוכן בוחר רק לקוחות המשויכים אליו; משתמש פורטל — רק מהלקוחות המקושרים אליו
- הטופס הורחב בדסקטופ (sm→2xl, lg→4xl, xl→5xl) כדי שלא יהיה דחוס מהצדדים ולתת מקום לפריסה רחבה. תוקן באג רוחב: ה-className הקודם (max-w-2xl ללא prefix) הפסיד ל-sm:max-w-lg של רכיב הדיאלוג הבסיסי ולכן הטופס היה בפועל ~512px בלבד בדסקטופ. רשת כתובת המוצא עברה ל-3 עמודות בדסקטופ
- בורר סוג המשלוח: כל אפשרות היא כפתור נפרד עם גבול משלו ורווח בין הכפתורים (הפרדה ברורה בין האפשרויות במקום רצף מבולבל), עם הדמיית-כיוון בכל כפתור (אייקון בית-העסק בצד המעוגן, אייקון מיקום בצד הלקוח, חץ מימין-לשמאל; חץ כפול ל'כפולה'). ההסבר המלא של הסוג שנבחר עבר לשורת הלייבל בפורמט '(הסוג שנבחר - מסירה - משלוח מבית העסק עד בית הלקוח)'. נוסף סוג רביעי 'כפולה' (משלוח דו-כיווני) שמתנהג כמסירה לעניין מילוי/נעילת המוצא ונשלח עם is_roundtrip. השדה חובה; במובייל מוצג כ-Select
- נוספו לסקציית 'כתובת יעד' שני שדות: קוד כניסה לבניין (door_code — מתקפל אוטומטית להערת היעד בליונוויל) ומיקוד יעד (destination_zip_code — נשלח לליונוויל/מדבקה). שדה 'הערות' זוהה כהערת-יעד (מה שהשליח רואה בכתובת המסירה, Lionwheel destination_notes), הועבר לסקציית 'כתובת יעד', הוקטן ל-2 שורות ותויג מחדש כ'הערת יעד'
- כל שדות כתובת היעד (עיר, רחוב, מספר, דירה, קומה, כניסה, קוד כניסה, מיקוד) אוחדו לגריד אחיד אחד — רוחב שווה לכל שדה (רבע בדסקטופ, חצי במובייל), במקום שעיר/רחוב/קוד-כניסה/מיקוד יהיו רחבים פי-שניים משאר השדות
- ליטושים: 'הערת יעד' צומצמה לשורה אחת (לכל הרוחב) במקום 2 שורות; שדות טלפון (נמען/מוצא/נוספים) ומיקוד מיושרים לימין כשאר הטופס (הוסר dir=ltr שגרם ליישור-שמאל); שדה 'ברקוד' הוסר כליל — הברקוד נוצר אוטומטית בליונוויל
- גוביינא מוסתרת מאחורי טוגל ('גוביינא (COD)' עם הסבר 'גביית כסף מהנמען בעת מסירת המשלוח') כדי לחסוך מקום — כבוי כברירת מחדל. רק בהפעלתו מופיעים השדות 'סכום גבייה' ו'סוג תשלום' (מזומן/שיק); כיבוי הטוגל מאפס את הסכום
- אחידות אייקוני שדות: לכל שדה אייקון, וללא כפילות בין מושגים שונים. תוקן ש'לקוח' ו'עיר' חלקו אותו אייקון (לקוח→חנות, עיר→Building). שדות זהים במוצא/יעד חולקים אייקון (עיר/רחוב/מספר/שם/טלפון); נוספו אייקונים לשדות שחסרו (דירה/קומה/כניסה/קוד-כניסה/מיקוד/מספר-מוצא); גוביינא קיבלה אייקונים מובחנים (סכום=שטר, סוג תשלום=ארנק)
- הצד הנעול של הכתובת (מוצא במסירה/כפולה, יעד באיסוף) מוצג כעת ככרטיס-טקסט קריא — 'כתובת ברירת המחדל של בית העסק' עם הפרטים + רמז 'להזנת כתובת שונה בחר סוג משלוח חופשי' — במקום שדות אפורים ונעולים שיצרו בלבול. הערכים עדיין נשלחים (inputs מוסתרים רשומים, ללא סיכון submit)
- שדה הרחוב הוסב ל-Combobox אמיתי: טוען פעם אחת את כל רחובות העיר ממאגר data.gov.il (ממוטמן פר-עיר) ומסנן מקומית — נפתח מיידית בלחיצה עם רשימה מלאה, הפוקוס נכנס ישר לשדה החיפוש, והשדה עצמו אינו ניתן לכתיבה (הערך נקבע רק מבחירה ברשימה). נוספה אפשרות 'רחוב שלא מופיע ברשימה' (מופיעה תוך כדי הקלדה) שבבחירתה מוצגת אזהרה לוודא שהרחוב קיים כדי למנוע טעויות שליחים. אינדיקציית הטעינה מוצגת בתוך הרשימה ולא חוסמת טקסט. שני ה-endpoints (ניהול + פורטל) עודכנו לתמוך בטעינת כל רחובות העיר
v01.147.002תיקוןפורטל לקוחות / משלוחיםפורטל לקוחות — תיקון לינק המעקב + הוספת לינק לעדכון פרטים
בדף המשלוח בפורטל הלקוחות כפתור 'לינק מעקב' בנה את הכתובת לפי הברקוד (/tracking/<barcode>), בעוד שדף המעקב הציבורי מחפש לפי public_id — כך שהקישור הוביל תמיד ל'משלוח לא נמצא / הקישור אינו תקף'.
פרטים נוספים ↓הסתר ↑
בדף המשלוח בפורטל הלקוחות כפתור 'לינק מעקב' בנה את הכתובת לפי הברקוד (/tracking/<barcode>), בעוד שדף המעקב הציבורי מחפש לפי public_id — כך שהקישור הוביל תמיד ל'משלוח לא נמצא / הקישור אינו תקף'. הכפתור תוקן ובמקומו נכנס דרופדאון עם שתי האפשרויות הזהות לאלו שבממשק הניהול: 'לינק מעקב ללקוח' (/tracking/<public_id>) ו'לינק לעדכון פרטים' (/validate/<public_id>) — שתיהן בנויות נכון לפי public_id ומועתקות ללוח בלחיצה. כשאין public_id למשלוח האפשרויות מושבתות.
v01.147.001חדשסוכנים / הקמת משלוחיםסוכנים — הקמת משלוח מהממשק, מוגבלת ללקוחות שלהם בלבד
עד כה כפתור 'משלוח חדש' בדף המשלוחים היה מוסתר לסוכנים, כך שסוכן יכול היה רק לצפות במשלוחים (וליבא בכמות דרך דף הייבוא) — אך לא להקים משלוח בודד מהממשק.
פרטים נוספים ↓הסתר ↑
עד כה כפתור 'משלוח חדש' בדף המשלוחים היה מוסתר לסוכנים, כך שסוכן יכול היה רק לצפות במשלוחים (וליבא בכמות דרך דף הייבוא) — אך לא להקים משלוח בודד מהממשק. כעת לסוכן יש גישה מלאה לטופס הקמת המשלוח הרגיל (כל השדות, כמו לצוות), עם הגבלה אחת: רשימת הלקוחות בטופס מצומצמת אך ורק ללקוחות המשויכים לסוכן (Customer.agentId). הסינון נאכף בצד שרת ב-/api/customers/for-shipment-form, ובנוסף נקודת היצירה /api/shipments/create מאמתת מחדש שהלקוח שנבחר באמת משויך לסוכן ודוחה בקשה מזויפת (403) — אותו דפוס הגנה שכבר קיים בייבוא הכמותי. סוכן ללא לקוחות משויכים מקבל רשימה ריקה.
v01.147.000חדשאינטגרציות / WooCommerceminorWooCommerce — שידור אוטומטי לליונוויל בייבוא + רישום Webhook אוטומטי + סנכרון גיבוי
עד כה WooCommerce דרשה מהלקוח להגדיר Webhook ידנית (יצירת webhook ב-WooCommerce + הדבקת Secret תואם), ובניגוד לקונימבו/CashCow/e-shop/nopCommerce — לא הייתה לה משיכה אוטומטית כגיבוי.
פרטים נוספים ↓הסתר ↑
עד כה WooCommerce דרשה מהלקוח להגדיר Webhook ידנית (יצירת webhook ב-WooCommerce + הדבקת Secret תואם), ובניגוד לקונימבו/CashCow/e-shop/nopCommerce — לא הייתה לה משיכה אוטומטית כגיבוי. התוצאה: לקוח שחיבר חנות, לחץ 'בדיקת חיבור' (שבודקת רק את ה-REST API) וקיבל 'החיבור הצליח' — אך לא השלים את הגדרת ה-Webhook או הגדיר Secret שלא תאם — לא ראה אף הזמנה, בלי שום אינדיקציה לתקלה. כעת בחיבור חנות WooCommerce שיפנסט **רושמת את ה-Webhook אוטומטית** דרך ה-API של החנות (יוצרת order.created + order.updated עם Secret שאנחנו מייצרים), כך שהזמנות חדשות מגיעות **מיד בזמן אמת ללא שום הגדרה ידנית**. בנוסף נוסף cron גיבוי שמושך הזמנות processing/on-hold כל 5 דקות, עם דה-דופ משותף עם ה-Webhook כך שאין כפילויות. כפתור 'סנכרן Webhook' מאפשר לרשום מחדש בלחיצה לחיבורים קיימים.
- הזמנה מיובאת משודרת אוטומטית לליונוויל (דרך אותה ליבת יצירת-משלוח כמו יצירה ידנית) — מקבלת ברקוד אמיתי של ליונוויל וסטטוס אמיתי, במקום שורה מקומית עם ברקוד סינתטי. נעילה אטומית (claim על הברקוד הדטרמיניסטי) מונעת שידור כפול מ-order.created+order.updated/cron; אם השידור נכשל המשלוח נשמר כ'ממתין' ולא אובד. חל על שני המסלולים (webhook + cron)
- רישום Webhook אוטומטי מול WooCommerce ברגע החיבור (order.created + order.updated, Secret מנוהל-מערכת) — זמן אמת ללא הגדרה ידנית; דורש מפתח Read/Write, ואחרת נופל בחן למסלול הידני
- כפתור 'סנכרן Webhook' בכרטיס החנות + endpoint register-webhook לרישום מחדש לחיבורים קיימים (כמו חנויות שחוברו לפני הפיצ'ר)
- Cron גיבוי sync-woocommerce-orders כל 5 דקות, מושך לפי modified_after (תופס גם הזמנות שעברו ל-processing אחרי תשלום); דה-דופ משותף עם ה-Webhook לפי (tenant, customer, connection, externalOrderId) + barcode זהה
- מדריך החיבור בפורטל עודכן (תיבת 'איך הסנכרון עובד', הבהרת ה-Secret), וכשל-חיבור לחנות נרשם כ-warning ולא כשגיאת-מערכת כדי לא להפעיל התראת admin בכל מחזור
- סנכרון ה-Webhook מוחק כעת hooks ישנים לפי נתיב מזהה-החיבור (לא URL מדויק), כך שכפילויות בכתובת מעט שונה (www מול apex) מוסרות ולא יוצרות 401 ומסירה כפולה
- תוקן: סטטוס ההזמנה של WooCommerce (processing/on-hold) דלף ל-additionalData.status ונראה ללקוח כסטטוס משלוח שגוי + הסתיר את המשלוח מדפי השיבוץ. המיפוי שומר אותו כעת תחת wooStatus, והמשלוח המיובא נקלט כ'משלוח חדש' (UNASSIGNED) וניתן לשיבוץ/דחיפה לליונוויל
- סנכרון סטטוס חזרה ל-WooCommerce על כל מעבר סטטוס (לא רק 'נמסר'): נמסר/הושלם→completed, בוטל→cancelled, נכשל→failed; 'נקלט במחסן' ו'יצא להפצה' מתועדים כהערה בציר-הזמן של ההזמנה (אין להם סטטוס מובנה ב-WooCommerce). פועל גם על מעברים מליונוויל (upsertShipment, AI-lock-aware) וגם על שינוי סטטוס ידני ב-Shipnest, fire-and-forget
- פריטי הזמנה כוללים כעת תמונת מוצר ומחיר: קולטים את image.src מ-line_items של WooCommerce ושומרים בעמודה image_url חדשה ב-order_item; כרטיס פריטי המשלוח מציג thumbnail לכל פריט (placeholder לפריטים ללא תמונה). גם המחיר נשמר כעת בשידור (עבר דרך ליבת יצירת-המשלוח, קודם ירד)
v01.146.006חדשיבוא משלוחיםיבוא משלוחים — הורדת השורות השגויות לאקסל לתיקון והעלאה מחדש
משתמשים רבים ביקשו דרך מהירה לטפל בקבצי יבוא גדולים עם שורות שגויות: במקום לתקן עשרות שורות אחת-אחת בתוך הטבלה, אפשר כעת להוריד את השורות השגויות בלבד כקובץ אקסל, לתקן אותן בנוחות באקסל, ולהעלות מחדש רק אותן.
פרטים נוספים ↓הסתר ↑
משתמשים רבים ביקשו דרך מהירה לטפל בקבצי יבוא גדולים עם שורות שגויות: במקום לתקן עשרות שורות אחת-אחת בתוך הטבלה, אפשר כעת להוריד את השורות השגויות בלבד כקובץ אקסל, לתקן אותן בנוחות באקסל, ולהעלות מחדש רק אותן. בשלב התצוגה המקדימה (טאב 'שגויות') נוסף כפתור 'הורד שגויות' לצד כפתור ה-AI; הוא מייצא את אותן שורות חוסמות (שדות חובה חסרים, טלפון לא תקין, מזהה כפול וכד') בדיוק בפורמט תבנית היבוא הסטנדרטי — כך שהקובץ נטען בחזרה ללא מיפוי מחדש — עם עמודת 'סיבת שגיאה' ראשונה המפרטת לכל שורה מה צריך לתקן. עמודת הסיבה אינה ממופה ביבוא ולכן מתעלמים ממנה אוטומטית בהעלאה החוזרת. הפיצ'ר זמין גם בפורטל הלקוחות (אותו רכיב יבוא).
v01.146.005חדשבוט תרחישים / יידוע טיפולבוט תרחישים — הודעת 'בודק' לקבוצת המקור כשהבוט מגשר לצד השני
נציגות השירות ביקשו לדעת מתי הבוט כבר טיפל בפנייה, כדי לא לטפל בה כפול.
פרטים נוספים ↓הסתר ↑
נציגות השירות ביקשו לדעת מתי הבוט כבר טיפל בפנייה, כדי לא לטפל בה כפול. עד כה כשהבוט גישר (למשל: לקוח שואל צפי → הבוט שואל את השליח בקבוצת השליח), קבוצת המקור — שם הלקוח והנציגות צופות — נשארה שקטה עד שחזרה התשובה, ולא היה ניתן לדעת שהבוט תפס את הפנייה. כעת, מיד כשהבוט פותח גישור בפועל, הוא רושם הודעת יידוע קצרה בקבוצת המקור (כציטוט של ההודעה המקורית): 'בודק מול השליח את צפי המסירה של משלוח X, אעדכן בהקדם 🔎' / 'מברר מול הלקוח...'. ההודעה נשלחת אך ורק כשהבוט באמת פעל ופתח גישור — לא כשהוא שותק או מתעלם — ופעם אחת בלבד (גארד hasOpenRelay), לא על כל הודעה חוזרת. הנוסח ניתן לעריכה פר-תרחיש בהגדרות → תרחישי הבוט (תבנית 'יידוע שהבוט מטפל'). חל על חמשת תרחישי הגישור: צפי, תיאום/שינוי מועד, אין מענה, כתובת שגויה וטלפון שגוי. תרחישי השידור ואימות הקבלה כבר עונים באותה קבוצת מקור, ולכן אינם כלולים.
v01.146.004שיפורבוט תרחישים / שידורבוט שידור — תשובות השידור נשלחות כציטוט (שרשור) של בקשת הקבלן
ציטוט הודעות (Green API quotedMessageId) אפשרי רק באותו צ'אט.
פרטים נוספים ↓הסתר ↑
ציטוט הודעות (Green API quotedMessageId) אפשרי רק באותו צ'אט. הודעות הבוט שהן חוצות-צ'אט (שאלת צפי לשליח, בקשת טלפון/כתובת ללקוח) לא יכולות להיות מצוטטות כי הטריגר נמצא בקבוצה אחרת — וזה החלק שנראה הכי הרבה. תשובות השידור, לעומת זאת, נשלחות באותה קבוצה של הקבלן — ושם עכשיו הוספנו ציטוט: '✅ שודר אליך', 'כדי לשדר אצטרך מספר', 'לא נמצא' וכו' נשלחות כתשובה מצוטטת על הודעת הבקשה של הקבלן, כך שברור ויזואלית למה הן מתייחסות. (relay-back ונדנודים כבר מצטטים מאז קודם; נדנודים עדיין כבויים כברירת מחדל.)
v01.146.003תיקוןתמונת מחסןתמונת מחסן — משלוחים שכבר נמסרו / יצאו להפצה הוסתרו מהעגלות
אנשי המחסן דיווחו שהדף מציג חבילות שכבר עזבו את המחסן (נמסרו או יצאו להפצה) כאילו הן עדיין תקועות בעגלה.
פרטים נוספים ↓הסתר ↑
אנשי המחסן דיווחו שהדף מציג חבילות שכבר עזבו את המחסן (נמסרו או יצאו להפצה) כאילו הן עדיין תקועות בעגלה. הסיבה: התצוגה סיננה לפי additionalData.status='IN_INVENTORY', וסטטוס זה נשאר 'תקוע' כשעדכון הסטטוס מליונוויל מתעכב או מתפספס. עד כה השאילתה הסתירה רק משלוח 'בדרך כרגע' (שליח משובץ), אך לא משלוח שכבר נמסר — כך שמשלוח נמסר עם סטטוס תקוע 'קפץ' חזרה לעגלה. כעת התצוגה סומכת על ביקור המסירה ועל חותמת היציאה מהמחסן יותר מאשר על שדה הסטטוס: מוסתרים משלוחים שביקור המסירה שלהם הושלם (isDone / deliveredAt) או שיצאו להפצה (out_inventory_at אחרי הקליטה) — תוך שמירה על משלוחים שנכשלו וחזרו פיזית למחסן. אומת מול נתוני פרודקשן: 15 משלוחים שגויים הוסרו (כולל אחד שנמסר במרץ), ללא פגיעה ב-2,102 המשלוחים שבאמת ממתינים. בנוסף: טופל מצב שבו כשל זמני בטעינת ה-API הציג 'המחסן ריק' מטעה (כעת מוצג באנר שגיאה והנתונים הקיימים נשמרים על המסך), והעגלות ממוינות כעת מספרית (1,2,3…10,11) במקום לקסיקוגרפית (1,10,11…2,20).
v01.146.002שיפורבוט תרחישים / נוסח הודעותבוט תרחישים — פרטי משלוח עשירים בכל הודעות הגישור ללקוח/שליח
עד כה הודעות הבוט פירטו את המשלוח בסוגריים עם מידע דל (למשל '(מורן 5, פרדס חנה)').
פרטים נוספים ↓הסתר ↑
עד כה הודעות הבוט פירטו את המשלוח בסוגריים עם מידע דל (למשל '(מורן 5, פרדס חנה)'). כעת בכל תרחישי הגישור — צפי, אין מענה, טלפון שגוי, כתובת שגויה, תיאום מחדש וכשל מסירה — פרטי המשלוח מופיעים בדיוק באותו פורמט שהנציגות מעתיקות מכרטיסיית פרטי היעד בדף המשלוח — בלוק מסודר עם אימוג'ים: מספר משלוח, שם הנמען, רחוב ומספר, דירה וקומה (כשקיימים), עיר וטלפון. הוסף placeholder חדש {details} לתבניות הניתנות לעריכה (לצד {barcode}/{address} שעדיין נתמכים). בתרחישי בקשת שידור הפורמט נשאר תמציתי כפי שביקשת.
v01.146.001תיקוןבוט תרחישים / שיוך משלוחבוט תרחישים — דיווח שליח שוּיֵּך למשלוח ישן שכבר נמסר
בדיווח שליח (אין מענה / נייד לא תקין / אין זיהוי) הבוט שייך את הדיווח למשלוח לפי הברקוד (מהטקסט או מצילום המדבקה), או — כשאין ברקוד — ל'משלוח הפעיל האחרון של השליח'.
פרטים נוספים ↓הסתר ↑
בדיווח שליח (אין מענה / נייד לא תקין / אין זיהוי) הבוט שייך את הדיווח למשלוח לפי הברקוד (מהטקסט או מצילום המדבקה), או — כשאין ברקוד — ל'משלוח הפעיל האחרון של השליח'. שני המסלולים לא בדקו את סטטוס המסירה: מסלול הברקוד התאים כל משלוח לפי המספר ללא סינון, ומסלול ה-fallback סינן בטעות לפי sendStatus (סטטוס שליחת הודעת הוואטסאפ ללקוח) במקום סטטוס המסירה. כך משלוח שכבר נמסר במרץ — אך הודעת הלקוח שלו מעולם לא סומנה כנשלחה (sendStatus=PENDING) — שוּיֵּך לדיווח, והבוט טרטר את הלקוח הלא-נכון שוב ושוב ('השליח מדווח שמספר הטלפון שגוי במשלוח 22834782...'). כעת שני המסלולים מתבססים על סטטוס המסירה הקנוני (status) ומחריגים משלוחים שנמסרו/נכשלו/בוטלו; ואם הברקוד בדיווח מצביע על משלוח שכבר נמסר — הבוט שותק ולא נופל אחורה למשלוח אחר.
v01.146.000חדשמשלוחיםminorטבלת המשלוחים — עמודות מוצא (איסוף) וסימון 'יעד' ברור
נוספו לטבלת המשלוחים עמודות פרטי המוצא (האיסוף), במקביל מלא לעמודות היעד: עיר מוצא, אזור חלוקה מוצא, כתובת מוצא ומועד האיסוף.
פרטים נוספים ↓הסתר ↑
נוספו לטבלת המשלוחים עמודות פרטי המוצא (האיסוף), במקביל מלא לעמודות היעד: עיר מוצא, אזור חלוקה מוצא, כתובת מוצא ומועד האיסוף. במקביל, עמודות היעד הקיימות תויגו מחדש כדי שיהיה ברור לאיזה צד הן שייכות: 'עיר' → 'עיר יעד', 'אזור' → 'אזור חלוקה יעד', 'כתובת' → 'כתובת יעד', ו'תאריך מסירה' → 'מועד מסירה'. 'כתובת מוצא' מציגה רחוב+מספר (בדומה ל'כתובת יעד'), ו'עיר מוצא' היא עמודה נפרדת. השדה pickupZoneCode נוסף ל-API של רשימת המשלוחים — גם בנתיב ה-Prisma וגם בנתיב ה-SQL הגולמי (המופעל בסינון לפי סטטוס/שליח), יחד עם delay_clock_started_at — כך שהעמודות החדשות מתאכלסות בכל שילוב פילטרים. כל עמודות המוצא מוסתרות כברירת מחדל ומופעלות מתפריט העמודות.
- ארבע עמודות מוצא חדשות: עיר מוצא, אזור חלוקה מוצא, כתובת מוצא, מועד האיסוף — מקבילות לעמודות היעד
- עמודות היעד תויגו מחדש לבהירות: עיר → עיר יעד, אזור → אזור חלוקה יעד, כתובת → כתובת יעד, תאריך מסירה → מועד מסירה
- pickupZoneCode + delay_clock_started_at נוספו לנתיב ה-SQL הגולמי (סינון סטטוס/שליח) כך שהעמודות מתאכלסות בכל שילובי הסינון
- כל עמודות המוצא מוסתרות כברירת מחדל — הפעלה מתפריט העמודות
v01.145.001תיקוןנוכחות / רכיבים משותפיםבורר השעות בדיווח נוכחות — גלילה תקועה בנייד
במודל 'דיווח משמרת רטרואקטיבי' (וכל בורר שעות אחר שנפתח בתוך דיאלוג), העמודות הנגללות של שעה/דקה לא נגללו במגע בטלפון — הן היו 'תקועות'.
פרטים נוספים ↓הסתר ↑
במודל 'דיווח משמרת רטרואקטיבי' (וכל בורר שעות אחר שנפתח בתוך דיאלוג), העמודות הנגללות של שעה/דקה לא נגללו במגע בטלפון — הן היו 'תקועות'. הסיבה: פאנל הבורר עבר portal אל גוף המסמך, מחוץ ל-DialogContent, ולכן נעילת הגלילה של הדיאלוג (react-remove-scroll) חסמה אירועי מגע שמקורם מחוץ לאזור הנעול. התיקון ממקם את פאנל הבורר בתוך הדיאלוג הקרוב (portal container), כך שהוא נכלל באזור המותר לגלילה והמגע עובד. במקביל, מרכוז הערך הנבחר בעת הפתיחה מתבצע מעתה על העמודה בלבד (scrollTop ידני) במקום scrollIntoView, כדי שלא יזיז את גלילת הדיאלוג עצמו.
v01.145.000חדשמשלוחים / תמחורminorטבלת המשלוחים — עמודות תמחור ורווחיות
טבלת המשלוחים חושפת מעתה את אותם נתוני תמחור ורווחיות שהיו זמינים רק באקורדיון 'תמחור ורווחיות' שבדף המשלוח הבודד: מחיר בסיס, עלות ליונוויל, עלות איסוף, עלות מסירה, סה"כ עלות ורווח.
פרטים נוספים ↓הסתר ↑
טבלת המשלוחים חושפת מעתה את אותם נתוני תמחור ורווחיות שהיו זמינים רק באקורדיון 'תמחור ורווחיות' שבדף המשלוח הבודד: מחיר בסיס, עלות ליונוויל, עלות איסוף, עלות מסירה, סה"כ עלות ורווח. כל העמודות נחשפות רק למשתמשים עם הרשאת finance:view ומוסתרות כברירת מחדל — המשתמש מפעיל אותן מתפריט העמודות. 'מחיר בסיס' הוא תעריף הבסיס במחירון הלקוח (ריק כשאין מחירון). הרווח חושב עד כה נאיבית כ'מחיר פחות עלויות'; מעתה הוא מחושב כמו בפאנל הפר-משלוח — סה"כ לחיוב ללקוח (בסיס × מכפיל דחיפות + תוספות) פחות עלות הביצוע, עם נפילה למחיר ליונוויל כשאין מחירון, ומוצג רק לאחר שחושבו עלויות האיסוף/מסירה. baseRate וההכנסה מחושבים פר-עמוד בשרת דרך helper מקובץ (שתי שאילתות בלבד). בנוסף, העמודה 'מחיר' (מחיר ליונוויל) שונתה ל'עלות ליונוויל' והוגנה אף היא מאחורי finance:view, עקבי עם שאר העמודות הפיננסיות.
- שש עמודות פיננסיות בטבלת המשלוחים — מחיר בסיס, עלות ליונוויל, עלות איסוף, עלות מסירה, סה"כ עלות, רווח — מקבילות לאקורדיון 'תמחור ורווחיות' בדף המשלוח
- מוצגות רק למשתמשים עם הרשאת finance:view, מוסתרות כברירת מחדל (הפעלה מתפריט העמודות)
- הרווח מחושב לפי מחירון הלקוח (בסיס × מכפיל דחיפות + תוספות) פחות עלות הביצוע, ומוצג רק לאחר שחושבו עלויות האיסוף/מסירה
- חישוב baseRate + הכנסה מקובץ פר-עמוד בשרת (שתי שאילתות), עם נפילה למחיר ליונוויל כשאין מחירון ללקוח
- העמודה 'מחיר' שונתה ל'עלות ליונוויל' והוגנה מאחורי finance:view
- נוספה עמודת 'סה"כ לחיוב' (החיוב המלא ללקוח: בסיס × מכפיל + תוספות, או מחיר ליונוויל כשאין מחירון) — משלימה את התמונה: רווח = סה"כ לחיוב − סה"כ עלות
- ייצוא ה-Excel של הטבלה מכבד מעתה את התצוגה ברגע הלחיצה — רק העמודות הגלויות (בסדרן) ורק השורות שעוברות את הפילטרים הפעילים (כולל העמודות הפיננסיות והשדות המותאמים). קודם יוצאה רשימת עמודות קבועה שהתעלמה מהבחירה
- הייצוא מוריד מעתה את כל השורות התואמות לסינון (כל העמודים), לא רק את הדף שעל המסך — שליפה מהשרת בלולאת עמודים עד מיצוי התוצאות, עם חיווי טעינה וספירת שורות
- הוסרה העמודה 'השליח קרוב נשלח' (חותמת הזמן של התראת 'השליח קרוב') מטבלת המשלוחים — שם מבלבל ולא נחוץ
v01.144.000שיפורAI / תובנותminorתובנות AI — הדף הפך לתצוגת שיפור-עצמי של הבוט
דף /settings/ai-insights הציג עד כה 'זיכרון על ישויות' (תצפיות על לקוח/שליח/משלוח ספציפי) — מה שנראה כטריוויה חסרת-משמעות.
פרטים נוספים ↓הסתר ↑
דף /settings/ai-insights הציג עד כה 'זיכרון על ישויות' (תצפיות על לקוח/שליח/משלוח ספציפי) — מה שנראה כטריוויה חסרת-משמעות. במקביל, התובנות שה-AI אוסף על עצמו (פעולות שלא ידע לבצע, טעויות חוזרות, שאלות שלא ידע לענות — רמת 'system') היו חבויות בלוח המפתחים בלבד ולא נחשפו לבעל המערכת. הדף נבנה מחדש כתצוגת שיפור-עצמי: הוא מציג כעת את תובנות-המערכת של הטננט עצמו, עם הרחבת המקור (השיחה/הקבוצה ממנה נלמדה), סימון 'טופל'/'נדחה' ומחיקה. תובנות על ישות (לקוח/שליח/משלוח) ירדו מהדף ומוצגות מעתה בכרטיס הייעודי שבדף של אותה ישות — שם הן הקשריות — וממשיכות להיות מוזרקות לפרומפט כרגיל. נוסף endpoint ייעודי לטננט (/api/ai/insights/system) המקודד-קשיח ל-entityType=system ולטננט של המבקש, כך שבידוד ה-multi-tenancy נשמר במלואו (הבידוד הקודם בנתיבי-הישות לא רוכך). תג 'תובנות' בסיידבר סופר מעתה תובנות-מערכת ממתינות בלבד.
- הדף מציג את תובנות-המערכת של הטננט: מה שהבוט לא ידע לבצע, טעה בו או לא הבין — לזיהוי מה לשפר
- תובנות לקוח/שליח/משלוח ירדו מהדף ומוצגות בכרטיס שבדף של אותה ישות (עדיין מוזרקות לפרומפט)
- endpoint ייעודי /api/ai/insights/system (+ [id] ל-triage/מחיקה) — scoped קשיח ל-system + tenantId; בידוד multi-tenancy נשמר
- תג 'תובנות' בסיידבר משקף מעתה את מה שהדף מציג — תובנות-מערכת ממתינות בלבד
- תיעוד /docs/ai עודכן לפיצול בין תובנות-ישות (בכרטיס הישות) לתובנות-מערכת (בדף ההגדרות)
- הרחבת 'מקור' מציגה כל הודעה בשורה נפרדת עם תאריך/שעה מקוצר ושם הכותב — תובנות חדשות נשמרות הודעה-הודעה (חילוץ מובנה דרך ה-webhook, אדיטיבי ללא שינוי בסיווג), הישנות מפוצלות לתצוגה; רכיב מקור משותף לדף ההגדרות וללוח המפתחים
v01.143.002תיקוןמסרונים / טריגריםטריגרים — שליחה 'מיידית' ללקוח מכבדת את שעות הפעילות
לקוחות קצה קיבלו הודעות וואטסאפ בלילה כשנפתח משלוח בשעות מאוחרות.
פרטים נוספים ↓הסתר ↑
לקוחות קצה קיבלו הודעות וואטסאפ בלילה כשנפתח משלוח בשעות מאוחרות. הסיבה: טריגר שמוגדר 'מיידי' (וזו גם ברירת המחדל) שלח ישירות דרך sendWhatsApp שבדק רק שבת — ולא את שעות הפעילות שהוגדרו לטננט (ברירת מחדל 08:00–21:00). כעת גם הנתיב המיידי בודק את חלון השליחה (isWithinMessagingWindow): אם המשלוח נוצר מחוץ לשעות הפעילות (או בחג חסום), ההודעה נכנסת לתור ההודעות המתוזמנות ומשתחררת אוטומטית ברגע שהחלון נפתח — בדיוק כמו מנגנון הצבירה שכבר היה קיים, דרך קרון scheduled-messages שרץ כל 5 דקות ומדלג על הודעות מחוץ-לחלון בלי לבזבז ניסיון. חסימת שבת ממשיכה כמקודם (תור עד מוצ"ש). בנוסף — בטופסי הטריגרים, מתחת לאפשרות 'מיידי', נוספה הבהרה שהשליחה מוגבלת לשעות הפעילות וההודעה תיצבר ותישלח כשייפתחו. ובדף שעות הפעילות (/messages/preferences) נוספה ולידציה שמונעת שמירת טווח לא תקין — שעת הסיום חייבת להיות מאוחרת משעת ההתחלה; טווח שעובר חצות (למשל 21:00–08:00) אינו נתמך וחוסם את כפתור השמירה.
v01.143.001תיקוןבוט תרחישים / שידורבוט שידור — תיקון 'בקשת מספר משלוח' שצצה מנותקת מהקשר
בקבוצת שליח/קבלן הבוט שלח לעיתים 'כדי לשדר אליך — אצטרך את מזהה המשלוח' בלי שאיש ביקש לשדר, מנותק לגמרי מההקשר.
פרטים נוספים ↓הסתר ↑
בקבוצת שליח/קבלן הבוט שלח לעיתים 'כדי לשדר אליך — אצטרך את מזהה המשלוח' בלי שאיש ביקש לשדר, מנותק לגמרי מההקשר. שני גורמים תוקנו: (1) חלון זמן — איסוף מספרי המשלוח כבר היה מוגבל ל-20 דקות, אבל שער-הזיהוי (האם זו בכלל בקשת שידור?) בדק את כל ה'מטח' מאז התגובה היוצאת האחרונה (עד 30 הודעות), כך שמילת-שידור ישנה מלפני שעות עדיין הדליקה אותו; כעת גם השער מוגבל לאותן 20 דקות אחרונות. (2) הפרדת צוות מקבלן — שער-הזיהוי בדק את כל הטקסט כולל שורות שכתב חבר צוות שלנו ([צוות: ...]), כך שמילת-שידור שצוות כתב הדליקה את הבוט; כעת השער קורא אך ורק את תוכן הקבלן (לא-צוות), עקבי עם איסוף-היעדים שכבר דילג על הודעות צוות. בקשת שידור חייבת להגיע מהקבלן, לא מאיתנו.
v01.143.000חדשבוט תרחישים / נדנודminorבוט תרחישים — נדנוד (תזכורות) לשליחים שלא ענו
נוסף נדנוד אוטומטי: כשהבוט שואל שליח/קבלן שאלה (למשל צפי מסירה) ולא מתקבלת תשובה, הוא שולח תזכורת בקבוצת השליח — בציטוט השאלה המקורית — כל מספר שעות שמוגדר, וממשיך לנדנד בהדרגה (תזכורת 1, 2, ...) עד שמתקבלת תשובה (עד 10 …
פרטים נוספים ↓הסתר ↑
נוסף נדנוד אוטומטי: כשהבוט שואל שליח/קבלן שאלה (למשל צפי מסירה) ולא מתקבלת תשובה, הוא שולח תזכורת בקבוצת השליח — בציטוט השאלה המקורית — כל מספר שעות שמוגדר, וממשיך לנדנד בהדרגה (תזכורת 1, 2, ...) עד שמתקבלת תשובה (עד 10 תזכורות). הנדנוד נשלח אך ורק בשעות הפעילות של העסק (ברירת מחדל 08:00–21:00, מודע לשבת/חגים — אותו מנגנון של ההודעות המתוזמנות), כך שלא נשלחות הודעות בלילה; הוא מתחדש למחרת בבוקר עם נוסח 'בוקר טוב' רך, ומגוון את הניסוח כדי שלא יהיה רובוטי. הנדנוד חל אך ורק על תרחישים שממתינים לשליח/קבלן (צפי, תיאום מחדש) — לעולם לא ללקוחות. בעריכת התרחיש (/settings/bot-scenarios) נוסף מתג 'נדנוד אוטומטי' + הגדרת מרווח השעות; כבוי כברירת מחדל.
- מתג נדנוד + מרווח שעות לכל תרחיש בר-נדנוד (כבוי כברירת מחדל)
- תזכורות בציטוט השאלה המקורית, מוגבלות לשעות פעילות (מודע לשבת/חגים), המשך בבוקר עם גיוון
- רק לשליחים/קבלנים (relay שממתין לשליח), לעולם לא ללקוחות
- מנוע: cron כל 15 דק' (/api/cron/scenario-nudges) + מעקב nudge_count/last_nudge_at על ה-relay
- מפסיק לנדנד אוטומטית כשהמשלוח כבר טופל (נמסר/נכשל/בוטל) — אין תזכורת מיותרת על משלוח סגור
- גיוון נוסח מורחב, במיוחד בפתיחים של תזכורות הבוקר; המונה מתאפס בכל בוקר (לא נצבר מיום ליום)
- נדנוד גם לשאלות צוות: כששואלים שליח על משלוח בקבוצה (עם מספר) והוא לא עונה — הבוט מזכיר לו; נתפס מרגע ההפעלה והלאה, נעצר כשהשליח עונה או כשהמשלוח טופל. מתג ייעודי בהגדרות (כבוי כברירת מחדל)
v01.142.000שיפורבוט תרחישים / Green APIminorבוט תרחישים — תשובות בציטוט (שרשור) של ההודעה המקורית
כשהבוט מחזיר תשובת גישור לקבוצה (למשל אחרי שהשליח עונה על שאלת צפי — 'לגבי X: נמסר אתמול', או כשהלקוח עונה על 'אין מענה'), ההודעה הופיעה כהודעה עצמאית שנראתה 'מנותקת מהקשר'.
פרטים נוספים ↓הסתר ↑
כשהבוט מחזיר תשובת גישור לקבוצה (למשל אחרי שהשליח עונה על שאלת צפי — 'לגבי X: נמסר אתמול', או כשהלקוח עונה על 'אין מענה'), ההודעה הופיעה כהודעה עצמאית שנראתה 'מנותקת מהקשר'. כעת הבוט שולח אותה כ**תשובה מצוטטת** ישירות על ההודעה המקורית שפתחה את הגישור (שאלת הצפי של הלקוח / דיווח השליח), כך שברור מיד למה היא מתייחסת. מומש דרך השדה quotedMessageId של Green API (ציטוט אפשרי רק לאותו צ'אט). הוספנו לכידה ושמירה של מזהה הודעת-הטריגר הנכנסת (עמודה trigger_message_id ב-relay), והעברנו אותו עד לשליחת התשובה. חל על כל תרחישי הגישור (צפי, אין מענה, כתובת שגויה, טלפון שגוי, תיאום מחדש). שאלת-הביניים לשליח אינה מצוטטת (צ'אט אחר — Green API לא מצטט בין צ'אטים).
- תשובת הבוט מופיעה כשרשור (reply) על ההודעה המקורית — סוף ל'הודעה שצצה משום מקום'
- נשמר מזהה הודעת-הטריגר הנכנסת (trigger_message_id) לכל relay
- תמיכה ב-quotedMessageId לאורך ה-adapter והשולח; חל על 5 תרחישי גישור
v01.141.000חדשתרחישי הבוט / הגדרותminorתרחישי הבוט — שליטה מלאה בביטויים שמפעילים כל תרחיש
עד כה במסך 'תרחישי הבוט' חלק מהביטויים שמפעילים תרחיש היו מובנים (קבועים, לא ניתנים להסרה) וחלק תוספות של הטננט.
פרטים נוספים ↓הסתר ↑
עד כה במסך 'תרחישי הבוט' חלק מהביטויים שמפעילים תרחיש היו מובנים (קבועים, לא ניתנים להסרה) וחלק תוספות של הטננט. כעת כל הרשימה ניתנת לעריכה: אפשר להסיר כל ביטוי, להוסיף ביטויים משלך, ולשחזר לברירת מחדל — כל טננט מגדיר לעצמו בדיוק מה מפעיל כל תרחיש. בתרחיש השידור (דטרמיניסטי) ההסרה אמיתית לחלוטין: הסרת מילת מפתח באמת מפסיקה להפעיל אותה, תוך שמירה על הכוונון מול false-positives (כמו ש'שדרות' לא נחשב 'שדר') לביטויים שנשארו. בתרחישי ה-AI כל ביטויי הטריגר הועברו מהקוד הקשיח אל הרשימה הניתנת לעריכה, והמסווג מופעל כעת אך ורק לפי הרשימה (תיאור התרחיש נשאר רק כהקשר ולמניעת התאמות שגויות — לא כטריגר): רשימה ריקה משביתה את התרחיש, והסרת ביטוי מסירה אותו כמקור טריגר (ניסוח או שגיאת-כתיב ברורה של ביטוי שנשאר עדיין תזוהה). הרשימות מאותחלות בברירת מחדל חזקה ומקיפה, וטננט שלא נוגע בהגדרות מקבל התנהגות זהה כמעט לחלוטין לקודמת.
- כל ביטוי טריגר ניתן להסרה — לא עוד ביטויים 'נעולים'
- כפתור 'החזר ברירת מחדל' לשחזור הביטויים המובנים
- שידור: רפקטור למשפחות מילות-מפתח (תווית + תבנית מכוונת) — הסרה אמיתית בלי לאבד הגנה מ-false-positives
- תרחישי AI: ביטויי הטריגר הוצאו מהקוד הקשיח — המסווג מופעל אך ורק לפי הרשימה הניתנת לעריכה (רשימה ריקה = תרחיש כבוי)
- אחסון בפורמט חדש (רשימה מלאה) עם תאימות-לאחור מלאה לנתונים קיימים
v01.140.000שיפורתיעוד ציבורי (/docs)minorתיעוד מלא של כל המערכת — 9 דפי תיעוד חדשים + הרחבות
התיעוד הציבורי ב-shipnest.io/docs הורחב כך שיכסה את כל מודולי המערכת, ולא רק את ליבת הלקוח/תפעול.
פרטים נוספים ↓הסתר ↑
התיעוד הציבורי ב-shipnest.io/docs הורחב כך שיכסה את כל מודולי המערכת, ולא רק את ליבת הלקוח/תפעול. נוספו 9 דפים חדשים: מחסן ו-3PL, עובדים ונוכחות ושכר, פיננסים, AI ובוט, אנליטיקה, אזורי הפצה וישובים, תפעול (ליקוט ובירורים), סוכנים, והגדרות וניהול. בנוסף הורחבו שלושה דפים קיימים: משלוחים (תצוגות מתקדמות — איסופים, מפה, יעד שבת/אקספרס, פערי הפצה, תמונת מחסן, סל מחזור), נהגים (ניתוח, התראות geofence, ושליחים מזדמנים), והודעות (תיבות נכנסות, היסטוריה ועלויות). הניווט בסיידבר אורגן מחדש לקבוצות (לקוחות ומכירות; שליחים, עובדים ומחסן; פיננסים ואנליטיקה; מערכת), ודף הבית של ה-docs עודכן עם כרטיסי המודולים החדשים. כל התוכן נגזר מקריאה ישירה בקוד, עם הבחנה כנה בין ששוחרר למה שעדיין בפיתוח.
- 9 דפים חדשים: מחסן/3PL, עובדים, פיננסים, AI/בוט, אנליטיקה, אזורי הפצה, תפעול, סוכנים, הגדרות
- הרחבת דפי משלוחים (תצוגות מתקדמות), נהגים (ניתוח/התראות/מזדמנים) והודעות (תיבות נכנסות/עלויות)
- ארגון מחדש של ניווט ה-docs ל-9 קבוצות, ועדכון כרטיסי דף הבית
- כיסוי מלא: כעת לכל מודול בסיידבר של האפליקציה יש דף תיעוד תואם
v01.139.006חדשמסרונים / Inboxמילוי אוטומטי של פרמטרי תבנית WhatsApp ב-Inbox
בשליחת תבנית Meta מאושרת לנמען מתוך תיבת הדואר הנכנס (/messages/inbox), השדות של הפרמטרים ({{destination_name}}, {{barcode}}, {{source_name}} וכו') כבר אינם ריקים — הם מתמלאים אוטומטית מהמשלוח האחרון של אותו נמען לפי שם …
פרטים נוספים ↓הסתר ↑
בשליחת תבנית Meta מאושרת לנמען מתוך תיבת הדואר הנכנס (/messages/inbox), השדות של הפרמטרים ({{destination_name}}, {{barcode}}, {{source_name}} וכו') כבר אינם ריקים — הם מתמלאים אוטומטית מהמשלוח האחרון של אותו נמען לפי שם המשתנה (destination_name → שם הלקוח, barcode → ברקוד, source_name → שם השולח, וכן שדות כתובת/יעד נוספים). כל שדה נשאר ניתן לעריכה, יש חיווי 'מולא אוטומטית מהמשלוח האחרון' וכפתור 'מלא מהמשלוח האחרון' למילוי חוזר. צד שרת: ה-API של ההודעות מחזיר כעת מפת variable→value שנבנית מהמשלוח התואם האחרון דרך buildVariables המשותף.
v01.139.005חדשאינטגרציות / DHLאינטגרציית DHL (SFTP) — שכבות הפורמט והתעבורה
תחילת אינטגרציה מול חלוקת last-mile של DHL דרך חילופי קבצי TXT ב-SFTP (פורמט Exp/Arr/Del מופרד ב-pipe).
פרטים נוספים ↓הסתר ↑
תחילת אינטגרציה מול חלוקת last-mile של DHL דרך חילופי קבצי TXT ב-SFTP (פורמט Exp/Arr/Del מופרד ב-pipe). נבנתה שכבת הפורמט הטהורה תחת lib/integrations/dhl/: כתיבת קובץ Exp (17 עמודות), פירוק קבצי Arr/Del כיומן אירועים (מיון לפי זמן והכרעת הסטטוס האחרון לכל שטר מטען), מיפוי סטטוסי הספק (OK/BA/NH/WC) לסטטוסים הקנוניים, ועזרי תאריך/טלפון/שם-קובץ — מאומת ב-12 בדיקות vitest מול קבצי הדוגמה האמיתיים. קוד תוסף בלבד שעדיין לא מחובר לזרימה; שלבי ההמשך (תעבורת SFTP, cron, קונפיג, חיבור לשיגור) ממתינים לתשובות הספק. בהמשך היום נבנתה גם שכבת התעבורה: לקוח SFTP (ssh2-sftp-client), קידוד Windows-1255/UTF-8, טעינת קונפיג מוצפן פר-tenant מ-TenantProviderConfig, אורקסטרציית סריקת inbox במצב dryRun בלבד (דיווח ללא שינוי סטטוסים), ושלד cron (טרם רשום ב-vercel.json). סה"כ 18 בדיקות vitest עוברות, אפס שגיאות טיפוסים.
v01.139.003ייעולביצועים / ממשק / יבואהאצת רשת יבוא המשלוחים — הקלדה חלקה גם ב-200 שורות
בעריכת תצוגת היבוא, הקלדה בתא בודד גרמה לרינדור מחדש של כל השורות הנראות (עד 200) ולחישוב מיקום כל שורה ב-findIndex (O(n) לכל שורה → O(n²) לכל תו), מה שהפך את ההקלדה ביבוא גדול לתקועה.
פרטים נוספים ↓הסתר ↑
בעריכת תצוגת היבוא, הקלדה בתא בודד גרמה לרינדור מחדש של כל השורות הנראות (עד 200) ולחישוב מיקום כל שורה ב-findIndex (O(n) לכל שורה → O(n²) לכל תו), מה שהפך את ההקלדה ביבוא גדול לתקועה. כעת: (1) שורת היבוא עטופה ב-React.memo כך שרק השורה שנערכה מתרנדרת מחדש (השאר נשארות יציבות מבחינת reference); (2) מיקום השורה מחושב מראש פעם אחת ל-Map (O(1) לכל שורה). אין שינוי בהתנהגות או בנתונים — רק הקלדה חלקה.
v01.139.002ייעולביצועים / פורטל / layoutהאצת טעינה — צמצום שאילתות כפולות בניווט (פורטל + ממשק צוות)
כל ניווט בפורטל הלקוח הריץ פעמיים את אותה שרשרת שאילתות (ה-layout וה-page כל אחד שלף בנפרד את היקף ההרשאות ואת קבוצת הלקוחות המקושרת).
פרטים נוספים ↓הסתר ↑
כל ניווט בפורטל הלקוח הריץ פעמיים את אותה שרשרת שאילתות (ה-layout וה-page כל אחד שלף בנפרד את היקף ההרשאות ואת קבוצת הלקוחות המקושרת). העטיפה ב-React cache() ממזגת אותן לקריאה אחת לכל בקשה — חיסוך של ~3 round-trips בכל ניווט בפורטל. במקביל, ב-layout של ממשק הצוות, שלושת בדיקות ה-feature-flags (מחסן, הצעות מחיר, חוזים) שלפו כל אחת בנפרד את הגדרות ה-tenant; כעת הן חולקות שליפה אחת ממוזגת (cache) — שלוש שאילתות לאחת. אין שינוי התנהגות — רק פחות round-trips ל-DB וטעינה מהירה יותר.
v01.139.001תיקוןבוט תרחישים / שידור + עדכוני לקוחבוט תרחישים — תיקוני אמינות (שידור רשימות + עדכון ללקוח)
שני תיקונים בבוט התרחישים בקבוצות הוואטסאפ.
פרטים נוספים ↓הסתר ↑
שני תיקונים בבוט התרחישים בקבוצות הוואטסאפ. (1) שידור רשימה: כשקבלן שולח בקבוצה רשימה של כמה משלוחים לשידור, הבוט שידר את הקיימים אך השמיט בשקט מהתשובה כל מספר שלא נמצא במערכת או שלא ניתן לשדר — כך שהקבלן לא ידע שמשלוח מסוים נכשל (למשל רשימה של 24508067 + 25644764 שהחזירה 'שודרו אליך 1 משלוחים' בלי לציין ש-24508067 לא נמצא). כעת התשובה המאוחדת מפרטת כל מספר שנשלח עם הסטטוס שלו (שודר / כבר משויך / כבר נמסר-הושלם / לא נמצא ❌ / לא ניתן לשדר), וכשאף משלוח לא נמצא מוצגת הודעה שמפרטת את כל המספרים; כפילות של אותו מספר עדיין מקובצת לשידור אחד. (2) דליפת טקסט-מטא ללקוח: בעדכוני 'אין מענה'/'כשל מסירה' התקציר של דיווח השליח נוצר ע"י מודל, וכשהקלט לא היה דיווח שליח בודד אלא רשימת מספרים, המודל החזיר לעיתים טקסט-מטא באנגלית ('I need the actual courier reports...') שדלף כמו-שהוא להודעה שנשלחה ללקוח. נוסף שומר שמוודא שהתקציר הוא עברית קצרה בלבד — אחרת חוזרים לנוסח גנרי ('אין מענה מהנמען') ושום טקסט פנימי/מטא לא מגיע ללקוח. (3) שידור שנכשל בשקט: כשקבלן ביקש לשדר משלוח שכבר נמסר/הושלם (אין לו משימת מסירה פעילה), או כשהשידור נכשל מסיבה אחרת — הבוט שתק לגמרי והקבלן לא ידע אם נשדר. כעת מוחזרת הודעה ברורה: 'אין משימת מסירה פעילה (ייתכן שכבר נמסר/הושלם/הוחזר)' או הודעת תקלה גנרית, לפי סיבת הכשל. (4) זיהוי 'לשים עלי': בקשת שידור בנוסח 'אפשר לשים עלי' (וכן 'שים עלי' / 'תשים עלי') לא זוהתה — אוצר המילים הכיר רק 'שימו עלי'/'לשבץ עלי' — כך שצילום מדבקה עם הכיתוב הזה לא שודר, ואף דולג כשנשלחה בקשה נוספת. הורחב הזיהוי לכל משפחת 'שים/לשים/תשים/לשום + עלי' ו-'שבץ/תשבץ/לשבץ + עלי', כולל צורות אות סופית. (5) חלון זמן ל-burst של קבוצת לקוח: ה'מטח' שהבוט סיווג נבנה מ'ההודעות מאז התגובה היוצאת האחרונה', אך הצוות שעונה מהטלפון האישי נספר כצד-הלקוח (לא כתגובה יוצאת), כך שללא הגבלת זמן שאלה ישנה נשארה ב'מטח' למשך ימים והפעילה את הבוט מחדש בכל הודעה חדשה לא-קשורה (שאלת צפי בת-4-ימים שוחררה לפתע ערב אחד). נוספה הגבלת חלון של 6 שעות — מטח אמיתי באותה שיחה ממשיך לעבוד, אך תוכן ישן כבר לא מפעיל את הבוט.
v01.139.000שיפורתיעוד ציבורי (/docs)minorתיעוד מלא — נכתבו 10 דפי התיעוד שהיו מסומנים 'בקרוב'
התיעוד הציבורי ב-shipnest.io/docs הושלם: כל הדפים שהיו מסומנים 'בקרוב' נכתבו במלואם, בעומק ובסגנון של דפי ה-API וה-CRM הקיימים.
פרטים נוספים ↓הסתר ↑
התיעוד הציבורי ב-shipnest.io/docs הושלם: כל הדפים שהיו מסומנים 'בקרוב' נכתבו במלואם, בעומק ובסגנון של דפי ה-API וה-CRM הקיימים. נוספו שני דפי התחלה (תחילת עבודה — חמשת הצעדים הראשונים מהתחברות ועד המשלוח הראשון; ומילון מונחים שמרכז את כל המושגים המרכזיים), חמישה דפי ליבה תפעולית (משלוחים, מעקב COD/גוביינא, לקוחות, נהגים ושיוך, ותבניות והודעות אוטומטיות), ושלושה דפי אינטגרציות (Lionwheel, Summit, WhatsApp Business). כל דף מבוסס על קריאה ישירה בקוד כדי לשקף את ההתנהגות בפועל — כולל הבחנה כנה בין יכולות ששוחררו לבין כאלה שעדיין בכתיבה (למשל אוטומציית מסמכים ב-Summit, אכיפת שעות פעילות בהודעות). בנוסף הוסרו סימוני 'בקרוב' מהסיידבר ומדף הבית, ותוקן ה-blurb של דף הלקוחות שהבטיח ייבוא ומיזוג כפילויות שאינם קיימים.
- התחלה: תחילת עבודה (5 צעדים) + מילון מונחים
- ליבה תפעולית: משלוחים, מעקב COD, לקוחות, נהגים ושיוך, תבניות והודעות אוטומטיות
- אינטגרציות: Lionwheel, Summit, WhatsApp Business (Meta Cloud API)
- התוכן נגזר מהקוד בפועל, עם הבחנה בין יכולות ששוחררו לבין כאלה בכתיבה; הוסרו סימוני 'בקרוב' מהניווט
v01.138.001חדשאיסופים / סינוןסינון איסופים לפי סוכן
בטבלת האיסופים (/pickups) נוסף ציר סינון חדש 'סוכן' בחלונית הפילטרים — לצד לקוח, עיר, אזור ושליח.
פרטים נוספים ↓הסתר ↑
בטבלת האיסופים (/pickups) נוסף ציר סינון חדש 'סוכן' בחלונית הפילטרים — לצד לקוח, עיר, אזור ושליח. הסוכן נגזר מהלקוח של המשלוח (customer → agent), כולל אפשרות 'ללא סוכן' למשלוחים שללקוח שלהם לא משויך סוכן. הספירות מתעדכנות חיה (faceted) ומשתלבות עם שאר הפילטרים הפעילים, בדיוק כמו שאר הצירים.
v01.138.000חדשלקוחות / אינטגרציית ליונווילminorיצירת לקוח גם בליונוויל + סנכרון עריכות
עד כה יצירת לקוח ב-Shipnest נשמרה רק מקומית, והקישור לליונוויל דרש ליצור את החברה ידנית בליונוויל ולהדביק את המזהה.
פרטים נוספים ↓הסתר ↑
עד כה יצירת לקוח ב-Shipnest נשמרה רק מקומית, והקישור לליונוויל דרש ליצור את החברה ידנית בליונוויל ולהדביק את המזהה. כעת בטופס הלקוח החדש נוסף מתג 'צור גם בליונוויל' (דלוק כברירת מחדל): כשהוא פעיל, נוצרת חברה תואמת בליונוויל עם השם, הטלפון, האימייל והכתובת של הלקוח, ומזהה החברה (lionwheelId) נשמר אוטומטית על הלקוח — כך שמשלוחים שלו ייקשרו מיד לחברה הנכונה. אם כבר הוזן מזהה ליונוויל ידני, המתג מושבת והלקוח פשוט מקושר לחברה הקיימת. בנוסף, עריכת שם/טלפון/כתובת/אימייל של לקוח שכבר מקושר לליונוויל דוחפת אוטומטית עדכון (PATCH) לחברה בליונוויל. כל הקריאות לליונוויל הן best-effort — כשל לא חוסם את השמירה המקומית, מוצגת התראה רכה והלקוח נשמר כרגיל.
- מתג 'צור גם בליונוויל' בטופס לקוח חדש, דלוק כברירת מחדל; מושבת כשהוזן מזהה ליונוויל קיים
- POST /companies יוצר את החברה בליונוויל ושומר את ה-lionwheelId על הלקוח אוטומטית
- עריכת שם/טלפון/כתובת/אימייל של לקוח מקושר מסנכרנת חזרה ב-PATCH /companies, תוך מיקוד ה-location הקיים כדי לא לכפול כתובות
- best-effort ולא-חוסם: כשל בליונוויל לא מונע שמירה מקומית; קוראים שאינם ה-UI (API ציבורי/ייבוא) לא מפעילים יצירה אלא אם ביקשו במפורש
v01.137.000חדשמחירון שליחים / חישוב עלויותminorמחירון שליחים — תשלום על כל איסוף בנפרד (פר חבילה)
במחירון השליח נוסף מתג 'תשלום על כל איסוף בנפרד'.
פרטים נוספים ↓הסתר ↑
במחירון השליח נוסף מתג 'תשלום על כל איסוף בנפרד'. עד כה כל איסוף עם 2+ משלוחים מאותו לקוח באותו יום קובץ אוטומטית ל'איסוף עסקי' — תשלום סמלי אחד שמתחלק בין המשלוחים. כעת, לשליחים שמקבלים על איסוף כמו על מסירה, אפשר להפעיל את המתג כך שכל איסוף משולם בנפרד לפי תעריף 'איסוף רגיל' (פר חבילה, כולל תוספת חבילה נוספת), גם כשנאספו כמה משלוחים מאותו לקוח באותו יום — בלי קיבוץ. הדגל נשמר פר-שליח, וכל עלויות האיסוף ההיסטוריות שלו מחושבות מחדש ברקע עם השמירה. ברירת המחדל ללא שינוי (קיבוץ לאיסוף עסקי).
- מתג פר-שליח בדיאלוג המחירון — מבטל את קיבוץ ה'איסוף עסקי' עבורו
- במצב פעיל כל איסוף משולם לפי pickupRate + תוספת חבילה נוספת (פר חבילה), כמו איסוף רגיל
- עקבי לאורך כל מנועי החישוב — דוח חודשי, סנפשוט עלות איסוף ופירוט סאב-שליחים
- חישוב מחדש רטרואקטיבי של עלויות האיסוף עם שמירת המחירון
v01.136.001ייעולביצועים / ממשקהאצת ממשק — טעינה ראשונית קלה יותר ופחות רינדורים
סדרת שיפורי מהירות כירורגיים בנקודות נבחרות, בלי שינוי התנהגות: (1) בורר האימוג'ים (emoji-picker-react, מאגר נתונים גדול) ב-inbox וב-business-inbox נטען כעת lazy — רק כשפותחים את הבורר — במקום להיכלל ב-JS של הטעינה הראשו…
פרטים נוספים ↓הסתר ↑
סדרת שיפורי מהירות כירורגיים בנקודות נבחרות, בלי שינוי התנהגות: (1) בורר האימוג'ים (emoji-picker-react, מאגר נתונים גדול) ב-inbox וב-business-inbox נטען כעת lazy — רק כשפותחים את הבורר — במקום להיכלל ב-JS של הטעינה הראשונית של המסכים הנפתחים ביותר. (2) גרף לוח-הבקרה בפורטל (recharts) נטען lazy אחרי כרטיסי ה-KPI, כך שדף הבית של הלקוח מגיב מהר יותר. (3) ברשימת המשלוחים, כפתור הרענון שמועבר לשורות הפך ל-callback יציב — סימון שורה או עדכון real-time כבר לא מרנדר מחדש את כל הרשימה אלא רק את השורה שהשתנתה. (4) הופעל optimizePackageImports (lucide-react, date-fns, recharts, react-day-picker) ל-tree-shaking טוב יותר של אייקונים בכל route. נבדק: typecheck נקי, build תקין, 1029 בדיקות יחידה עוברות.
v01.136.000תיקוןPublic REST API / פורטל לקוחות / Webhooksminorבידוד מפתחות API של פורטל הלקוח — מפתח של לקוח לא נוגע בלקוח אחר
מפתח API שמונפק דרך פורטל הלקוח (/portal/settings/api) היה מוגבל עד כה ל-Tenant בלבד — כך שלקוח אחד יכול היה לקרוא ולערוך משלוחים, לקוחות ומנויי webhook של כל שאר לקוחות ה-Tenant דרך ה-REST API הציבורי.
פרטים נוספים ↓הסתר ↑
מפתח API שמונפק דרך פורטל הלקוח (/portal/settings/api) היה מוגבל עד כה ל-Tenant בלבד — כך שלקוח אחד יכול היה לקרוא ולערוך משלוחים, לקוחות ומנויי webhook של כל שאר לקוחות ה-Tenant דרך ה-REST API הציבורי. מעתה כל מפתח כזה נכבל אוטומטית ללקוח שהנפיק אותו (ולסאב-לקוחות המקושרים שלו בלבד): כל endpoints ה-v1 מסננים את הקריאה והכתיבה לקבוצת הלקוחות המורשית בלבד, יצירת לקוח דרך POST /customers נוצרת כסאב-לקוח של אותו לקוח, ומנויי webhook מקבלים אך ורק events שהמשלוח/לקוח שמאחוריהם שייך לאותה קבוצה (סינון פר-לקוח ב-emit, fail-closed). מפתחות ברמת ה-Tenant שמונפקים על ידי הצוות ממשיכים לראות את כל נתוני ה-Tenant ללא שינוי.
- ApiKey ו-WebhookSubscription נושאים customerId — מפתח/מנוי של פורטל מצומצם ללקוח שלו + הסאב-לקוחות המקושרים
- GET/PATCH/cancel למשלוחים ולקוחות מסוננים ל-allowedCustomerIds; ניסיון לגעת בלקוח מחוץ לקבוצה מחזיר 404/403
- POST /customers ממפתח פורטל יוצר סאב-לקוח (parentCustomerId), POST /shipments מחויב customerId בתוך הקבוצה
- מסירת webhook מסוננת פר-לקוח — events של לקוחות אחרים לא נמסרים למנוי של לקוח (fail-closed כשלא ניתן לשייך)
- מפתחות ברמת Tenant (צוות) ללא שינוי — גישה מלאה כבעבר
v01.135.000חדשבוט קבוצות / תרחישי WhatsAppminorבוט השידור — שידור רצף תמונות במכה אחת לפי מילת מפתח
תרחיש 'בקשת שידור' מבין כעת רצף של תמונות מדבקה כבקשה אחת: כשהקבלן שולח כמה תמונות וכותב מילת שידור (לשדר/שדר/תשדרו...) על אחת מהן או בהודעה נפרדת — לפני הרצף, אחריו או בתוכו — הבוט משדר את כל המשלוחים שזוהו ומשיב בהודעה…
פרטים נוספים ↓הסתר ↑
תרחיש 'בקשת שידור' מבין כעת רצף של תמונות מדבקה כבקשה אחת: כשהקבלן שולח כמה תמונות וכותב מילת שידור (לשדר/שדר/תשדרו...) על אחת מהן או בהודעה נפרדת — לפני הרצף, אחריו או בתוכו — הבוט משדר את כל המשלוחים שזוהו ומשיב בהודעה אחת מאוחדת ('שודרו אליך N משלוחים ✅' עם רשימת מספרי השידור). תמונה בתוך הרצף שכתוב עליה משהו אחר (למשל 'אין מענה') לא תשודר — רק היא יוצאת מהכלל; ומספר משלוח שצוין לצד מילת השידור (בטקסט) משודר גם הוא. כדי לזהות רצף, נתיב קבוצות-השליח עבר לאיחוד-מטח (debounce 8 שניות) עם חלון 20 דקות שמונע שידור בטעות של תמונות ישנות שהצטברו. ארכיטקטונית, השידור הופרד לנתיב דטרמיניסטי נפרד — תרחישי הגישור (אין מענה/כתובת/טלפון) נשארו פר-הודעה כך שדיווחים על כמה משלוחים שונים ברצף אחד לא נדרסים. מספרי טלפון מסוננים כך שלא יזוהו כמספרי משלוח.
- מילת שידור במקום כלשהו ברצף (כיתוב על תמונה או הודעה נפרדת) חלה על כל התמונות ברצף
- תשובה אחת מאוחדת — תבנית חדשה success_multi ('שודרו אליך {count} משלוחים ✅' + רשימה), ניתנת לעריכה בהגדרות
- תמונה עם טקסט אחר משלה (הוראה שונה) מוחרגת מהשידור — שאר התמונות משודרות
- השידור הופרד לנתיב דטרמיניסטי נפרד; תרחישי הגישור נשארו פר-הודעה ולא נדרסים ברצף רב-משלוחי
- סינון מספרי טלפון (לא יזוהו כמשלוח) + תקרה של 8 משלוחים בבת אחת + חלון 20 דקות
v01.134.000חדשבוט קבוצות / תרחישי WhatsApp / הגדרותminorביטויי מפתח לתרחישי הבוט — ניתנים לעריכה בהגדרות
בדף 'תרחישי הבוט', דיאלוג 'ערוך נוסח' של כל תרחיש קיבל סקציה חדשה — 'ביטויים שמפעילים את התרחיש'.
פרטים נוספים ↓הסתר ↑
בדף 'תרחישי הבוט', דיאלוג 'ערוך נוסח' של כל תרחיש קיבל סקציה חדשה — 'ביטויים שמפעילים את התרחיש'. עד כה אוצר מילות-המפתח שמפעיל כל תרחיש היה קבוע בקוד; כעת מוצגים הביטויים המובנים (לקריאה בלבד) ואפשר להוסיף ביטויים משלך לכל תרחיש — בלי קוד. הביטויים שמוסיפים מוזנים למסווג ה-AI (לכל התרחישים), ובתרחיש 'בקשת שידור' גם לשער הדטרמיניסטי שמאשר את הזיהוי. כך, למשל, אפשר לחדד את תרחיש 'טלפון שגוי' בעצמך ('מספר לא פעיל', 'יש 11 ספרות' וכו') או להוסיף ניסוחי שידור מקומיים של קבלן מסוים. הביטויים נשמרים פר-חברה, מנוקים (trim/כפילויות, עד 40), ואינם כופלים את הביטויים המובנים.
- סקציית 'ביטויים שמפעילים את התרחיש' בדיאלוג עריכת הנוסח — צ'יפים מובנים לקריאה + הוספה/הסרה של ביטויים משלך
- הביטויים מוזנים למסווג ה-AI לכל התרחישים, ולשער הדטרמיניסטי של 'בקשת שידור'
- נשמר פר-חברה ב-botScenarios.triggerPhrases (מנוקה, עד 40, ללא כפילות של ביטוי מובנה)
- מאפשר לחדד תרחישים (למשל 'טלפון שגוי' עם 'מספר לא פעיל') ללא שינוי קוד
v01.133.006תיקוןAI / בדיקות מסירההערת מסירה אוטומטית של בוט בדיקות-המסירה — רק הנחיות לשליח, בלי דריסה ובלי תובנות פנימיות
בוט בדיקות-המסירה (cron ai-delivery-sessions) שמטפל בשיחות WhatsApp מול הנמען היה כותב לשדה 'הערת יעד' (destinationNotes — שמודפס על המדבקה ומסונכרן לליונוויל) גם תובנות תפעוליות פנימיות שאינן נוגעות לשליח — כמו 'המשלוח …
פרטים נוספים ↓הסתר ↑
בוט בדיקות-המסירה (cron ai-delivery-sessions) שמטפל בשיחות WhatsApp מול הנמען היה כותב לשדה 'הערת יעד' (destinationNotes — שמודפס על המדבקה ומסונכרן לליונוויל) גם תובנות תפעוליות פנימיות שאינן נוגעות לשליח — כמו 'המשלוח יצא להפצה והיום הוא יום ההפצה האחרון לפי ההתחייבות' — וגם דרס את ההערה הקיימת בכל סבב שיחה במקום לשמרה. הסיבה: פעולת update_notes הוגדרה ב-prompt כטקסט חופשי ללא גבולות, והקוד החיל אותה כדריסה מלאה (destinationNotes = value). כעת ה-prompt מגדיר את ההערה כהנחיית מסירה לשליח בלבד: מותר רק פרטי גישה/טיפול/העדפת זמן שמסייעים בפועל למסירה (קוד כניסה, להשאיר עם שכן, עדיפות בוקר, חוסר זמינות + בקשת תיאום), ואסור במפורש סטטוס משלוח, ימי-הפצה/SLA, מועד התחייבות או נימוקים פנימיים. בנוסף הבוט מונחה לשמר את ההערה הקיימת ולהוסיף רק פרט חדש (מיזוג, לא החלפה), ולא לפלוט update_notes כלל אם אין פרט חדש רלוונטי לשליח. נוסף שומר בקוד שמונע מחיקת הערה קיימת ע"י ערך ריק.
v01.133.005תיקוןבוט קבוצות / תרחישי WhatsAppבוט השידור — שידור רק על מילת מפתח מפורשת
תרחיש 'בקשת שידור' של בוט הקבוצות עבר לדרישת מילת שידור מפורשת בכל מקרה.
פרטים נוספים ↓הסתר ↑
תרחיש 'בקשת שידור' של בוט הקבוצות עבר לדרישת מילת שידור מפורשת בכל מקרה. מספר משלוח בודד או צילום מדבקה בודד כבר לא מפעילים שידור בעצמם — רק מילה כמו 'לשדר', 'שדר', 'שדרו', 'שימו עלי', 'לא משודר', 'לא נסרק' וכו' (אפשר לצרף לצידה מספר או צילום). זה תיקן תקלות שדווחו בקבוצות שבהן קבלן הדביק מספר משלוח לצורך אחר (הפניה, דיווח על טלפון שגוי) והבוט ענה בטעות 'המשלוח כבר משויך אליך' או 'לא מצאתי משלוח'. רשימת מילות-המפתח כבר מחוזקת בגבולות-מילה עבריים כך ש'שדרות'/'משודרג' אינם נחשבים.
v01.133.004תיקוןשיבוץ איסופיםסינון לפי שליח איסוף — הטבלה התרוקנה למרות שהמונה הראה משימות
בדף שיבוץ האיסופים, בחירת שליח איסוף מתוך הפילטר רוקנה את הטבלה לגמרי ('אין משימות איסוף פתוחות') למרות שליד שם השליח הופיע מונה נכון (למשל 'דוד בהר — 24').
פרטים נוספים ↓הסתר ↑
בדף שיבוץ האיסופים, בחירת שליח איסוף מתוך הפילטר רוקנה את הטבלה לגמרי ('אין משימות איסוף פתוחות') למרות שליד שם השליח הופיע מונה נכון (למשל 'דוד בהר — 24'). הסיבה: שם השליח שמוצג במונה נבנה בביטוי SQL אחד (TRIM לכל חלק + רווח בודד, עם נפילה ל'ליונוויל #<id>'), אבל כשלוחצים על השם, ה-WHERE שמסנן את הטבלה שיחזר את השם בביטוי שונה (TRIM(CONCAT(...))) — כך ששליח עם רווח מיותר ב-firstName (למשל 'דוד ' + 'בהר' → המונה מציג 'דוד בהר' אבל הסינון יצר 'דוד בהר' עם רווח כפול) או שליח עם שם ליונוויל-בלבד מעולם לא הותאם, והטבלה התרוקנה. כעת שני הצדדים — בניית התצוגה והתאמת הסינון — משתמשים באותו ביטוי SQL יחיד (driverDisplayNameSql) בכל שלושת ה-endpoints (טבלה, מפה, מוני הפילטר), כך שהתאמה מובטחת. אומת מול נתוני פרודקשן: לפני התיקון הסינון החזיר 0 שליחים לטוקן 'דוד בהר'; אחריו הוא מתאים את השליח ואת 30 משימות האיסוף הפתוחות שלו. בנוסף: כפתור ה-X להסרת השליח המשובץ בתיבת השיבוץ הופיע רק אצל שליחים שנמצאים ברשימת השליחים הפעילים — שליח משובץ שסונן מהרשימה (לא-פעיל / ליונוויל-בלבד) הציג את שמו אך ללא כפתור הסרה. כעת הכפתור מותנה בקיום שיבוץ בלבד ולכן מופיע אצל כל שליח משובץ. כמו כן, אייקון החיפוש שמוצג בתיבת השיבוץ כשאין שליח משובץ הוצג עם רקע אפור (bg-muted) שבלט מול הדף — הוסר הרקע כך שהאייקון נטמע בעיצוב (נשאר רק המסגרת, בדומה לכפתור ה-X). התיקון הוחל על כל מופעי תיבת שיבוץ השליח במערכת — לא רק בדף שיבוץ האיסופים אלא גם בכרטיסי המשימות של עמוד המשלוח (TasksCard ו-ShipmentTasks) ובדיאלוג השיבוץ הקבוצתי, וגם על אייקון בורר התאריך הצמוד באותן שורות כדי לשמור על אחידות.
v01.133.003שיפורAI / דיוקדיוק סיווגי ה-AI — פלט דטרמיניסטי (temperature=0)
כל הקלסיפיירים וה-extractors של ה-AI (סיווג הודעות שליח, אישור מסירה, OCR ברקוד, חילוץ הנחיות מסירה, תיקון ומיפוי יבוא, וכריית תובנות) רצו עד כה ב-temperature ברירת-מחדל (~1.0) — כלומר אותה הודעה יכלה להתקבל אחרת בהרצות …
פרטים נוספים ↓הסתר ↑
כל הקלסיפיירים וה-extractors של ה-AI (סיווג הודעות שליח, אישור מסירה, OCR ברקוד, חילוץ הנחיות מסירה, תיקון ומיפוי יבוא, וכריית תובנות) רצו עד כה ב-temperature ברירת-מחדל (~1.0) — כלומר אותה הודעה יכלה להתקבל אחרת בהרצות שונות. כעת הם רצים ב-temperature=0: לכל קלט המודל מחזיר את התשובה הכי-סבירה, באופן עקבי ומדויק יותר. אפס שינוי בעלות (אותם טוקנים) וללא נגיעה בלוגיקת הבוט. שיפור אפקטיביות ישיר — פחות סיווגים אקראיים שגויים.
v01.133.002שיפורAI / משלוחיםעוזר ה-AI מאתר משלוחים גם לפי מזהה נכנס / יוצא (איסוף ומסירה)
עד כה חיפוש המשלוחים של עוזר ה-AI הכיר רק את הברקוד הראשי (וכן שם, עיר, רחוב, public_id), ולא ידע לאתר משלוח לפי מזהי ה-partner — מזהה נכנס (originPartnerTaskId), מזהה יוצא לאיסוף (pickupOutboundTaskId) ומזהה יוצא למסירה…
פרטים נוספים ↓הסתר ↑
עד כה חיפוש המשלוחים של עוזר ה-AI הכיר רק את הברקוד הראשי (וכן שם, עיר, רחוב, public_id), ולא ידע לאתר משלוח לפי מזהי ה-partner — מזהה נכנס (originPartnerTaskId), מזהה יוצא לאיסוף (pickupOutboundTaskId) ומזהה יוצא למסירה (targetPartnerTaskId) — כך שמשלוחים שהגיעו מספק מקור או שודרו לקבלן חיצוני לא נמצאו לפי המזהה שהמשתמש מכיר. כעת שלושת המזהים נוספו גם לחיפוש הטקסט החופשי (searchShipments/countShipments) וגם לשליפת פרטי משלוח בודד (getShipmentDetails): כל מזהה שהמשתמש מקליד נפתר מול כל עמודות המזהה. שינוי additive בלבד — חיפוש לפי ברקוד נשאר זהה.
v01.133.001ייעולDB / משלוחים / ביצועיםסטטוס המשלוח קודם לעמודה מאונדקסת (במקום probe ל-JSON)
סטטוס המסירה הקנוני של משלוח, שהיה כלוא בשדה JSON (additionalData.status) ונדרש סינון עם OR על מספר ייצוגים ללא אינדקס, קודם לעמודת 'status' מאונדקסת.
פרטים נוספים ↓הסתר ↑
סטטוס המסירה הקנוני של משלוח, שהיה כלוא בשדה JSON (additionalData.status) ונדרש סינון עם OR על מספר ייצוגים ללא אינדקס, קודם לעמודת 'status' מאונדקסת. העמודה מתעדכנת אוטומטית ע"י trigger ב-DB מתוך additionalData.status (שנשאר מקור-האמת), כך שאף נתיב כתיבה באפליקציה לא משתנה. בוצע backfill ל-185,756 השורות הקיימות (0 אי-התאמות), נוצר אינדקס (tenantId, status, createdAt), ומשלוח חסר-סטטוס (יבוא מחסן/API ציבורי) מנורמל כעת ל-UNASSIGNED — מה שמסיר באג ידוע שבו סטטוס NULL הסתיר משלוחים מסינונים. כשלב המשך, שאילתות הסטטוס בפורטל הלקוחות (רשימת המשלוחים, לוח הבקרה וכרטיס הלקוח) עברו כעת לקרוא מהעמודה המאונדקסת במקום מה-JSON — סינון מהיר ומאונדקס. שאר נתיבי הקריאה (אנליטיקה, ליקוט, סנכרון) יעברו בהדרגה.
v01.133.000חדשAI / עלות / בוט קבוצותminorמכסת AI חינמית יומית (1$ לטננט) + באנר התראה
ה-AI האוטונומי שרץ על מפתח ה-AI החינמי של Shipnest (בוט הקבוצות: סיווג תרחישים, שער רלוונטיות, חילוץ תובנות, OCR לתמונות, וסוכן הלקוח ב-1:1) מוגבל כעת ל-1$ ביום פר-טננט.
פרטים נוספים ↓הסתר ↑
ה-AI האוטונומי שרץ על מפתח ה-AI החינמי של Shipnest (בוט הקבוצות: סיווג תרחישים, שער רלוונטיות, חילוץ תובנות, OCR לתמונות, וסוכן הלקוח ב-1:1) מוגבל כעת ל-1$ ביום פר-טננט. כשהמכסה נגמרת, ה-AI האוטונומי משתתק לשארית היום (התנהגות ברירת-המחדל הבטוחה של הבוט) ומופיע באנר קבוע בראש האפליקציה שמסביר שעברת את המכסה היומית החינמית ומפנה ל'הגדרות ← ספק AI' לחיבור מפתח משלך. טננט שמחבר מפתח משלו אינו מוגבל כלל, והבאנר נעלם מיידית. צ'אט ה-AI האינטראקטיבי שומר על מכסת ההודעות החינמית הנפרדת שלו ללא שינוי. תמלול (Whisper) משתמש תמיד במפתח של הטננט ולכן אינו מושפע.
- תקרת עלות 1$/יום פר-טננט על מפתח המערכת, מבוססת על ai_usage_event הקיים (בלי טבלה/אינדקס חדשים)
- אכיפה בנקודות שיודעות keySource: מנוע התרחישים (classifier/relay/insight), OCR, וסוכן הלקוח 1:1 — רק כשהמפתח הוא של המערכת
- חסימה = שתיקה (לא שבירה): הודעות עדיין נשמרות, רק התשובה/הסיווג האוטומטי מדולגים; הבדיקה fail-open על תקלת DB
- באנר קבוע בראש האפליקציה עם קישור ל-/settings/ai-provider; נעלם ברגע שמוגדר מפתח עצמי
- איפוס יומי בחצות UTC (~02:00–03:00 שעון ישראל), עקבי עם מכסת הצ'אט הקיימת
v01.132.000שיפורמדבקות / פורטל לקוחותminorלוגו מדבקה: ירושה מהחשבון הראשי וזהות מלאה בין הפורטל לממשק הניהול
המשך פיצ'ר הלוגו לכל סאב-לקוח.
פרטים נוספים ↓הסתר ↑
המשך פיצ'ר הלוגו לכל סאב-לקוח. (1) ירושת לוגו: חשבון מקושר ללא לוגו משלו מדפיס כעת אוטומטית את הלוגו של החשבון הראשי (האב), כך שלקוח-אב שמגדיר לוגו אחד מקבל מיתוג אחיד לכל הקבוצה — וניתן עדיין להגדיר לוגו ייעודי לכל סאב-לקוח שמבטל את הירושה. (2) זהות מלאה בין מסלולי המדבקה: הלוגו שהלקוח מעלה בפורטל משמש כעת בכל מסלולי ההדפסה של הטננט (הצוות) — מדבקה בודדת, הדפסה מרובה/ליקוט ולינק שיתוף — דרך הלפר מרכזי משותף. (3) תוקן פער שבו לינק שיתוף של מדבקה בודדת לא כלל כלל את לוגו הלקוח. (4) בעמוד הגדרות הלוגו בפורטל מוצג כעת הלוגו המורש (בעמעום קל עם הסבר) לחשבונות ללא לוגו משלהם. (5) הלוגו מוצג כעת גם בצד הצוות — בטבלת הלקוחות (אווטאר השם) ובכותרת דף הלקוח — וניתן לערוך אותו ישירות מדף הלקוח (כפתור 'לוגו': העלאה/החלפה/הסרה) דרך endpoint חדש מאובטח בהרשאת עריכת לקוחות.
- ירושת לוגו: סאב-לקוח ללא לוגו משלו מדפיס את הלוגו של החשבון הראשי (האב); הגדרת לוגו ייעודי מבטלת את הירושה
- הלוגו שהלקוח מעלה משמש בכל מסלולי המדבקה של הטננט/צוות — בודד, מרובה (ליקוט / share-bulk) ולינק שיתוף
- תיקון: לינק שיתוף של מדבקה בודדת לא הציג את לוגו הלקוח — כעת מוצג (כולל ירושה)
- ריכוז הלוגיקה בהלפר משותף (effectiveLabelLogoUrl + select אחיד) על פני כל מסלולי המדבקה
- עמוד הגדרות הלוגו בפורטל מציג לוגו מורש בעמעום עם הסבר 'יורש את הלוגו מהחשבון הראשי'
- צד הצוות: לוגו הלקוח מוצג בטבלת הלקוחות (אווטאר עמודת השם) ובכותרת דף הלקוח, עם נפילה חזרה לאייקון כשאין לוגו
- צד הצוות: עריכת לוגו לקוח ישירות מדף הלקוח (כפתור 'לוגו') — העלאה/החלפה/הסרה דרך endpoint חדש /api/customers/[id]/logo, מאובטח בהרשאת עריכת לקוחות (CUSTOMERS_EDIT) ומתועד ב-audit log
v01.131.004שיפורבחירת שעה (UI) / הגדרות AI / נוכחותבורר שעה מותאם (TimePicker) — עיצוב מחדש לשעות הפעילות והטמעה בכל המערכת
סקציית 'שעות פעילות' בהגדרות ה-AI עוצבה מחדש.
פרטים נוספים ↓הסתר ↑
סקציית 'שעות פעילות' בהגדרות ה-AI עוצבה מחדש. בורר השעה הנייטיבי של הדפדפן (input type=time) — שאייקון השעון המובנה שלו חפף לטקסט השעה ולא ניתן לעיצוב — הוחלף ב-TimePicker משותף חדש: Popover עם עמודות שעה/דקה נגללות, בסגנון ה-DatePicker הקיים. הטבלה הגנרית עם ה-checkbox הגולמי הוחלפה ברשימת ימים נקייה עם מתג צ'ק מעוצב לכל יום, ימים סגורים מסומנים בבירור, וכפתור 'החל על כל הימים' להעתקת שעות יום אחד לכל הימים הפתוחים. בהמשך, אותו TimePicker הוטמע בכל שאר מקומות בחירת השעה במערכת במקום בורר השעה הנייטיבי: דיווח משמרת רטרואקטיבי (עובד), הוספת משמרת, רישום עובדים מזדמנים, ובוחר התאריך+שעה של משימות אדמין. אין שינוי בנתונים הנשמרים או ב-API.
v01.131.003ייעולAI / עלויותהוזלת עלות ה-AI — prompt caching, מטרינג מלא וניקוי
ה-prefix הקבוע של סוכני ה-AI (הוראות המערכת + הגדרות 23 הכלים) נשלח מחדש בכל סבב כלי ובכל תור בשיחה, וחויב במחיר מלא.
פרטים נוספים ↓הסתר ↑
ה-prefix הקבוע של סוכני ה-AI (הוראות המערכת + הגדרות 23 הכלים) נשלח מחדש בכל סבב כלי ובכל תור בשיחה, וחויב במחיר מלא. כעת הוא נשמר ב-cache (cache_control ephemeral), כך שבקריאות חוזרות בתוך החלון הוא מחויב ב-~0.1× במקום מחיר מלא — הוזלה ניכרת בעלות הקלט, ללא כל שינוי בפלט או בהתנהגות המודל. מודל ברירת המחדל נשאר Haiku, כך שאף לקוח לא משלם יותר. במקביל נוספה תשתית adaptive thinking שמופעלת אך ורק עבור לקוחות שבחרו ידנית מודל חזק (Sonnet/Opus) — היא הופכת את המודל שכבר בחרו לחכם יותר, בלי להעלות את עלות ברירת המחדל לאף אחד. כל הספקים שאינם Anthropic (Google/OpenAI-תואם) ולקוחות עם מודל נעול — ללא שינוי כלל. בנוסף, מסווג שירות-הלקוחות ב-WhatsApp — ה-prompt הסטטי הגדול ביותר ובנפח הקריאות הגבוה ביותר — עבר אף הוא ל-prompt caching (הוזלת קלט של ~85-90% בקריאות חוזרות). שלוש קריאות AI שלא נמדדו עד כה (המסווג, חילוץ כתובת מתשובת לקוח, ודייג התובנות השעתי) חוברו למטרינג כך שעלותן נראית בלוח הבקרה — עם שיוך מדויק של 'מפתח הלקוח מול מפתח המערכת'. תקרת הטוקנים של המסווג הוקטנה מ-8192 ל-4096 (הגנת runaway עם מרווח בטוח לתשובה ארוכה), וקובץ AI מת (ai-delivery-parser) הוסר. בנוסף, בנתיב קבוצות-השליחים (הנפח הגבוה ביותר) בוטל סיווג-Haiku כפול ללמידה: הודעות ללא אוצר-מילים של דיווח-מסירה — או דיווח 'אין מענה' חד-משמעי — מטופלות כעת דטרמיניסטית ומדלגות על קריאת הסיווג, ללא כל נגיעה בלוגיקת הבוט (התרחישים והפעולות נשארו זהים). נוספו שני בלמי-עלות נוספים: תמלול קולי (Whisper, חיוב לדקה) חוסם כעת קבצים גדולים חריגים (מעל 10MB — הרבה מעבר להודעה קולית רגילה), וכריית התובנות (גם בזמן-אמת וגם ב-digest השעתי) נעצרת ל-tenant שצבר ערימה גדולה של תובנות-pending שלא נסקרו — ומתחדשת אוטומטית כשהתור מתפנה. אף אחד מהשינויים אינו משפיע על tenant חדש או על מי שמשתמש בפיצ'ר בפועל.
v01.131.002תיקוןאבטחה / משלוחים / הרשאות / SSRFחיזוק אבטחה — בידוד נתוני משלוח ושלילת גישה מהירה
ה-API של משלוח בודד (צפייה, עריכה, שינוי סטטוס וסטטוס-תפעול, סטטוס החזרה והלוך-חזור, חילוץ AI ועדכון ביקור) חוזק כך שכל גישה למשלוח מוגבלת במפורש לארגון של המשתמש המחובר; בקשה למזהה שאינו שייך לארגון מחזירה כעת 'לא נמצא'…
פרטים נוספים ↓הסתר ↑
ה-API של משלוח בודד (צפייה, עריכה, שינוי סטטוס וסטטוס-תפעול, סטטוס החזרה והלוך-חזור, חילוץ AI ועדכון ביקור) חוזק כך שכל גישה למשלוח מוגבלת במפורש לארגון של המשתמש המחובר; בקשה למזהה שאינו שייך לארגון מחזירה כעת 'לא נמצא' (404) במקום לטעון נתונים. בנוסף, משתמש צוות שהושבת או שתפקידו שונה מאבד כעת את ההרשאות באופן כמעט-מיידי (עד דקה) במקום להמתין לפקיעת ההתחברות. כמו כן, כתובות URL של webhooks יוצאים ושל ספקי AI מאומתות כעת כך שלא ניתן להפנותן לכתובת רשת פנימית/שמורה (הגנת SSRF), ובקשות יוצאות כאלה נחסמות גם בזמן השליחה. אין שינוי בחוויית המשתמש עבור גישה לגיטימית — רק חיזוק הבידוד בין ארגונים, ההרשאות, והבקשות היוצאות.
v01.131.001ייעולאינטגרציות / ש.נ.ל / שידור משלוחיםהאצת שידור משלוחים ל-ש.נ.ל — עיבוד מקבילי
שידור אצווה ל-ש.נ.ל עיבד עד כה את המשלוחים אחד-אחרי-השני, כך ששידור של עשרות משלוחים נמשך דקות — וקריאת API איטית או שנתקעת עד ה-timeout (15 שניות) חסמה את כל שאר המשלוחים בתור.
פרטים נוספים ↓הסתר ↑
שידור אצווה ל-ש.נ.ל עיבד עד כה את המשלוחים אחד-אחרי-השני, כך ששידור של עשרות משלוחים נמשך דקות — וקריאת API איטית או שנתקעת עד ה-timeout (15 שניות) חסמה את כל שאר המשלוחים בתור. כעת המשלוחים מעובדים במקביל ב-pool תחום (5 בו-זמנית), מה שמקצר משמעותית את זמן השידור ומונע ממשלוח בודד תקוע לעכב את כל האצווה. בנוסף, כשל בעיבוד משלוח יחיד (למשל תקלת DB אחרי שה-API הצליח) מבודד כעת לאותו משלוח בלבד במקום להפיל את כל האצווה. סדר התוצאות המוזרמות ל-UI נשמר עקבי, והתקרה נשמרת נמוכה כדי לא לחרוג ממגבלות הקצב של ש.נ.ל ו-Lionwheel.
v01.131.000חדשמחירון לקוחות / תמחור / יבוא אקסלminorמודל הנחה לחבילה נוספת — וחיבורו לחיוב המשלוח בפועל
מחיר החבילות הנוספות עבר ממודל 'מחיר נפרד' למודל 'הנחה': חבילה מהשנייה והלאה מתומחרת כמחיר הבסיס פחות הנחה.
פרטים נוספים ↓הסתר ↑
מחיר החבילות הנוספות עבר ממודל 'מחיר נפרד' למודל 'הנחה': חבילה מהשנייה והלאה מתומחרת כמחיר הבסיס פחות הנחה. ההנחה מוגדרת כסכום ב-₪: הנחה כללית לכל חבילה נוספת, ובנוסף עוקפים ייעודיים פר-אינדקס (חבילה שנייה, שלישית, …) שנוספים בלחיצת '+'. אינדקס ללא עוקף מקבל את ההנחה הכללית; ברירת המחדל (ללא הנחה) היא מחיר בסיס מלא. במקביל תוקן פער מהותי: מנגנון הטירים הקודם כלל לא היה מחובר לחיוב המשלוח בפועל (הפונקציה getPackagePrice מעולם לא נקראה, והחיוב נשען על שדה ישן שאף מסך לא הגדיר) — כעת ההנחות מוטמעות ב-computeAutoSurcharges ומשפיעות על תוספת 'חבילה נוספת' בכל משלוח. ⚠️ שינוי התנהגות: מרגע ההטמעה, חבילות נוספות מתומחרות (מחיר בסיס פחות הנחה) במקום שלא להוסיף דבר כפי שהיה בפועל — יש לוודא שמחירוני הלקוחות מעודכנים. ההגדרה זמינה בדיאלוג המחירון (סקציית 'חבילות נוספות (הנחה)') וב-3 עמודות חדשות בקובץ יבוא האקסל.
- מודל הנחה: חבילה נוספת = מחיר בסיס − הנחה (₪). הנחה כללית + עוקפים פר-אינדקס; אינדקס ללא עוקף → הכללי; ברירת מחדל = מחיר בסיס מלא
- תיקון פער: ההנחות מחוברות עכשיו לחיוב המשלוח בפועל (computeAutoSurcharges); קודם מנגנון הטירים היה תצוגתי בלבד (הצעות מחיר/PDF)
- ⚠️ שינוי חיוב: חבילות נוספות יתחילו להיות מתומחרות מרגע ההטמעה (פחות הנחות שתגדיר); בעבר הן בפועל לא הוסיפו למחיר
- דיאלוג המחירון: סקציית 'חבילות נוספות (הנחה)' — שדה כללי + '+' להוספת הנחה לחבילה ספציפית
- יבוא אקסל: שלוש עמודות חדשות — 'הנחת חבילה נוספת', 'הנחת חבילה שניה', 'הנחת חבילה שלישית' (במקום עמודות מחיר החבילה); התבנית להורדה עודכנה בהתאם
- ההנחה מוגבלת ל-[0, מחיר בסיס] (חבילה לא יורדת מתחת ל-0); חל על מסירה ואיסוף יחד; שינויים מתועדים ב-audit של המחירון
- כיסוי טסטים: ללא הנחה, הנחה כללית, עוקף פר-אינדקס, הנחה גדולה מהבסיס, וחבילה בודדת
v01.130.001תיקוןבוט קבוצות / תרחישי WhatsAppבוט השידור — זיהוי בקשת שידור הפך לדטרמיניסטי ומדויק
חוזק תרחיש 'בקשת שידור' של בוט הקבוצות נגד זיהויי-שגוי, אחרי שני מקרים בפרודקשן: (1) צילום של מדבקת משלוח שצורף לדיון תפעולי אחר (היכן נמסר) זוהה כבקשת שידור והוליד 'לא מצאתי משלוח עם המספר שצוין'; (2) ההודעה '25595110 י…
פרטים נוספים ↓הסתר ↑
חוזק תרחיש 'בקשת שידור' של בוט הקבוצות נגד זיהויי-שגוי, אחרי שני מקרים בפרודקשן: (1) צילום של מדבקת משלוח שצורף לדיון תפעולי אחר (היכן נמסר) זוהה כבקשת שידור והוליד 'לא מצאתי משלוח עם המספר שצוין'; (2) ההודעה '25595110 יש 11 ספרות' (דיווח של קבלן על מספר טלפון שגוי) זוהתה כבקשת שידור, כי מספר משלוח בודד נחשב טריגר. כעת הזיהוי דטרמיניסטי: בקשת שידור = מילת שידור מפורשת (לשדר/שדר/שדרו/תשדרו/לא משודר/לא נסרק/שימו עלי/לא מופיע לי...) או מספר משלוח בודד לחלוטין (ללא טקסט נוסף). מספר שמלווה בכל הערה/שאלה/דיווח אחר → שתיקה. צילום מדבקה נחשב בקשת שידור אך ורק אם מלווה במילת שידור מפורשת — צילום ללא מילת מפתח (גם אם נשלח לבדו) אינו בקשת שידור. רשימת מילות המפתח חוזקה עם גבולות-מילה עבריים, כך שמילים לא-קשורות שמכילות שורש 'שדר' (שדרות, משודרג, שדרוג) לא מזוהות בטעות. במקביל שופרה הנחיית תרחיש 'טלפון שגוי' (כבוי כרגע) כך שיזהה דיווח על מספר ספרות שגוי כמו 'יש 11 ספרות' — מוכן ליום שיופעל. מחרוזת ה-OCR אוחדה לקבוע משותף.
v01.130.000חדשמחירון לקוחות / תמחורminorמכפיל מחיר לפי דחיפות (דחוף/בהול) במחירון הלקוח
נוסף מנגנון מכפיל דחיפות למחירון הלקוח: לכל לקוח ניתן להגדיר 'מכפיל דחוף' (EXPRESS) ו'מכפיל בהול' (URGENT) — מספר עשרוני כמו 1.8, 2 או 3 — שמוכפל על מחיר הבסיס האפקטיבי של משלוחים בדחיפות המתאימה.
פרטים נוספים ↓הסתר ↑
נוסף מנגנון מכפיל דחיפות למחירון הלקוח: לכל לקוח ניתן להגדיר 'מכפיל דחוף' (EXPRESS) ו'מכפיל בהול' (URGENT) — מספר עשרוני כמו 1.8, 2 או 3 — שמוכפל על מחיר הבסיס האפקטיבי של משלוחים בדחיפות המתאימה. עד כה שדה הדחיפות במשלוח (REGULAR/EXPRESS/URGENT) היה קיים אך לא השפיע על המחיר כלל. המכפיל חל על מחיר הבסיס בלבד (התוספות — גוביינא, יעד חריג, חבילות — נשארות שטוחות), והוא מוטמע בכל מסלולי החישוב: סיכום החיוב הפר-משלוח, פאנל התמחור (שמציג כעת שורת 'מכפיל דחוף/בהול ×N' עם תוספת המחיר), וסיכום הרווחיות המצטבר ללקוח. ברירת המחדל היא 1 (ללא שינוי). אפשר להגדיר את המכפילים בדיאלוג המחירון של הלקוח, וגם דרך שתי עמודות חדשות בקובץ יבוא מחירוני האקסל ('מכפיל דחוף', 'מכפיל בהול').
- שני שדות חדשים בפרופיל המחירון: expressMultiplier (דחוף) ו-urgentMultiplier (בהול), Decimal עם ברירת מחדל 1.0
- המכפיל חל על מחיר הבסיס האפקטיבי לפי shipment.urgency; התוספות נשארות שטוחות
- מוטמע בכל החישובים: computeCustomerBillingSummary, פאנל התמחור (שורת 'מכפיל דחוף/בהול ×N'), וחישוב הרווחיות המצטבר
- ניתן להגדרה בדיאלוג המחירון של הלקוח (סקציית 'מכפילי דחיפות')
- שתי עמודות חדשות בקובץ יבוא מחירוני האקסל — 'מכפיל דחוף' ו'מכפיל בהול' (מספר עשרוני, לא ₪), כולל בתבנית להורדה, בתצוגה המקדימה ובוולידציה (1–20)
- תיעוד מלא ב-audit: שינוי מכפיל נרשם בהיסטוריית המחירון של הלקוח
v01.129.000חדשרווחיות / תמחור / אנליטיקסminorסיכום רווחיות ללקוח + איחוד תצוגת התמחור בדף המשלוח המלא
נוסף סיכום רווחיות מצטבר ברמת הלקוח: כמה הלקוח חויב, כמה עלו האיסופים, כמה עלו המסירות, והרווח/הפסד שנגזר ביניהם — על פני טווח תאריכים נבחר.
פרטים נוספים ↓הסתר ↑
נוסף סיכום רווחיות מצטבר ברמת הלקוח: כמה הלקוח חויב, כמה עלו האיסופים, כמה עלו המסירות, והרווח/הפסד שנגזר ביניהם — על פני טווח תאריכים נבחר. ההכנסה למשלוח מחושבת בדיוק כמו בלשונית התמחור הפר-משלוח (תעריף בסיס מהמחירון לפי סוג המשימה + תוספות, או מחיר ליונוויל השמור כשאין מחירון), והעלות מבוססת על ה-snapshot של עלות האיסוף/מסירה ששמור על המשלוח. הסיכום מופיע בשני מקומות: כרטיס 'רווחיות' בדף הלקוח (עם בורר טווח תאריכים) וטבלת 'רווחיות לפי לקוח' באנליטיקס (לשונית לקוחות), שניהם מאחורי הרשאת FINANCE_VIEW. בנוסף, דף המשלוח המלא (/shipments/[barcode]) קיבל כרטיס 'תמחור ורווחיות' שעוטף בדיוק את אותו פאנל של לשונית התמחור במגירת המשלוח — כך ששני המסכים מציגים מידע פיננסי זהה ואין יותר חוסר אחידות בין כניסה למשלוח מהרשימה לבין כניסה ישירה לפי ברקוד.
- כרטיס 'רווחיות' בדף הלקוח: סך חיוב ללקוח, עלות איסופים, עלות מסירות ורווח/הפסד — עם בורר טווח תאריכים (ברירת מחדל: החודש הנוכחי)
- טבלת 'רווחיות לפי לקוח' באנליטיקס: שורה לכל לקוח (הכנסה, עלות, רווח/הפסד) ממוינת לפי רווח, עם סיכום כללי וייצוא CSV
- חישוב הכנסה זהה ללשונית התמחור הפר-משלוח; חישוב יעיל — פרופיל המחירון נשלף פעם אחת ללקוח והרווחיות נצברת בזיכרון
- סימון כיסוי חלקי: כשעלות זמינה רק לחלק מהמשלוחים (איסוף/מסירה שטרם הושלמו) — מוצגת הבהרה שהרווח משקף את צד העלות הריאלי בלבד
- דף המשלוח המלא מציג כעת את אותו פאנל תמחור (מחיר בסיס, תוספות, סה"כ לחיוב, עלות איסוף/מסירה ורווח) כמו מגירת המשלוח — איחוד מלא של התצוגה הפיננסית
- כל הנתונים הפיננסיים (עלות ורווח) מאחורי הרשאת FINANCE_VIEW; ללא ההרשאה מוצגים רק מחיר בסיס ותוספות
- עיצוב מחדש של פאנל התמחור: שורת KPI עליונה (לחיוב · עלות · רווח + שולי רווח %), שני כרטיסי פירוט פרוסים זה לצד זה (חיוב מול עלות/רווח), בורדרים רכים ופריסה רחבה במקום קונטיינר צר מוצמד
v01.128.000חדששיבוץ נהגים / טעויות מיוןminorאזהרת טעות מיון לפני שיבוץ נהג — חוסמת שיבוץ לאזור לא מורשה עד אישור מפורש
כעת, לפני כל שיבוץ נהג (איסוף או מסירה), המערכת בודקת בזמן אמת אם הנהג מורשה לאזור של המשלוח — באותה שיטה בדיוק שבה עובד טריגר 'טעות מיון' הקיים (checkDriverZoneAllowance: בדיקת האזורים המורשים של הנהג מול אזור המשלוח, ע…
פרטים נוספים ↓הסתר ↑
כעת, לפני כל שיבוץ נהג (איסוף או מסירה), המערכת בודקת בזמן אמת אם הנהג מורשה לאזור של המשלוח — באותה שיטה בדיוק שבה עובד טריגר 'טעות מיון' הקיים (checkDriverZoneAllowance: בדיקת האזורים המורשים של הנהג מול אזור המשלוח, עם סובלנות למספר אזור בסיסי כמו '1- מרכז' ≈ '1- צפון'). אם מזוהה טעות מיון, מוצגת אזהרה חמורה ומעוצבת (לא נייטיב) שמפרטת בדיוק את הטעות — שם השליח, האזורים המורשים שלו, ורשימת המשלוחים מחוץ לאזור מקובצת לפי אזור — והפעולה מתבצעת רק אם המשתמש מאשר אותה במפורש ('אני בטוח — שבץ בכל זאת'). הבדיקה היא קריאה-בלבד: היא אינה יוצרת רשומת טעות מיון ואינה משדרת התראות וואטסאפ/סירנה (זה ממשיך לקרות כרגיל בסנכרון מ-Lionwheel). האזהרה חלה על כל מסלולי שיבוץ הנהג במערכת.
- בדיקה בזמן-אמת לפני שיבוץ — אותו כלל בדיוק כמו טריגר טעות המיון הקיים (לוגיקת ההרשאה חולצה לפונקציה משותפת evaluateDriverZoneAllowance)
- אזהרה חמורה מעוצבת עם פירוט מלא: שם השליח, אזוריו המורשים, ורשימת המשלוחים החריגים מקובצת לפי אזור
- הפעולה מתבצעת רק לאחר אישור מפורש; ביטול עוצר את כל השיבוץ
- חל על כל המסלולים: טבלת איסופים (שורה בודדת / סרגל קבוצתי / קבוצה מקובצת), לאסו במפת האיסופים והמשלוחים, דיאלוג שיבוץ קבוצתי, שיבוץ מהיר בכרטיס השליח, ושיבוץ פר-משימה בעמוד המשלוח
- כיסוי לאיסוף ולמסירה כאחד; הסרת שליח (ניקוי) אינה דורשת אישור
- בדיקה קריאה-בלבד — ללא יצירת רשומת טעות מיון וללא שידור התראות; fail-open אם הבדיקה נכשלת כדי לא לחסום עבודה
v01.127.002שיפוראיסופים / שיבוץ נהגיםאישור לפני שיבוץ קבוצתי של איסופים לשליח
נוסף חלון אישור מעוצב (לא נייטיב) לפני כל שיבוץ קבוצתי של משימות איסוף לשליח, כדי למנוע שיבוץ בטעות של עשרות איסופים לקבלן/שליח שגוי בלחיצה אחת.
פרטים נוספים ↓הסתר ↑
נוסף חלון אישור מעוצב (לא נייטיב) לפני כל שיבוץ קבוצתי של משימות איסוף לשליח, כדי למנוע שיבוץ בטעות של עשרות איסופים לקבלן/שליח שגוי בלחיצה אחת. ההודעה מפרטת כמה איסופים, מאיזו עיר/עירוֹת מקור, ולאיזה שליח עומדים לשבץ — לדוגמה: 'שים לב — הנך עומד לשבץ 28 איסופים מירושלים על השליח אל איי שליחויות. האם הנך בטוח?'. האישור חל על שלושת מסלולי השיבוץ בלחיצה אחת בעמוד האיסופים: סימון אזור במפה (לאסו), סרגל הפעולות הקבוצתי, ושיבוץ קבוצה מקובצת. הסרת שליח מקבוצה (ניקוי) אינה דורשת אישור.
v01.127.001שיפורסקריפטים / תשתיתסקריפטי Backfill עמידים יותר בהרצה ארוכה
שיפורי תשתית בסקריפטי ה-backfill התפעוליים (לא חשוף ללקוח).
פרטים נוספים ↓הסתר ↑
שיפורי תשתית בסקריפטי ה-backfill התפעוליים (לא חשוף ללקוח). backfill-pickup-zone-codes: נוסף מנגנון retry עם backoff סביב קריאות Prisma Accelerate, כך ש-'fetch failed' חולף (P5010) לא מפיל ריצה על אלפי שורות — שורה שנכשלת באופן עקבי מדולגת ונספרת (הרצה חוזרת מנסה אותה שוב). backfill-shipment-costs: תוקנה טעינת ה-.env מ-root הריפו לפני שרשרת ה-lib (db.ts בונה את ה-Prisma client בזמן import), כך שהסקריפט רץ נכון מ-root עם pnpm --filter web exec tsx. בנוסף נוסף .mcp.json עם הגדרת שרת ה-MCP של Vercel.
v01.127.000חדשפורטל לקוחות / הרשאותminorניהול משתמשים מלא בידי הלקוח — הזמנה, מחיקה, איפוס סיסמה והרשאות מתוך הפורטל
בעל החשבון (או משתמש עם הרשאת 'ניהול משתמשים') יכול כעת לנהל את צוות הפורטל לבד, בלי לפנות לחברת המשלוחים בכל פעם.
פרטים נוספים ↓הסתר ↑
בעל החשבון (או משתמש עם הרשאת 'ניהול משתמשים') יכול כעת לנהל את צוות הפורטל לבד, בלי לפנות לחברת המשלוחים בכל פעם. עמוד 'צוות וגישה' בפורטל הורחב ל-CRUD מלא: הזמנת משתמש חדש (אימייל, שם, הרשאות → נשלח קישור הזמנה במייל להגדרת סיסמה), קביעת הרשאות וגישת חשבונות לכל חבר צוות, איפוס סיסמה/שליחת הזמנה מחדש (מחזיר קישור להעתקה), ומחיקת משתמש. גבולות הבטיחות נאכפים בשרת: מנהל יכול להעניק כל הרשאה חוץ מ'ניהול משתמשים' (שנשארת בידי חברת המשלוחים בלבד), ואינו יכול לערוך/למחוק/לאפס את עצמו או משתמש אחר שהוא 'מנהל משתמשים'. נלווה לתיקון של היום שמנע שמירת הרשאות מוגבלות (ההשלמה-האוטומטית לבעלים הוסרה).
- הזמנת משתמש חדש מתוך הפורטל — אימייל הזמנה להגדרת סיסמה (או קישור להעתקה אם המייל לא נשלח)
- קביעת הרשאות וגישת חשבונות לכל חבר צוות, איפוס סיסמה/הזמנה מחדש, ומחיקה
- גבול: 'ניהול משתמשים' לעולם אינו ניתן להענקה מהפורטל — נשאר בידי הטננט
- מניעת הסלמה/נעילה: אי אפשר לפעול על עצמך או על מנהל-משתמשים אחר
- כל הגבולות נאכפים בשרת (canManagePortalUsers + בדיקות יעד), לא רק ב-UI
v01.126.000שיפורמדבקות / משלוחיםminorמדבקת משלוח: הערת מיקום בולטת (קומה/דירה/כניסה/קוד) והגדלת טקסט הכתובת
שיפור מדבקת המשלוח לפי משוב מהשטח.
פרטים נוספים ↓הסתר ↑
שיפור מדבקת המשלוח לפי משוב מהשטח. (1) נוסף בלוק 'הערת מיקום' בולט מתחת לכתובת, שמרכז את פרטי המיקום המדויקים — קומה, דירה, כניסה וקוד כניסה — יחד עם הערת היעד החופשית. עד כה פרטי המיקום המובנים לא הופיעו על המדבקה כלל, והערת היעד הייתה ממוזגת לשורת 'הערות' כללית בתחתית המדבקה ולכן נחתכה לעיתים במדבקות מלאות. (2) הוגדל הפונט בבלוק פרטי היעד — גם התווית (מפתח) וגם הערך — כי לקוחות התלוננו שטקסט הכתובת קטן מדי וקשה לקריאה לשליח. (3) תוקנה תצוגת סכום הגוביינא: הסכום מאוחסן באגורות והוצג ללא המרה — כך שגוביינא של 250 ₪ הופיעה כ-25000 ₪. כעת הסכום מומר נכון לשקלים, מוצג עם מפרידי אלפים (1,250 ש״ח) ומציין את אמצעי התשלום (במזומן / בשיק) לפי codType, במקום הטקסט הקבוע 'במזומן'. השינוי חל על שני מנועי הרינדור (PDF להדפסה ו-HTML לתצוגה מקדימה וללינק שיתוף) ועל כל מסלולי המדבקה — משלוח בודד, מרובה, לינק שיתוף ציבורי ופורטל לקוחות.
- בלוק 'הערת מיקום' חדש ובולט מתחת לכתובת — קומה · דירה · כניסה · קוד כניסה
- הערת היעד הוצאה לבלוק המיקום הייעודי במקום שורת 'הערות' הכללית — כך אינה נחתכת במדבקות מלאות
- הגדלת הפונט של התווית והערך בבלוק פרטי היעד (עיר, כתובת, שם מקבל, טלפון, גוביינא) לשיפור הקריאות
- תיקון סכום הגוביינא: הוצג פי 100 (250 ₪ נראו כ-25000) — כעת מומר נכון מאגורות לשקלים, עם מפרידי אלפים
- סכום הגוביינא מציין את אמצעי התשלום — במזומן / בשיק לפי codType — במקום 'במזומן' קבוע
- פרטי המיקום המובנים מוצגים תמיד; הערת היעד החופשית כפופה למתג 'הערות' הקיים
- חל על PDF ו-HTML ועל כל מסלולי ההדפסה — בודד, מרובה, לינק שיתוף ופורטל לקוחות
- פורטל לקוחות: לוגו נפרד לכל חשבון מקושר — לקוח-אב מקושר יכול כעת להגדיר לוגו שונה לכל סאב-לקוח בקבוצה (במקום לוגו יחיד), והלוגו מופיע על מדבקות המשלוחים של אותו חשבון. עד כה ניתן היה להגדיר רק לוגו אחד (על חשבון המשתמש), ועל משלוחים של סאב-לקוחות לא הופיע לוגו כלל
- ניווט: 'שיבוץ איסופים' הועברה מקבוצת-אב נפרדת לתת-לשונית תחת קבוצת 'משלוחים'
- שיבוץ איסופים: סדר עמודות ברירת מחדל חדש — שליח איסוף ותאריך איסוף מיד אחרי הלקוח, ואז אזור, עיר וכתובת
- שיבוץ איסופים: עמודת האזור מציגה את הקוד בלבד (13) במקום 'אזור 13'
- שיבוץ איסופים: עמודות חדשות — 'סוכן' (הסוכן המשויך ללקוח) ו'תאריך יצירה' של המשלוח
- שיבוץ איסופים: הוצרו עמודות 'שליח איסוף' ו'תאריך איסוף' שהיו רחבות מדי
- שיבוץ איסופים: מסנן התקופה עובד כעת לפי תאריך יצירת המשלוח (במקום תאריך האיסוף, שגולגל קדימה כל לילה ע"י קרון וניפח את 'השבוע' ל-37,000)
- שיבוץ איסופים: הדף מציג כעת אך ורק משלוחים שטרם נאספו — בסטטוס 'משלוח חדש' או 'שובץ לשליח איסוף' (וכן משלוחים חדשים ללא סטטוס עדיין); סונכרן בטבלה, בפילטרים ובמפה
- תצוגת סטטוס: תוקן סטטוס גולמי 'new' — ליונוויל מסמן משימה חדשה במחרוזת 'new' (במקום קוד מספרי), שנשמרה כפי שהיא והוצגה גולמית במקום 'משלוח חדש', לא הופיעה בדף שיבוץ האיסופים, ואף נספרה בטעות כמזכה-עמלה. כעת מנורמלת ל-UNASSIGNED בכתיבה (chokepoint יחיד) ובתצוגה, עם backfill לשורות הקיימות
- שיבוץ איסופים: הושמטו מהדף משלוחים המיועדים לליקוט פנימי של הטננט (שמופיעים בדף הליקוט) — מה שמיועד לליקוט אינו מיועד לאיסוף
- שיבוץ איסופים: שם שליח האיסוף המשובץ מוצג כעת בצבע מלא וברור (במקום בגוון פלייסהולדר עמום)
- שיבוץ איסופים: כפתור הניקוי (X) בתיבת תאריך האיסוף עוצב כתיבה תחומה זהה לזו שבבורר השליח
- שיבוץ איסופים: עמודת הברקוד עברה לרכיב הברקוד הקנוני של המערכת (כמו בדף המשלוחים) — כולל העתקה מהירה ופתיחת המשלוח
- שיבוץ איסופים: תאריך היצירה מוצג כעת באותו עובי/צבע כשאר תאי הטבלה (לא בגוון עמום)
- שיבוץ איסופים: קיבוץ משימות להאצת השיבוץ — קיבוץ לפי לקוח+כתובת (ברירת מחדל), לפי אזור איסוף או לפי עיר (וכן 'ללא קיבוץ'), עם כפתור החלפה בסרגל. כל קבוצה מוצגת כשורה מכווצת ('משימות מקובצות' + מונה), נפתחת בלחיצה למסגרת עוטפת, וניתן לשבץ שליח/תאריך לכל הקבוצה בפעולה אחת או לבחור חלק מהמשימות
- שיבוץ איסופים: העתקת משימות לשליחים/קבלנים — אייקון העתקה בכל משימה משובצת, בכל כותרת קבוצה (מעתיק את כל הקבוצה), וכפתור 'העתקה' בסרגל הבחירה המרובה. הטקסט כולל ברקוד, לקוח, כתובת ועיר
- שיבוץ איסופים: כפתור 'סמן לליקוט' בסרגל הבחירה המרובה (זהה לדף המשלוחים) — מסמן את הנבחרים לליקוט פנימי
- שיבוץ איסופים: אייקון '⋯' בסוף כל שורה (במקום אייקון פתיחת המשלוח) עם תפריט פעולות — סמן לליקוט, פתח בליונוויל, העתקת פרטים, שכפל משלוח, העברה לסל מחזור
- שיבוץ איסופים: לחיצה על הברקוד פותחת מגירת תצוגה מהירה של דף המשלוח (זהה לדף המשלוחים)
- תיבת שיבוץ שליח: רוחב מינימלי תואם לעמודת תאריך האיסוף, והוסר קיצור ראשי התיבות (אווטאר) מרשימת השליחים — בכל מקום בפרויקט
- שיבוץ איסופים: שורת הקבוצה עוצבה מחדש לתאים מלאים בכל עמודה (זהה לשורה רגילה) — בכל עמודה מוצג הערך האחיד או 'לא אחיד'. עמודות שליח ותאריך הן בקרות קבוצתיות שמשבצות שליח/תאריך לכל הקבוצה בפעולה אחת; הסטטוס ותאריך היצירה מציגים ערך אחיד או 'לא אחיד'
- שיבוץ איסופים: רק כפתור 'משימות מקובצות' (עם החץ בתוכו) פותח/סוגר את האקורדיון; שאר התא אינו לחיץ
- שיבוץ איסופים: כפתור הקיבוץ בסרגל עוצב כשאר כפתורי הסרגל (תאריך/פילטרים/מפה), והתפריט הנפתח קיבל אייקונים, תיאורים וסימון לאופציה הפעילה
- שיבוץ איסופים: מתג מהיר בסרגל למעבר בין 'הכל / לא משובץ / משובץ' עם מונים חיים לכל מצב, קיצורי מקלדת 1/2/3, ושמירת הבחירה. ברירת מחדל: 'לא משובץ'. הסינון חל על הטבלה ועל המפה
- שיבוץ איסופים: תיקון תצוגה מבלבלת — איסוף המשובץ על שליח לא-פעיל (שמסונן מרשימת השליחים) הוצג כתיבה ריקה כאילו אינו משובץ, מה שגרם לקבוצה להיראות 'מעורב' ללא סיבה גלויה. כעת מוצג שם השליח המשובץ גם אם אינו פעיל, וגם בזמן טעינת רשימת השליחים
- שיבוץ איסופים: מתג 'הכל / לא משובץ / משובץ' עוצב מחדש לסגנון הלשוניות (tabs) הזהה לדפים אחרים כמו 'פערי חלוקה' — מסילה רכה ולשונית פעילה מורמת — במקום סגרל מקטעים תחום בקו
- שיבוץ איסופים: תיקון — הסרת שליח מקבוצה (לחיצה על ה-X) נכשלה כי נקודת הקצה הקבוצתית לא קיבלה ערך ריק; כעת ההסרה עובדת ומסנכרנת גם לליונוויל
- שיבוץ איסופים: קביעת תאריך איסוף לקבוצה/לבחירה מרובה משמרת את שעת הביקור (מהפריט הראשון) במקום לאפס ל-09:00
- שיבוץ איסופים: מיון ברירת מחדל לפי תאריך יצירה — המשלוחים החדשים ביותר ראשונים, כדי לראות מיד 'מה נכנס עכשיו'
- שיבוץ איסופים: כשהקיבוץ חורג מ-500 משימות — נוסף כפתור 'הצג הכל ברשימה' שמעביר לתצוגה רגילה מעומדת על אותו סינון
- שיבוץ איסופים: תפריט הקיבוץ מציג כמה קבוצות ייווצרו בכל מצב (אזור/עיר/לקוח+כתובת) כדי לבחור בלי ניסוי וטעייה
- שיבוץ איסופים: בעמודות 'שליח איסוף' ו'תאריך איסוף' הוסר סינון הטקסט (שחיפש בערך השמור ולא בבורר החי); המיון נשמר
- שיבוץ איסופים: כפתור 'ביטול' (Undo) ל-10 שניות בהודעות של העברה לסל מחזור וסימון לליקוט — בשורה, בקבוצה ובבחירה מרובה — להחזרה מיידית של פעולה שגויה
- שיבוץ איסופים: ייעול ביצועים — בחירת שורה כבר לא מרנדרת מחדש את כל הטבלה (ייצוב ה-handlers וה-refresh), חשוב במיוחד בקיבוץ עם מאות שורות
- שיבוץ איסופים: נגישות — מתג 'הכל / לא משובץ / משובץ' סומן כקבוצת בחירה (radiogroup) עם תוויות ARIA
- שיבוץ איסופים: מגירת פרטי המשלוח (בלחיצה על ברקוד) נטענת בעצלתיים (lazy) רק בפתיחה הראשונה — מקטין את משקל הטעינה של דף האיסופים
- שיבוץ איסופים: איחוד פונקציות עזר לתאריך למודול משותף אחד (ניקיון קוד, ללא שינוי התנהגות)
- אזורי חלוקה: לישובים שליונוויל מפצלת לכמה אזורים לפי פוליגון (כיום ירושלים), המערכת קוראת כעת את אזור החלוקה המלא (כולל מרכז/צפון/דרום) ישירות מליונוויל — גם באיסוף וגם בחלוקה — ונופלת לאזור-הישוב היחיד ('1') רק כשליונוויל לא החזירה אזור. שאר הישובים ממשיכים להישען על המיפוי הידני לפי שם ישוב
- אזורי חלוקה: תיקון — בסנכרון (webhook/סנכרון ידני) האזור המדויק של ירושלים שנקבע ביצירה (מרכז/צפון/דרום) נדרס בכל פעם באזור-הישוב הגנרי, כי נתיב הסנכרון לא משך מ-API את ה-region_str המדויק (שלא נשמר ב-payload). כעת לישובים רב-אזוריים הסנכרון מושך את האזור המדויק מליונוויל — כך האזור נשאר מדויק ואף ממלא אזורים ריקים. שאר הישובים ללא שינוי (ללא קריאת API)
- תאריך איסוף: תיקון אזור-זמן בדחיפה לליונוויל — בעת קביעה/שינוי של תאריך איסוף מהמערכת, הפירמוט לליונוויל נעשה לפי UTC במקום שעון ישראל, מה שהזיז את השעה ב-3 שעות (ולעיתים את היום סביב חצות) וגרם לתאריך 'לקפוץ'. כעת הפירמוט תמיד בשעון ישראל. תוקן בכל שלושת נקודות הדחיפה: עדכון ביקור בודד, קביעת תאריך מרובה, ותאריך האיסוף בעת יצירת משלוח חדש (שברירת המחדל שלו 'היום' חושבה ב-UTC)
- שיבוץ איסופים: כפתור 'סנכרן מליונוויל' בסרגל הבחירה המרובה — מושך נתונים טריים (כולל תאריך האיסוף המעודכן) מליונוויל למשלוחים שנבחרו. נחוץ כי ליונוויל לא שולחת webhook כששינוי הוא רק תאריך הביקור, ולכן תאריך שעודכן בממשק של ליונוויל נשאר ישן אצלנו עד סנכרון ידני או webhook הבא
v01.125.001תיקוןפורטל לקוחות / הרשאותתיקון: עריכת הרשאות של משתמש פורטל חזרה לאחור בכל רענון
כשמנהל ערך משתמש פורטל בעמוד הלקוח והוריד לו הרשאות (למשל כרטסת או API), השינוי נשמר אך 'חזר' בטעינה הבאה — וכל המשתמשים נראו כבעלים עם גישה מלאה.
פרטים נוספים ↓הסתר ↑
כשמנהל ערך משתמש פורטל בעמוד הלקוח והוריד לו הרשאות (למשל כרטסת או API), השינוי נשמר אך 'חזר' בטעינה הבאה — וכל המשתמשים נראו כבעלים עם גישה מלאה. הסיבה: הפונקציה שמזריעה את משתמש הפורטל הראשון מהאימייל של הלקוח רצה בכל טעינה של עמוד הלקוח, ובתוכה 'השלמת הרשאות בעלים' שהוסיפה מחדש את כל הרשאות הבעלים לכל משתמש שהיו לו יותר מהרשאת הצפייה הבסיסית בלבד. כך כל הורדת הרשאה (שלא הורידה עד לצפייה-בלבד) שוחזרה אוטומטית. ההשלמה האוטומטית הזו הוסרה — מעתה כל צירוף הרשאות שמגדירים נשמר ונשאר. הערה: משתמשים שכבר 'הועלו' לבעלים צריך לערוך מחדש פעם אחת אחרי העדכון.
v01.125.000חדשפורטל לקוחות / הרשאותminorדרגת 'מנהל משתמשים' ללקוח — האצלת ניהול ההרשאות ללקוח עצמו
נוספה הרשאת לקוח חדשה — 'ניהול משתמשי פורטל' — הדרגה הגבוהה ביותר, שאותה רק הטננט יכול להעניק (מתוך עמוד הלקוח, ככל שאר ההרשאות).
פרטים נוספים ↓הסתר ↑
נוספה הרשאת לקוח חדשה — 'ניהול משתמשי פורטל' — הדרגה הגבוהה ביותר, שאותה רק הטננט יכול להעניק (מתוך עמוד הלקוח, ככל שאר ההרשאות). משתמש פורטל שקיבל אותה (וכן בעל החשבון) יכול כעת לנהל בעצמו, מתוך עמוד 'צוות וגישה' בפורטל, את כל משתמשי הפורטל של הלקוח (וחשבונות מקושרים) — לקבוע לכל אחד את ההרשאות שלו (צפייה/יצירת משלוחים, כרטסת, מפתחות API) ואת החשבונות שהוא רואה. גבולות הבטיחות: מנהל משתמשים בפורטל אינו יכול להעניק או לשלול את הרשאת 'ניהול משתמשים' עצמה (נשארת בלעדית לטננט), לא יכול לערוך בעלים ולא את עצמו — כך שהטננט שומר על השליטה בדרגה העליונה ואין הסלמת הרשאות. האכיפה בשרת (ה-API מגודר), לא רק ב-UI. הרחבה של עמוד 'צוות וגישה' שנוסף קודם.
- הרשאת 'ניהול משתמשי פורטל' — הדרגה העליונה, ניתנת על ידי הטננט בלבד (מופיעה אוטומטית ברשימת ההרשאות בעמוד הלקוח)
- מנהל משתמשים (או בעלים) קובע מתוך הפורטל את ההרשאות ואת גישת החשבונות של כל חבר צוות
- מנהל בפורטל יכול להעניק כל הרשאה חוץ מ'ניהול משתמשים' עצמה — נשארת בידי הטננט
- מניעת הסלמת הרשאות: אי אפשר לערוך בעלים, אי אפשר לערוך את עצמך, וה-MANAGE_USERS של היעד נשמר תמיד
- אכיפה בשרת (ה-API מגודר ב-canManagePortalUsers), לא רק הסתרת UI
- ללא מיגרציה — בעלים קיימים ממשיכים לנהל את הצוות כרגיל
v01.124.000חדשמשלוחים / שיבוץ איסופיםminorטבלת שיבוץ איסופים — מסך תפעולי לשיבוץ שליחים, תאריכים וסטטוסים למשימות איסוף פתוחות
נוסף דף חדש 'שיבוץ איסופים' (/pickups) כפריט ניווט עליון.
פרטים נוספים ↓הסתר ↑
נוסף דף חדש 'שיבוץ איסופים' (/pickups) כפריט ניווט עליון. הדף מרכז את כל המשלוחים שיש בהם משימת איסוף שטרם בוצעה ומאפשר לנציגות לשבץ שליח, לקבוע תאריך איסוף ולעדכן סטטוס — אינליין בכל שורה, או בבחירה מרובה בפעולה אחת. הדף בנוי במתכונת דף המשלוחים: בורר טווח תאריכים (היום/אתמול/השבוע/שבוע שעבר/החודש/חודש קודם/טווח מותאם — מסונן לפי תאריך האיסוף), פילטרים מבוססי-ספירה לפי לקוח, עיר איסוף, אזור איסוף, שליח איסוף וסטטוס, חיפוש חופשי, שליטה בעמודות (הצגה/הסתרה/הצמדה/מיון/סינון בתוך העמודה), ייצוא לאקסל, סקלטון, רספונסיביות, מצב כהה/בהיר ופאגינציית שרת. כל שורה כוללת ברקוד, סטטוס, שם לקוח, כתובת האיסוף, עיר ואזור האיסוף, שליח האיסוף ותאריך האיסוף. בנוסף נוספה תצוגת מפה לצד הטבלה (split-view) עם סימון אזור (lasso) לשיבוץ שליח איסוף לקבוצת משלוחים. כדי לתמוך בעמודה ובפילטר 'אזור איסוף' נוסף שדה pickupZoneCode למשלוח, הנגזר מעיר האיסוף, מתעדכן גם בסנכרון, ועבר backfill לכל הקיים. במסגרת זו תוקנה גם מכונת-המצבים של האיסוף בכל המערכת: שיבוץ שליח לאיסוף מעדכן כעת ל'שובץ לשליח איסוף' ולא ל'נאסף', ומעבר לסטטוס שאחרי האיסוף (נאסף/נקלט במחסן/יצא להפצה/בהעברה/הושלם/נמסר) מסמן אוטומטית את משימת האיסוף כבוצעה.
- דף חדש /pickups עם פריט ניווט עליון 'שיבוץ איסופים' — כל המשלוחים עם משימת איסוף פתוחה
- עריכה אינליין של שלושה שדות בכל שורה: שליח איסוף (אותה קומפוננטת שיבוץ עם השלמה אוטומטית ו-X להסרה כמו בדף המשלוח), תאריך איסוף, וסטטוס המשלוח
- בחירה מרובה + טולבר לשיבוץ שליח / קביעת תאריך / שינוי סטטוס לכל הנבחרים בפעולה אחת
- פילטרים מבוססי-ספירה (לקוח, עיר איסוף, אזור איסוף, שליח איסוף, סטטוס), בורר טווח תאריכים לפי תאריך האיסוף, חיפוש, שליטה בעמודות, ייצוא לאקסל ותצוגת מפה עם lasso
- עמודת 'אזור איסוף' חדשה (pickupZoneCode) שנגזרת מעיר האיסוף, מתעדכנת בסנכרון ועברה backfill
- תיקון גלובלי: שיבוץ שליח איסוף → 'שובץ לשליח איסוף' (לא 'נאסף'); מעבר לסטטוס שאחרי האיסוף מסמן אוטומטית את משימת האיסוף כבוצעה
- פיצול ה'מזהה היוצא' לשתי רגליים: 'מזהה יוצא (איסוף)' (שדה חדש pickupOutboundTaskId) ו'מזהה יוצא (מסירה)' — כדי לתמוך באיסוף ומסירה אצל קבלנים שונים. שיבוץ שליח קבלן לאיסוף שומר כעת את מזהה הקבלן בעמודת האיסוף, ותוקן באג ששידר שיבוץ של ביקור בודד תמיד כמסירה
v01.123.000חדשפורטל לקוחות / הרשאותminorהגבלת משתמשי פורטל לחשבונות מקושרים נבחרים
בעל חשבון בפורטל יכול כעת להגביל כל חבר צוות לתת-קבוצה של החשבונות המקושרים — למשל עובד שאחראי רק על 'פרשה' יראה אך ורק את המשלוחים של 'פרשה', ולא של שאר החשבונות בקבוצה.
פרטים נוספים ↓הסתר ↑
בעל חשבון בפורטל יכול כעת להגביל כל חבר צוות לתת-קבוצה של החשבונות המקושרים — למשל עובד שאחראי רק על 'פרשה' יראה אך ורק את המשלוחים של 'פרשה', ולא של שאר החשבונות בקבוצה. עד כה כל משתמש פורטל קיבל אוטומטית גישה לכל הקבוצה המקושרת (הורה + כל הילדים). נוסף עמוד 'צוות וגישה' בפורטל (גלוי לבעלים בלבד) שבו מגדירים פר-חבר-צוות לאילו חשבונות יש לו גישה (ברירת מחדל: כל החשבונות; בעלים תמיד עם גישה מלאה ואי אפשר להגביל אותם). ההגבלה נאכפת בשרת בכל נקודות הסינון של נתוני משלוחים, ייבוא, תוויות וכרטסת — מזהה ה-scope הוא פרמטר חובה בפונקציית ההרשאה, כך שהקומפיילר מוודא שאף מסלול לא נשכח (אין דליפת מידע משקט). בורר החשבונות בעמוד המשלוחים מציג למשתמש מוגבל רק את החשבונות שלו.
- עמוד 'צוות וגישה' בפורטל (לבעלים בלבד) — הגדרת גישה פר-חבר-צוות לחשבונות מקושרים נבחרים
- scope נשמר על משתמש הפורטל (scoped_customer_ids); ריק = גישה מלאה (תאימות לאחור — אף משתמש קיים לא מושפע)
- אכיפה בשרת בכל ~20 נקודות הסינון: scope הוא פרמטר חובה, ה-TypeScript מכריח לעדכן כל מסלול
- החיתוך תמיד מול הקבוצה המקושרת — מזהה זר/ישן לעולם לא מרחיב גישה (fail-closed)
- בורר 'חשבונות מקושרים' ועמודי הפורטל מציגים למשתמש מוגבל רק את החשבונות המורשים לו
- בעלים אינם ניתנים להגבלה — תמיד גישה מלאה (מניעת נעילה-עצמית)
v01.122.000חדשהודעות / WhatsApp / Green APIminorניטור ניתוק WhatsApp (Green API) — באנר גלובלי וחיווי 'נותק/חזר' בתוך כל צ'אט
עד כה, כשמופע ה-WhatsApp (Green API) התנתק, איש לא ידע — הודעות נעלמו בלי עקבות ונציגי השירות לא הבינו לאן.
פרטים נוספים ↓הסתר ↑
עד כה, כשמופע ה-WhatsApp (Green API) התנתק, איש לא ידע — הודעות נעלמו בלי עקבות ונציגי השירות לא הבינו לאן. נוסף ניטור מצב מלא: המערכת מתעדת כעת כל מעבר חיבור/ניתוק של המופע (notAuthorized / sleepMode / blocked / yellowCard ↔ authorized) משני מקורות — webhook מיידי (stateInstanceChanged) ו-cron גיבוי כל 5 דקות שמתשאל את getStateInstance (תופס גם ניתוקים שה-webhook לא נמסר עליהם). נשמרים רק מעברים (טבלת provider_state_events), כך שאין הצפת רשומות. שתי נקודות תצוגה: (1) באנר ענבר גלובלי בראש האפליקציה כל עוד המופע מנותק, עם שעת הניתוק והסיבה; (2) קו-מפריד מערכתי בתוך כל צ'אט ב-business-inbox שמראה בדיוק מתי החיבור נותק ומתי חזר — ממוקם כרונולוגית בין ההודעות, כך שכל נציג שנכנס לכל צ'אט מבין את הפער.
- באנר גלובלי באפליקציה כל עוד ה-WhatsApp מנותק — עם שעת הניתוק והסיבה
- חיווי 'נותק ב-HH:MM · חזר ב-HH:MM' בתוך כל צ'אט ב-business-inbox, ממוקם כרונולוגית בין ההודעות
- זיהוי כפול: webhook מיידי (stateInstanceChanged) + cron גיבוי כל 5 דק' (getStateInstance) שתופס גם ניתוקים שלא נמסר עליהם webhook
- תיעוד מעברים בלבד (provider_state_events) — בלי הצפת רשומות מה-poll
- סקריפט חד-פעמי להפעלת stateWebhook על המופע (הזיהוי המיידי); ה-cron עובד גם בלעדיו
- מדריך הגדרה מובנה בדיאלוג אינטגרציית Green API — כתובת ה-webhook להעתקה + צ'קליסט מלא של ה-toggles וההגדרות שצריך בקונסולה כדי שכל היכולות יעבדו
v01.121.001תיקוןלקוחות / אינטגרציית סאמיטחיבור לקוח לסאמיט שנתקע על טעינה אינסופית — קריאת ה-config עברה לפר-טננט
דיאלוג 'חיבור לקוח לסאמיט' נתקע על ספינר בלי להציג התאמות או הצעות.
פרטים נוספים ↓הסתר ↑
דיאלוג 'חיבור לקוח לסאמיט' נתקע על ספינר בלי להציג התאמות או הצעות. הסיבה: לאחר המעבר של אינטגרציית סאמיט להגדרה פר-טננט (TenantProviderConfig), חמש הפונקציות ב-actions/customers.ts (שליפת לקוחות סאמיט, פרטי לקוח, חוב, קישור לכרטסת, וחיבור לקוח) נשארו על ה-config הגלובלי הישן מה-env — שלא מוגדר בפרודקשן כי כל טננט מגדיר את סאמיט שלו בעצמו. כתוצאה getSumitCredentials החזיר null, ה-API החזיר רשימה ריקה (עם שגיאה 'Summit API not configured' בלוג), והדיאלוג נשאר במצב טעינה לנצח. תוקן: כל חמש הפונקציות עברו ל-getTenantSummitConfig(tenantId) — אותו דפוס פר-טננט שכבר בשימוש ב-summit-accounting.ts. בנוסף, הדיאלוג כבר לא נתקע על ספינר כשהרשימה ריקה (תקלה או טננט שלא הגדיר סאמיט) אלא עובר למצב חיפוש ידני.
v01.121.000חדשפורטל לקוחות / מדבקותminorלוגו הלקוח על מדבקות המשלוח
לקוחות הפורטל יכולים כעת להעלות את הלוגו שלהם, והוא מודפס על כל מדבקת משלוח.
פרטים נוספים ↓הסתר ↑
לקוחות הפורטל יכולים כעת להעלות את הלוגו שלהם, והוא מודפס על כל מדבקת משלוח. ההעלאה נעשית מתוך הגדרות → מדבקה בפורטל (כרטיס 'לוגו על המדבקה', PNG/JPG עד 2MB); הלוגו נשמר ברמת הלקוח/חברה ומשותף לכל משתמשי הפורטל של אותו חשבון. במדבקה הלוגו מצויר בתחתית במקום סמל ברירת המחדל, מגודר בהגדרת 'הצג לוגו'. הלוגו נפתר פר-משלוח לפי החברה שלו — כך שבהדפסה קבוצתית של מספר חשבונות מקושרים כל מדבקה מקבלת את הלוגו הנכון; הוא מופיע גם כשמדפיסים מצד הצוות או דרך קישור שיתוף. מימוש נשען על תשתית הלוגו והאחסון הקיימת (Supabase) ועל אותו דפוס שמסמכי ה-CRM כבר משתמשים בו לציור לוגו ב-PDF (הטמעת data-URI, רק PNG/JPG שנתמכים ב-react-pdf).
- העלאת לוגו פר-לקוח מתוך הגדרות → מדבקה בפורטל (כרטיס חדש), עם תצוגה מקדימה והסרה
- הלוגו נשמר על הלקוח (logo_url) ומופיע על מדבקות שמדפיס כל משתמש של אותו חשבון
- פתרון פר-משלוח: בהדפסה קבוצתית של חשבונות מקושרים כל מדבקה מקבלת את הלוגו של החברה שלה
- מופיע בכל מסלולי ההדפסה — פורטל בודד/קבוצתי, צד צוות, וקישור שיתוף
- גודל הלוגו ב-footer מתואם לגובה הסמל הקיים כדי לא לדחוף את שאר פרטי המדבקה; העלאה מוגבלת ל-PNG/JPG (נתמך ב-react-pdf)
- הרשאה: רק חבר עם 'יצירת משלוחים' יכול לשנות את הלוגו; צפייה פתוחה לכל משתמש
v01.120.000תיקוןטריגרים / הודעותminorטריגרי סטטוס משלוח שלא נורו אף פעם — "יצא להפצה", "נקלט במחסן", "נאסף" — פעילים סוף-סוף
שלושה סוגי טריגרים שניתן היה להגדיר בטופס הטריגרים ("יצא להפצה"/out_inventory, "נקלט במחסן"/in_inventory, "נאסף"/pickup_completed) מעולם לא נשלחו בפועל — מנוע הטריגרים החזיק רשימה מקוצרת משלו שלא כללה אותם, כך שהטריגר הי…
פרטים נוספים ↓הסתר ↑
שלושה סוגי טריגרים שניתן היה להגדיר בטופס הטריגרים ("יצא להפצה"/out_inventory, "נקלט במחסן"/in_inventory, "נאסף"/pickup_completed) מעולם לא נשלחו בפועל — מנוע הטריגרים החזיק רשימה מקוצרת משלו שלא כללה אותם, כך שהטריגר היה מוגדר ופעיל בממשק אך יצא מהפונקציה עוד לפני שליפת ההגדרה מה-DB. נוסף לכך, גם מעבר ל"יצא להפצה" שמקורו פנימי (שיבוץ שליח מסירה בסריקה/בלאסו, או שינוי סטטוס ידני בממשק) כלל לא הגיע לצינור הטריגרים — רק webhook מליונוויל הפעיל אותו. תוקנו שני הפערים: (1) מנוע הטריגרים גוזר כעת את סוגי הטריגרים ואת טבלת מיפוי-הסטטוס ישירות מ-status-mappings.ts (מקור אמת יחיד, בלי דריפט עתידי); (2) שינויי סטטוס פנימיים (applyAssignmentStatus המשמש סריקה+שיבוץ-מרובה, וה-PATCH הידני של סטטוס) מפעילים כעת את אותו צינור טריגרים שה-webhook מפעיל. שליחה כפולה נמנעת על ידי שמירת המשמרת הקיימת (statusChanged): ה-echo של ליונוויל אחרי הדחיפה רואה שהסטטוס המקומי כבר עודכן ואינו שולח שוב.
- out_inventory / in_inventory / pickup_completed — טריגרים שהיו מוגדרים בממשק אך מתים — נשלחים סוף-סוף
- מקור אמת יחיד: המנוע נגזר מ-status-mappings.ts במקום רשימה כפולה שנטתה לדריפט
- שינוי סטטוס פנימי (שיבוץ שליח / שינוי ידני) מפעיל טריגר בדיוק כמו webhook מליונוויל
- הרחבה: שינוי סטטוס ידני בממשק מפעיל כעת גם טריגרי מחזור-חיים (למשל סימון 'נמסר' ידנית שולח את הודעת delivery_completed)
- מניעת כפילות מובנית — ה-echo של ליונוויל לא שולח שוב (statusChanged=false)
v01.119.000שיפוריומן פעולות / משלוחיםminorיומן הפעולות של המשלוח — כיסוי מלא: מי שינה, מה שינה ומתי, על כל פעולת ליקוט / תפעול / סטטוס
עד כה חלק גדול מהפעולות שמשנות משלוח שמרו חותמת זמן בלבד (למשל 'נלקט') בלי לתעד מי ביצע אותן, ולכן הן לא הופיעו ביומן הפעולות של המשלוח.
פרטים נוספים ↓הסתר ↑
עד כה חלק גדול מהפעולות שמשנות משלוח שמרו חותמת זמן בלבד (למשל 'נלקט') בלי לתעד מי ביצע אותן, ולכן הן לא הופיעו ביומן הפעולות של המשלוח. הסיבה: היומן מוזן מטבלת ה-AuditLog, ונקודות כתיבה רבות פשוט לא קראו ל-logAudit. הושלם הפער: כל פעולה משמעותית שנוגעת במשלוח רושמת כעת רשומת audit פר-משלוח עם ייחוס מלא (משתמש / API / מערכת), כולל דיף 'לפני ← אחרי' לכל שדה שהשתנה. כוסו: כל מסלולי הליקוט (סימון נלקט / ביטול ליקוט / הוספה / הסרה / שינוי קטגוריה / הערת ליקוט), פעולות תפעול (תוספות תשלום, הערת מעקב פער, ביטול פעולת מאסה), פעולות שליח מהאפליקציה (סימון הושלם / נכשל — משויך לשם השליח), שינויים מ-API ציבורי, מפורטל הלקוח ומעמוד המעקב הציבורי (מתויגים כמקור חיצוני), וגם מעברים אוטומטיים — הוספה אוטומטית לליקוט, סימון-נלקט אוטומטי לפי סטטוס, ומעברי סטטוס שמגיעים מהספק ב-webhook (מתויגים 'סנכרון ספק' / 'אוטומטי', ונרשמים רק על מעבר אמיתי). במקביל הורחבה טבלת תוויות השדות של היומן כך ששבת יעד, תאריך אקספרס, הערת ליקוט, הערת מעקב פער וסך תוספות התשלום מוצגים בעברית עם פורמט ₪ / תאריך תקין.
- סימון 'נלקט' / 'בוטל ליקוט' מציג סוף-סוף מי לקט את המשלוח — התלונה שהובילה לשינוי
- כל מסלולי הליקוט נרשמים פר-משלוח עם דיף לפני/אחרי (סטטוס, קטגוריה, סוג, הערה, שבת יעד)
- פעולות שליח מהאפליקציה (הושלם / נכשל) משויכות לשם השליח שביצע אותן
- שינויים מ-API ציבורי, פורטל לקוח ועמוד מעקב — נרשמים ומתויגים לפי מקור (שם מפתח ה-API / פורטל / עמוד מעקב)
- מעברי סטטוס אוטומטיים מהספק (webhook) וסימון-נלקט אוטומטי — נרשמים ומתויגים 'סנכרון ספק' / 'אוטומטי', רק על מעבר אמיתי
- תוספות תשלום, אקספרס, הערות ושבת יעד — קיבלו תוויות עבריות ופורמט ₪ / תאריך ביומן
- הודעות WhatsApp לא מופיעות ביומן הפעולות — הן נשארות באקורדיון 'מסרונים' הייעודי בלבד (סינון פעולות send_whatsapp ושדות הודעה)
v01.118.004שיפוראנליטיקה / עיצובריענון כרטיסי ה-KPI בסקירת האנליטיקה — שפה שקטה, עומק פיזי וגרף מגמה אמיתי
כרטיסי המדדים בטאב 'סקירה כללית' (אנליטיקה) עוצבו מחדש בשפה מרוסנת: הוסרו ארבעת צבעי הגרדיאנט השונים, אפקטי ה-glow, ה-blob המטושטש, ה-sparkle וה-shine sweep — והוחלפו במשטח ניטרלי אחיד שבו הצבע נושא משמעות בלבד (ירוק/אדו…
פרטים נוספים ↓הסתר ↑
כרטיסי המדדים בטאב 'סקירה כללית' (אנליטיקה) עוצבו מחדש בשפה מרוסנת: הוסרו ארבעת צבעי הגרדיאנט השונים, אפקטי ה-glow, ה-blob המטושטש, ה-sparkle וה-shine sweep — והוחלפו במשטח ניטרלי אחיד שבו הצבע נושא משמעות בלבד (ירוק/אדום לכיוון השינוי). המספרים הוגדלו עם tabular-nums והיררכיה טיפוגרפית חדה, נוסף sparkline אמיתי מסדרת המשלוחים היומית לכרטיס 'סה"כ משלוחים', ופס התקדמות אמיתי לכרטיס 'אחוז הצלחה'. אפקט ה-hover עבר מהרמה + זוהר ניאון לעומק צל פיזי בלבד. במקביל נוסף סולם elevation (טוקני --elevation-1/2/3 + utility classes) ל-globals.css כבסיס לשפת העיצוב החדשה.
v01.118.003תיקוןפורטל לקוחות / מדבקותהדפסת מדבקות בפורטל — עד 1000 בבת אחת, מדבקה לכל חבילה, ותיקון בורר החשבונות
לקוחות בפורטל קיבלו שגיאה כשניסו להדפיס מדבקות לבחירה גדולה (מעל 250 משלוחים) — הבקשה נדחתה והם נאלצו לפצל ידנית.
פרטים נוספים ↓הסתר ↑
לקוחות בפורטל קיבלו שגיאה כשניסו להדפיס מדבקות לבחירה גדולה (מעל 250 משלוחים) — הבקשה נדחתה והם נאלצו לפצל ידנית. הוסר חסם ה-250: מחולל ה-PDF מרנדר כעת אצוות גדולות במקטעים מוגבלים (כדי לא להעמיס את הזיכרון של הפונקציה) וממזג אותם לקובץ PDF אחד עם pdf-lib, כך שניתן להדפיס עד 1000 מדבקות בקובץ אחד. במקביל שופר ה-UI בפורטל: חיווי טעינה בזמן ההכנה ופתיחת הטאב מראש כדי לא להיחסם ע"י חוסם החלונות הקופצים בהדפסות ארוכות. בנוסף תוקנו שני באגים: (1) בהדפסה מרובה משלוח עם כמה חבילות הדפיס מדבקה אחת בלבד במקום מדבקה לכל חבילה — כעת ההדפסה הקבוצתית מרחיבה משלוח רב-חבילתי ל-N מדבקות בדיוק כמו הדפסה מדף המשלוח (תוקן גם במסלול הפורטל וגם במסלול השיתוף לצוות). (2) בבורר 'חשבונות מקושרים' בעמוד המשלוחים בפורטל לא ניתן היה לבטל את הבחירה 'הכל' — צ'קבוקס 'הכל' היה תקוע מסומן; כעת לחיצה עליו מבטלת ומתמקדת בחשבון של המשתמש עצמו, וניתן להוסיף משם חשבונות נוספים. בנוסף שופרה תבנית המדבקה עצמה: (א) מספר החבילה (חבילה 1/2, 2/2 וכו') מוצג כעת בבירור על מדבקת משלוח רב-חבילתי — קודם הוא חושב פנימית אך מעולם לא צויר ב-PDF; (ב) הפונט של פרטי המשלוח (עיר, כתובת, שם מקבל, טלפון, גוביינא, הערות) הוגדל לקריאוּת טובה יותר, עם ריווחים שהודקו כדי שהכול ימשיך להיכנס במדבקת 100×100; (ג) המדבקה נחתכת כעת בגבול הפיזי (overflow hidden) במקום לגלוש לעמוד שני מיותר בהדפסה קבוצתית. הערות המשלוח והערת היעד/מיקום ממשיכות להופיע (כברירת מחדל) וכעת בפונט גדול יותר.
v01.118.002תיקוןבוט קבוצות / תרחישיםתיקון בוט הקבוצות — סוף לזליגת הודעות לא-קשורות וכפילויות ב-relay
תוקנה תקלה שבה בוט הקבוצות (מנוע התרחישים) העביר הודעות זבל לא-קשורות בחזרה ללקוח/שליח.
פרטים נוספים ↓הסתר ↑
תוקנה תקלה שבה בוט הקבוצות (מנוע התרחישים) העביר הודעות זבל לא-קשורות בחזרה ללקוח/שליח. כששאלת צפי (eta_relay) של לקוח נשלחה לקבוצת שליח עמוסה, כל פטפוט שהגיע שם ('בוקר טוב', צילום מדבקה של משלוח אחר, רשימת כתובות) הוחזר ללקוח עם הקידומת 'לגבי משלוח X:'. שני שורשים: (1) ה-leg של תשובת ה-relay קיבל כל טקסט כ'תשובה' (heuristic טריוויאלי בלבד), בעוד שצד הטריגר מוגן במסווג LLM זהיר — נוסף כעת שער רלוונטיות LLM זול שמעביר רק הודעה שבאמת עונה על מה שנשאל, ומדלג על הודעות שכתב נציג שלנו בצד היעד; בכל ספק — שתיקה וה-relay נשאר פתוח לתשובה אמיתית. (2) ה-burst בקבוצת הלקוח לא התאפס, כך שכל הודעה חדשה הפעילה מחדש את אותו תרחיש ויצרה relay כפול ופנייה חוזרת לשליח — נוסף guard שמונע פתיחת relay כפול כשכבר קיים אחד פתוח לאותו משלוח. בנוסף בוטל relay תקוע שנותר פתוח, כמיטיגציה מיידית.
v01.118.001שיפורשיחות עסקיות / UIכפתור ניקוי (X) בתיבת החיפוש בשיחות עסקיות
נוסף כפתור X בתיבת החיפוש בעמוד השיחות העסקיות (business-inbox) לניקוי מהיר של השדה, בדיוק כפי שקיים כבר בתיבת החיפוש של תיבת הדואר הרגילה.
פרטים נוספים ↓הסתר ↑
נוסף כפתור X בתיבת החיפוש בעמוד השיחות העסקיות (business-inbox) לניקוי מהיר של השדה, בדיוק כפי שקיים כבר בתיבת החיפוש של תיבת הדואר הרגילה. הכפתור מופיע רק כשיש טקסט בשדה.
v01.118.000חדשAI / לולאות למידהminorסגירת שתי לולאות המשוב של ה-AI — תשובות לשאלות ממתינות הופכות לתובנות, ולמידת תרחישים לבוט הקבוצות
הושלמו שתי לולאות משוב שהיו פתוחות.
פרטים נוספים ↓הסתר ↑
הושלמו שתי לולאות משוב שהיו פתוחות. (1) 'שאלות ממתינות' → תובנה: עד כה כשמשתמש ענה כן/לא על שאלה שעוזר ה-AI שאל (פאנל 'שאלות ממתינות'), התשובה רק נשמרה ב-DB ונעלמה — ה-AI לא קיבל אותה בחזרה. כעת תשובת כן/לא הופכת אוטומטית לתובנה מאושרת על הישות הקשורה (שליח/משלוח/חברה), כך שהידע נכנס לזיכרון ה-AI ומשפיע על תשובות עתידיות; קריאת Haiku קצרה מנסחת את התשובה כעובדה הצהרתית, והמשתמש מקבל הודעת 'נשמר כתובנה'. דחייה אינה מלמדת דבר. (2) למידת תרחישים לבוט הקבוצות (Phase 2): נוסף עמוד 'החלטות הבוט' (הגדרות → AI → החלטות הבוט) שמציג את ההחלטות האחרונות של הבוט בקבוצות — ובמיוחד היכן שתק. נציג יכול ללמד 'זה היה אמור להיות תרחיש X', והתיקון מוזרק כדוגמה למסווג של אותו טננט ומשטח (קבוצת שליח/לקוח) — כך הדיוק עולה עם הזמן בלי שינוי קוד. ניתן להסיר דוגמה שגויה (ואז ההחלטה חוזרת לרשימת הטיפול). תרחיש מושבת לעולם אינו מסווג גם אם נלמד.
- תשובת כן/לא בפאנל השאלות הממתינות → תובנה מאושרת שנכנסת לזיכרון ה-AI (כולל קידום תובנה שכבר הומתנה)
- עמוד 'החלטות הבוט' — סקירת החלטות הבוט בקבוצות ולימוד 'זה היה תרחיש X' לשיפור המסווג
- דוגמאות שנלמדו מוזרקות למסווג לפי טננט ומשטח; הסרת דוגמה שגויה מחזירה את ההחלטה לטיפול
- תיקון: סוגי אירועי התרחישים מבודדים מ-digest הלמידה (לא יוצרים תובנות שווא); אינדקס + ניקוי טלמטריה לבונד גודל הטבלה
- תיוג מקור-מפתח (tenant/system) מדויק בחיוב, ומדידת עלות לכל קריאות החילוץ
v01.117.000שיפורמשלוחים / היסטוריית פעולותminorהיסטוריית פעולות: מעקב מלא אחר פעולות ה-AI, זהות לסטטוס תפעול/החזרה/גוביינא, וקישור לשיחה
שדרוג מקיף להיסטוריית הפעולות של המשלוח.
פרטים נוספים ↓הסתר ↑
שדרוג מקיף להיסטוריית הפעולות של המשלוח. (1) פעולות שמבצע עוזר ה-AI שעד כה לא תועדו כלל — שינוי כתובת/טלפון יעד (updateShipmentAddress) ושינוי סטטוס תפעולי (updateShipmentOperationalStatus) — נרשמות כעת ב-audit log, מיוחסות למשתמש שביקש מה-AI (קישור FK רק כשהוא משתמש אמיתי) ועם diff מלא של השדות שהשתנו. (2) כל פעולת AI (סטטוס, כתובת, תפעול) מסומנת כעת בתג 'AI' ענברי + נקודת ניצוץ, וכוללת קישור 'צפה בשיחה' שפותח את ה-widget של העוזר ישירות על הצ'אט שגרם לפעולה — סוף-סוף ניתן לעקוב מההיסטוריה איך ולמה ה-AI פעל. הקישור ממומש דרך עמודת session_id חדשה ב-audit_logs שנלכדת בכל פעולת AI. (3) סוגי פעולה שהוצגו עד כה כ'פעולה' גנרית עם שעון אפור — סטטוס תפעול וסטטוס החזרה — קיבלו אייקון, תווית עברית וצ'יפ-סינון ייעודיים. (4) שינויי גוביינא (COD) שהופיעו בהיסטוריה מחופשים לשינוי/עדכון/מחיקה ברמת המשלוח (כולל פח אדום מטעה על מחיקת גוביינא) קיבלו זהות 'גוביינא' נפרדת עם אייקון מטבעות. הכול תוך שמירה על תאימות: הנתונים נשמרים, ותג ה-AI/כפתור הביטול הקיימים ממשיכים לעבוד. (5) בקרת גישה לקישור 'צפה בשיחה': צפייה בשיחה של משתמש אחר מותרת רק לבעלי הרשאת AUDIT_LOGS_VIEW (בעלים/אדמין) — נציג רגיל רואה ופותח רק את השיחות שהוא עצמו יצר. נאכף בשרת ב-/api/ai/chat (לא רק הסתרת הקישור ב-UI): טעינת שיחה בודדת בודקת בעלות, והקישור עצמו מוצג רק כשהצופה רשאי לפתוח. סוגר פער קודם שבו טעינת שיחה לפי id הייתה מסוננת לפי tenant בלבד.
- שינויי כתובת/טלפון וסטטוס תפעולי של ה-AI נרשמים כעת בהיסטוריה (קודם נעלמו לגמרי), מיוחסים למשתמש שביקש
- כל פעולת AI מסומנת בתג 'AI' + קישור 'צפה בשיחה' שפותח את הצ'אט שגרם לה
- סטטוס תפעול וסטטוס החזרה קיבלו אייקון/תווית/צ'יפ-סינון ייעודיים במקום 'פעולה' גנרית
- שינויי גוביינא קיבלו זהות נפרדת — כבר לא מתחזים לשינוי/מחיקה ברמת המשלוח (פח אדום מטעה הוסר)
- עמודת session_id חדשה ב-audit_logs מקשרת כל פעולת AI לשיחה שיצרה אותה
- בקרת גישה: צפייה בשיחה של משתמש אחר רק לבעלים/אדמין (AUDIT_LOGS_VIEW), נאכף בשרת — נציג רואה רק את שלו
v01.116.000חדשבוט קבוצות / תרחישיםminorתרחיש 'אימות קבלה מול הנמען' + שדרוגי אמינות לבדיקת המסירה
נוסף תרחיש בוט שביעי: 'אימות קבלה מול הנמען'.
פרטים נוספים ↓הסתר ↑
נוסף תרחיש בוט שביעי: 'אימות קבלה מול הנמען'. כשקבלן/שליח טוען בקבוצתו שהנמען כבר קיבל את המשלוח ('נמסר', 'הלקוח קיבל', 'כבר אצלו') אך אצלנו הוא לא מסומן כנמסר, הבוט פונה אוטומטית לנמען בצ'אט לקוחות הקצה (תבנית ה-Meta המסומנת 'בדיקת מסירה') ושואל אם קיבל; אם מאשר — המשלוח מסומן DELIVERED אוטומטית, אם מכחיש — מסומן לטיפול. הבוט מאשר לקבלן שהבדיקה יצאה. התרחיש משתמש מחדש בתשתית בדיקת המסירה הקיימת (sendDeliveryConfirmationViaTemplate + ה-webhook של Meta) ומוסיף שני שומרים: דילוג אם המשלוח כבר מסומן כנמסר, ודילוג אם כבר יש בקשת אישור פתוחה למשלוח (לא להציק לנמען פעמיים). כבוי כברירת מחדל, רמת סיכון 'פעולה'. בנוסף — שני שדרוגי אמינות ל-webhook של Meta: (1) תקתוק על כפתור תשובה מהירה ('כן'/'לא') ממופה ישירות ל-CONFIRMED/DENIED בלי קריאת LLM (חד-משמעי וזול יותר; טקסט חופשי עדיין עובר לסיווג); (2) תפוגת זמן — בקשת אישור ממתינה תיחשב רק אם נוצרה ב-14 הימים האחרונים, כדי שתקתוק מאוחר על כפתור לא ישייך תשובה לבקשה ישנה/לא קשורה. בנוסף — תיעוד מלא בהיסטוריית הפעולות של המשלוח: באישור הנמען נכתבת רשומת 'שינוי סטטוס' עם הנימוק שבוצעה בדיקת מסירה חיובית (כולל אם זה היה בלחיצת כפתור או בהודעה), ובהכחשה נכתבת רשומת 'בדיקת מסירה' שהנמען הכחיש קבלה. תיקון חשוב שהתגלה תוך כדי: בדיקת המסירה הקודמת עדכנה רק את sendStatus (שמתאר אם הודעת ההתראה נשלחה — לא אם המשלוח נמסר), כך שלמעשה היא לא סגרה את המשלוח כנמסר בפועל; כעת היא מעדכנת את הסטטוס האמיתי (additionalData.status → COMPLETED), כך שהמשלוח באמת מסומן כהושלם. גם השומר 'כבר נמסר' בתרחיש תוקן לבדוק את שדה הסטטוס הנכון.
- תרחיש 'אימות קבלה מול הנמען' — קבלן טוען שנמסר → בדיקה אוטומטית מול הנמען → סימון נמסר באישור
- שומרים: דילוג אם כבר נמסר, ודילוג אם כבר יש בקשת אישור פתוחה
- מיפוי דטרמיניסטי של תקתוק כפתור (כן/לא) בלי LLM
- TTL של 14 יום על בקשות אישור ממתינות
- תיעוד בהיסטוריית המשלוח: אישור → 'שינוי סטטוס' עם נימוק בדיקת מסירה חיובית; הכחשה → רשומת 'בדיקת מסירה'
- תיקון: בדיקת מסירה חיובית סוגרת עכשיו את הסטטוס האמיתי (additionalData.status=COMPLETED), לא רק sendStatus
v01.115.000חדשAI / תובנות ולמידהminorמערכת למידה לעוזר ה-AI — תובנות לפי רמה, חילוץ בזמן אמת, וחידוד בצ'אט
הרחבה מקיפה של מנגנון התובנות כך שהעוזר הופך ל'מכונה לומדת' עם פיקוח אנושי.
פרטים נוספים ↓הסתר ↑
הרחבה מקיפה של מנגנון התובנות כך שהעוזר הופך ל'מכונה לומדת' עם פיקוח אנושי. תובנות נשמרות ברמה המדויקת שלהן ונשלפות רק כשהן רלוונטיות, במקום להיכנס עיוורת לכל פרומפט: משלוח, לקוח, שליח, חברה (קיימים) + שתי רמות חדשות — 'משתמש' (תובנות על אופן העבודה המועדף של משתמש ספציפי, מוזרקות לפרומפט רק כשאותו משתמש מדבר) ו'מערכת' (משוב על העוזר עצמו: פעולות שלא הצליח לבצע, טעויות חוזרות, שאלות שלא ידע לענות — נשמר למפתחים בלבד ולעולם לא מוזרק לשום פרומפט). כל תובנה נשמרת כעת עם 'הקשר מקור' (sourceContext) שנלכד ברגע היצירה — באיזו קבוצה/שיחה נוצרה, מי אמר (צוות/שליח/לקוח), מתי, והטקסט המקורי המדויק. נוסף חילוץ תובנות בזמן אמת מקבוצות WhatsApp: כשמנוע התרחישים מזהה אירוע תפעולי ודאי (חריג), קריאת Haiku זולה וfire-and-forget מחלצת תובנה ארוכת-טווח אם יש כזו, עם dedup ושמירה כ'ממתינה'. בדף 'תובנות AI' נוסף כפתור 'חדד' שפותח drawer עם מיני-צ'אט: המשתמש יכול לחקור את העוזר כיצד הגיע לתובנה, לראות את הטקסט המקורי, ולדון בנכונותה — ובסוף לאשר, לדחות, או לשמור ניסוח מחודד שהעוזר מציע. תובנות מערכת מוצגות בלוח הבקרה (Control Plane → תובנות מערכת) בלבד, חוצות-טננט, מאחורי הרשאת פלטפורמה, כדי שהמפתחים ידעו מה לשפר. בנוסף, פריטים 'ממתינים' שלא טופלו 60 יום נמחקים בשקט כדי לשמור על מיקוד דף הסקירה.
- שתי רמות תובנה חדשות: 'משתמש' (מוזרקת רק לאותו משתמש) ו'מערכת' (משוב למפתחים, לעולם לא בפרומפט)
- הקשר מקור מלא לכל תובנה — קבוצה/שיחה, דובר, תאריך וטקסט מקורי
- חילוץ תובנות בזמן אמת מקבוצות WhatsApp בעת אירוע תפעולי ודאי (fire-and-forget, dedup)
- כפתור 'חדד' — מיני-צ'אט לבחינת התובנה וקבלת ניסוח מחודד, לצד אישור/דחייה
- לוח בקרה לתובנות מערכת חוצה-טננט (הרשאת פלטפורמה) + ניקוי שקט של ממתינות אחרי 60 יום
- בידוד תובנות מערכת נאכף בשרת (לא רק ב-UI) — אינן דולפות או ניתנות לעריכה דרך נתיבי הטננט
v01.113.001תיקוןתיבת הודעותכפתור 'אחורה' במובייל ב-business-inbox חוזר לרשימת הצ'אטים במקום לצאת מהדף
בצ'אט הלקוחות העסקיים (/messages/business-inbox), לחיצה על כפתור/מחוות 'אחורה' של הטלפון בתוך שיחה פתוחה הוציאה את המשתמש לגמרי מהדף, בניגוד לצ'אט לקוחות הקצה (/messages/inbox) ששם 'אחורה' חוזר לרשימת הצ'אטים.
פרטים נוספים ↓הסתר ↑
בצ'אט הלקוחות העסקיים (/messages/business-inbox), לחיצה על כפתור/מחוות 'אחורה' של הטלפון בתוך שיחה פתוחה הוציאה את המשתמש לגמרי מהדף, בניגוד לצ'אט לקוחות הקצה (/messages/inbox) ששם 'אחורה' חוזר לרשימת הצ'אטים. נוסף ל-business-inbox אותו יירוט מבוסס-היסטוריה (pushState בפתיחת שיחה + מאזין popstate): כעת 'אחורה' סוגר את השיחה הפתוחה וחוזר לרשימה, וזהה בשני הצ'אטים.
v01.113.000תיקוןליונוויל / הוכחת מסירהminorתמונות הוכחת מסירה מליונוויל — תיקון פער שהשפיע על רוב המשלוחים שהושלמו
התגלה שתמונות הוכחת המסירה (POD) שצולמו בליונוויל כמעט ולא הופיעו אצלנו — רק חלק זעיר מהמשלוחים שהושלמו הציגו תמונה.
פרטים נוספים ↓הסתר ↑
התגלה שתמונות הוכחת המסירה (POD) שצולמו בליונוויל כמעט ולא הופיעו אצלנו — רק חלק זעיר מהמשלוחים שהושלמו הציגו תמונה. שורש הבעיה: ליונוויל מצרף את התמונה ברגע המסירה או מיד אחריה, כשהמשלוח כבר במצב 'הושלם' (טרמינלי), וה-payload של ה-webhook הרגיל לרוב לא כולל את מערך התמונות — התמונה זמינה באופן אמין רק דרך /tasks/show. בנוסף, ה-cron שמסנכרן משלוחים פתוחים מדלג על משלוחים טרמינליים, כך שמשלוח שהושלם לא נמשך שוב ולכן התמונה שלו לא נשלפה. כמו כן הסנכרון הקודם היה הרסני — מחק תמונות קיימות בכל עדכון וייצר אותן מחדש רק אם ה-payload הנוכחי כלל תמונות, כך שכל webhook מאוחר בלי תמונות מחק תמונה שכבר נשמרה. התיקון: (1) הסנכרון הפך ללא-הרסני — לא מוחק תמונות קיימות כשאין תמונות ב-payload; (2) טיפול ייעודי ב-webhook של 'צירוף תמונה' (is_photo_attached) — כשמתקבל סיגנל שצורפה תמונה אך ה-payload לא נשא אותה, התמונה נמשכת מ-/tasks/show; (3) cron התאמה חדש (sync-completed-pod-images) שרץ כל 30 דקות, מאתר משלוחים שהושלמו לאחרונה וחסרי תמונה, ומושך את ה-POD מליונוויל — עם חלון זמן מוגבל וניסיונות חוזרים תחומים כדי לכבד את ה-rate limit. התיקון פועל קדימה (משלוחים חדשים); לא בוצע backfill היסטורי המוני.
- סנכרון תמונות POD לא-הרסני — webhook בלי תמונות לא מוחק יותר תמונה שכבר נשמרה
- משיכת התמונה מ-/tasks/show כשליונוויל מסמן is_photo_attached אך ה-webhook לא נשא את ה-URL
- cron התאמה חדש שתופס תמונות שמצורפות אחרי השלמת המשלוח (כל 30 דק', חלון מוגבל)
v01.112.001שיפורתיבת הודעות / עוזר AIרמז 'Shift+Enter לשורה חדשה' בפלייסהולדר תיבת ההודעה בשני הצ'אטים
הפלייסהולדר של תיבת כתיבת ההודעה בשני הצ'אטים (/messages/inbox ו-/messages/business-inbox) מציין כעת גם איך יורדים שורה: 'כתוב הודעה...
פרטים נוספים ↓הסתר ↑
הפלייסהולדר של תיבת כתיבת ההודעה בשני הצ'אטים (/messages/inbox ו-/messages/business-inbox) מציין כעת גם איך יורדים שורה: 'כתוב הודעה... (Enter לשליחה, Shift+Enter לשורה חדשה)'. במובייל (ב-/messages/inbox) נשאר 'כתוב הודעה...' בלבד כי שם Enter ממילא יורד שורה. בנוסף — לארבעת כפתורי ה-header של חלון עוזר ה-AI (שאלות ממתינות, היסטוריית שיחות, שיחה חדשה, סגור) נוספו Tooltip תקניים בהתאם לקונבנציית shadcn/ui. כמו כן תוקנה אי-עקביות במקלדת: ב-business-inbox במובייל Enter שלח את ההודעה (במקום לרדת שורה) בניגוד ל-/messages/inbox — נוסף זיהוי מכשיר-מגע גם ל-business-inbox, כך שכעת בשני הצ'אטים זהה: במובייל Enter יורד שורה (השליחה בכפתור) ובדסקטופ Enter שולח ו-Shift+Enter יורד שורה.
v01.112.000חדשAI / עלויותminorלשונית 'עלויות' חדשה תחת AI — מעקב עלויות AI פר-לקוח (מדידה עצמית)
נוספה תחת הלשונית הראשית AI (לצד 'ספקים', 'תרחישים', 'תובנות') לשונית 'עלויות' המציגה לכל לקוח כמה עלה לו השימוש ב-AI — בעיצוב זהה לדף עלויות המסרונים.
פרטים נוספים ↓הסתר ↑
נוספה תחת הלשונית הראשית AI (לצד 'ספקים', 'תרחישים', 'תובנות') לשונית 'עלויות' המציגה לכל לקוח כמה עלה לו השימוש ב-AI — בעיצוב זהה לדף עלויות המסרונים. מכיוון שכל לקוח מחבר ספק AI משלו (ואנחנו לא מספקים שירות AI), העלות נמדדת בשיטת מדידה-עצמית: בכל קריאת AI נרשם אירוע שימוש פר-לקוח (טבלת ai_usage_event) עם ספירת הטוקנים בפועל, והעלות מחושבת ונשמרת באותו רגע מול מחירון. כך השיטה אחידה לכל הספקים (Anthropic/Google/OpenAI), והכי חשוב — היא מייחסת ללקוח גם שימוש שרץ על מפתח-הגיבוי של המערכת (key_source = system), כך שאפשר להציג ולחייב עליו בנפרד (הדף מפצל 'מפתח שלך' מול 'מפתח מערכת'). המספר הוא הערכה: ספירת הטוקנים מדויקת, התמחור לפי מחירון ציבורי. הדף מציג כרטיס עלות כוללת (₪/$ עם שער חי), מדדי טוקנים, וטבלאות פירוט לפי מודל ולפי יום, וכן אזהרה על מודלים ללא מחיר מוגדר. אינסטרומנטציה: מנוע התרחישים (classify + סיכומי דיווח שליח) וסוכני הצ'אט (עובדים + פורטל לקוחות) — דרך wrapper מדידה guarded שלעולם לא שובר קריאת AI. בנוסף, נוסף דף ניהול 'מחירי מודלים' (למנהלי פלטפורמה בלבד) לתחזוקת המחירון לאורך זמן: ברירות מחדל בקוד + override ב-DB הניתן לעריכה ידנית, וכפתור 'בדוק מחירים' שמריץ חיפוש אינטרנט (Claude + web_search) מול דפי התמחור הרשמיים ומציג diff לאישור — מסמן שינויים חריגים, ולעולם לא מחיל אוטומטית בלי אישור אנושי. עלויות היסטוריות אינן משתנות בעדכון מחיר (snapshot בזמן הרישום).
- לשונית 'עלויות' פר-לקוח תחת AI — הערכת עלות לפי ספירת טוקנים ומחירון, אחידה לכל הספקים
- מדידה עצמית מייחסת גם שימוש על מפתח-הגיבוי של המערכת ללקוח (פיצול 'מפתח שלך' מול 'מפתח מערכת') — בסיס לחיוב עתידי
- דף 'מחירי מודלים' למנהלי פלטפורמה: מחירון בקוד + override, וכפתור 'בדוק מחירים' (web search → diff לאישור, ללא החלה אוטומטית)
- עלויות היסטוריות יציבות — המחיר מצולם בזמן הרישום ואינו משתנה בעדכון מחירון
v01.111.002שיפורבוט קבוצות / תרחישיםעדכון השולח במלוא פרטי הדיווח של השליח (אין מענה / כשל מסירה) — עם סינון מידע פנימי
עד כה תרחיש 'אין מענה' שלח ללקוח העסקי תבנית קבועה שדיברה רק על אי-מענה, וסיננה פרטים נוספים שהשליח ציין באותה הודעה.
פרטים נוספים ↓הסתר ↑
עד כה תרחיש 'אין מענה' שלח ללקוח העסקי תבנית קבועה שדיברה רק על אי-מענה, וסיננה פרטים נוספים שהשליח ציין באותה הודעה. כעת הבוט מחלץ מהדיווח של השליח תקציר נאמן של כל הפרטים התפעוליים שעשויים לעזור במסירה — למשל 'אין מענה מהנמען, והשליח גם אינו מצליח לאתר את הכתובת' — ומשבץ אותו בהודעה ללקוח דרך placeholder חדש {driverReport}. כך הלקוח מקבל תמונה מלאה (אם השליח לא מצא את הכתובת הוא לא יכול היה אפילו לדפוק בדלת או להניח ליד הדלת אם זה מאושר) ויכול לתת הנחיה מועילה. זה אינו תרחיש 'כתובת שגויה' — שם הכתובת עצמה שגויה וצריך לתקנה; כאן הכתובת תקינה והשליח פשוט אינו מאתר אותה, והפרט מועבר ללקוח במסגרת האין-מענה. בנוסף — אותו חילוץ הוחל גם על תרחיש 'דיווח כשל מסירה', שעד כה העביר ללקוח את הטקסט הגולמי של השליח (סיכון לחשיפת מידע פנימי). חשוב מכך, מנגנון החילוץ מסנן כעת מידע פנימי/תפעולי שהלקוח לא אמור להיחשף אליו ללא בקרה: עיכובים אצלנו/במחסן, בעיות שידור/שיבוץ, החבילה הגיעה לשליח באיחור מצדנו, פספוס יום איסוף, נזק/אשמה, מחירים, שמות עובדים, מספרי משלוח ותיוגי צוות. הכלל: כל פרט שעוזר למסירה (מצד הנמען/הכתובת) מועבר לשולח; כל פרט פנימי — מסונן, ובספק מושמט; אם לא נשאר פרט בטוח לחשיפה — נשלח משפט גנרי. החילוץ נעשה בקריאת Haiku קצרה שמפענחת גם קיצורים (אמ=אין מענה). בנוסף, גם תשובת השליח בתרחיש 'בקשת תיאום/שינוי מועד' עוברת ניקוי לפני שהיא מועברת ללקוח — שומר על התשובה המהותית (מתי/האם/אילוצי מסירה) ומסיר מידע פנימי; אם לא נשאר תוכן בטוח, התשובה כלל לא מועברת.
v01.111.001תיקוןניהול / ניטור AIחיתוך כותרות ארוכות ברשימת שיחות ה-AI עם Tooltip
כותרות ארוכות ברשימת השיחות בדף /admin/ai-sessions גלשו ודחקו את חותמת הזמן מהשורה.
פרטים נוספים ↓הסתר ↑
כותרות ארוכות ברשימת השיחות בדף /admin/ai-sessions גלשו ודחקו את חותמת הזמן מהשורה. התיקון בשני שלבים: (1) נוסף min-w-0 לשדה הכותרת כך ש-truncate ייכנס לפועל ב-flex child; (2) הרשימה הוחזרה משימוש ב-Radix ScrollArea ל-div עם overflow-y-auto רגיל (כמו ב-/messages/inbox) — ה-Viewport של Radix עוטף את התוכן ב-wrapper עם display:table שמתרחב לרוחב הכותרת הארוכה ביותר ולכן ביטל את ה-truncate לחלוטין. הכותרת נעטפה גם ברכיב ה-Tooltip המשותף (בהתאם לקונבנציה שאוסרת title נייטיבי) שמציג את הכותרת המלאה במעבר עכבר. בנוסף — פעולות שינוי-סטטוס שמבצע עוזר ה-AI (כולל ביטול משלוח) מתעדות כעת מי ביקש אותן: ה-audit log מקשר את המשתמש המבקש (כשהוא משתמש אמיתי) ומוסיף '(לבקשת <שם>)' לתיאור, כך שבהיסטוריית הפעולות של המשלוח רואים את שם המבקש והאווטאר שלו עם חותמת הזמן — במקום 'מערכת' בלבד. תג ה-AI וכפתור הביטול נשמרים. עד כה לא היה ניתן לדעת מההיסטוריה מי הורה ל-AI לבצע את הפעולה. בנוסף — ניקיון רעש בהיסטוריית הפעולות של המשלוח: רשומות עדכון-ביקור הציגו 'עודכנו השדות: שליח (משלוח 12345)' — גם מספר המשלוח (מיותר בדף המשלוח עצמו) וגם שם השדה (שכבר מוצג בטבלת השינויים מתחת) — וכעת שורת התיאור מנוקה ונשען על תג 'עדכון ביקור' + טבלת השינויים בלבד; ושליחות WhatsApp/תבנית Meta (send_whatsapp) הוסרו מהטיימליין כיוון שכבר מוצגות בפירוט באקורדיון 'מסרונים' הייעודי — שניהם שינויי תצוגה בלבד, הנתונים נשמרים ב-DB.
v01.111.000תיקוןAI / WhatsApp inboxminorבוט הקבוצות מזהה היררכיות — תת-לקוחות וסאב-שליחים מנותבים לקבוצת האב/המנהל
מנוע התרחישים בקבוצות שייך עד כה משלוחים לפי רשומת הלקוח/השליח המדויקת בלבד, ולכן פספס שתי היררכיות נפוצות שכבר קיימות במערכת: (1) לקוח-אב עם תת-לקוחות (parentCustomerId) — למשל 'חבד ישראל' שיש לו קבוצה ו-8 תת-לקוחות (חי…
פרטים נוספים ↓הסתר ↑
מנוע התרחישים בקבוצות שייך עד כה משלוחים לפי רשומת הלקוח/השליח המדויקת בלבד, ולכן פספס שתי היררכיות נפוצות שכבר קיימות במערכת: (1) לקוח-אב עם תת-לקוחות (parentCustomerId) — למשל 'חבד ישראל' שיש לו קבוצה ו-8 תת-לקוחות (חיינו, פרוייקטים, עלון פרשה...) עם אלפי משלוחים, אך ללא קבוצה משלהם; (2) שליח-מנהל עם סאב-שליחים (DriverManagerLink) — למשל 'מישל ראשון לציון' שיש לו קבוצה ו-12 סאב-שליחים ללא קבוצה. כתוצאה מכך משלוחים של תת-הלקוחות/הסאב-שליחים לא טופלו ע"י הבוט. כעת השיוך מודע-היררכיה: בכל תרחישי הגישור (אין-מענה, צפי מסירה, כתובת שגויה, טלפון שגוי, כשל מסירה) — איתור המשלוח מקבוצת שליח-מנהל מכסה את כל הסאב-שליחים (visit.driverId בין המנהל לסאבים), שליחת הודעה ללקוח נופלת חזרה לקבוצת לקוח-האב כשלתת-לקוח אין קבוצה, איתור משלוח מקבוצת לקוח-אב מכסה את כל תת-הלקוחות, ושאלה לשליח נופלת חזרה לקבוצת המנהל כשלסאב-שליח אין קבוצה. מומש מרכזית ב-lib/ai/scenarios/shared.ts (getDriverAndSubIds, getCustomerAndChildrenIds, customerChatTarget מודע-אב, resolveDriverGroupChat מודע-מנהל) כך שכל ה-handlers נהנים מהתיקון.
- קבוצת לקוח-אב (חבד ישראל) מכסה כעת את משלוחי כל תת-הלקוחות שלה
- קבוצת שליח-מנהל (מישל) מכסה כעת את משלוחי כל הסאב-שליחים שלו
- fallback אוטומטי לקבוצת האב/המנהל כשלישות-הבן אין קבוצה — בכל 5 תרחישי הגישור
v01.110.000שיפורAI / תרחישי הבוטminorעיצוב מחדש לדף תרחישי הבוט — כרטיסי יכולת + מגירת עריכה
דף תרחישי הבוט (AI → תרחישים) עוצב מחדש מרשימת סקשנים ארוכה וטקסטואלית לגריד כרטיסי יכולת קומפקטי.
פרטים נוספים ↓הסתר ↑
דף תרחישי הבוט (AI → תרחישים) עוצב מחדש מרשימת סקשנים ארוכה וטקסטואלית לגריד כרטיסי יכולת קומפקטי. כל תרחיש מוצג ככרטיס עם אייקון בוט, כותרת, תגיות סיכון (קריאה/גישור/פעולה) וסוג קבוצה, צ'יפ זרימה ויזואלי שממחיש את כיוון הגישור (שליח ← בוט ← לקוח), ומתג הפעלה/כיבוי כפעולה הראשית. ההפעלה/כיבוי נשמרים מיידית (אופטימי, עם חזרה לאחור בכשל) במקום כפתור שמירה גלובלי. עריכת נוסח התגובות עברה למגירה צדדית ממוקדת לפי קונבנציית ה-Drawer של המערכת (כותרת קבועה, אזור גלילה, וכפתורי שמירה/ביטול קבועים). כרטיס מופעל מקבל הדגשה סגולה עדינה, וכרטיס עם נוסח מותאם מסומן 'מותאם'. שמירת נוסח שומרת רק overrides שנבדלים מברירת המחדל, כך ששינויי נוסח עתידיים בברירת המחדל עדיין מגיעים לטננטים שלא התאימו.
- גריד כרטיסי יכולת במקום רשימת סקשנים ארוכה
- צ'יפ זרימה ויזואלי לכיוון הגישור (שליח ← בוט ← לקוח)
- מתג הפעלה/כיבוי עם שמירה מיידית (אופטימי)
- עריכת נוסח התגובות במגירה צדדית ממוקדת
- שמירת overrides בלבד — שינויי ברירת מחדל עתידיים עדיין מתפשטים לטננטים
v01.109.001שיפורתמחור / משלוחי איסוףזיהוי משלוחי איסוף/החזרה — מילוי הפער מליונוויל
משלוחי 'איסוף' (סחורה שנאספת מלקוח קצה וחוזרת לבית העסק) זוהו עד היום רק כשליונוויל תייג task_type='pickup', אבל פריסת השדה אצל ליונוויל אינה עקבית — חלק מהאיסופים הגיעו ללא תיוג ולכן נחשבו (וגם תומחרו) כמסירה רגילה.
פרטים נוספים ↓הסתר ↑
משלוחי 'איסוף' (סחורה שנאספת מלקוח קצה וחוזרת לבית העסק) זוהו עד היום רק כשליונוויל תייג task_type='pickup', אבל פריסת השדה אצל ליונוויל אינה עקבית — חלק מהאיסופים הגיעו ללא תיוג ולכן נחשבו (וגם תומחרו) כמסירה רגילה. חוזק מנגנון הזיהוי האוטומטי שגוזר 'pickup' כשהנמען הוא העסק עצמו: עיגון לפי טלפון או כתובת החנות (מרשומת הלקוח), עם תנאי-בטיחות ששם הנמען תואם לשם העסק — כך שמסירה רגילה לעולם לא תסומן בטעות (חשוב כי task_type מזין תמחור ועמלות סוכן). הכלל מחליף את ה-fallback הישן שהתאים רק כתובת מדויקת (פספס סניף שני, כתיב רחוב שונה, או לקוח ללא כתובת ברשומה). בנוסף בוצע backfill חד-פעמי שתייג 298 משלוחי איסוף שהיו ללא תיוג. הזיהוי המחוזק רץ מעתה אוטומטית בכל סנכרון. בנוסף, משלוחי האיסוף הוצאו מטאבי פערי המסירה (מסירה / קריטיים / יום אחרון) כדי שלא יתערבבו עם מסירות רגילות, וטאב 'כפולות' הורחב ל'החזרות וכפולות' — מציג כעת גם את כל האיסופים הפתוחים (סחורה שנאספה מלקוח וטרם חזרה לעסק) לצד הכפולות. נוספה עמודת 'סוג' (כפולה / החזרה), מניין הימים לאיסוף נספר מרגע האיסוף בפועל מהלקוח, ועמודת השליח מציגה את מי שמביא חזרה לעסק (שליח ההחזרה לכפולה, שליח המסירה-חזרה-לעסק לאיסוף).
v01.109.000חדשבוט קבוצות / תרחישיםminorחמישה תרחישי בוט חדשים — כתובת/טלפון שגויים, תיאום מועד, כשל מסירה ובקשת שידור
מנוע התרחישים של בוט הקבוצות (Green API) הורחב בחמישה תרחישים חדשים שניתן להפעיל ולערוך פר-טננט בהגדרות → תרחישי הבוט.
פרטים נוספים ↓הסתר ↑
מנוע התרחישים של בוט הקבוצות (Green API) הורחב בחמישה תרחישים חדשים שניתן להפעיל ולערוך פר-טננט בהגדרות → תרחישי הבוט. (1) 'כתובת שגויה/חסרה' — שליח מדווח בקבוצתו שהכתובת שגויה או שאינו מוצא אותה, הבוט שואל את הלקוח העסקי לכתובת הנכונה, מחלץ את השדות (עיר/רחוב/מספר/קומה/דירה) בקריאת Haiku קצרה, מעדכן את המשלוח ומסנכרן לליונוויל, ומעביר את הכתובת המעודכנת לשליח. (2) 'טלפון שגוי' — שליח מדווח שמספר הנמען לא תקין, הבוט מבקש מהלקוח מספר נכון, מעדכן את המשלוח ומעביר לשליח. (3) 'בקשת תיאום/שינוי מועד' — לקוח מבקש בקבוצתו לתאם או לשנות מועד מסירה, הבוט מעביר את הבקשה לשליח המשובץ ושואל אם אפשרי, ומעביר את התשובה חזרה ללקוח (אם המשלוח לא משובץ — שותק). (4) 'דיווח כשל מסירה' — שליח מדווח על כשל סופי, הבוט מיידע את הלקוח העסקי על הכשל והסיבה (יידוע חד-כיווני ללא גישור). (5) 'בקשת שידור' — קבלן/שליח מדווח בקבוצתו שמשלוח לא משודר אליו ומבקש לשדר (מילים כמו 'לשדר', 'לא משודר', 'לא נסרק', 'שימו עלי', 'לא מופיע לי באפליקציה'), או שולח צילום של מדבקת המשלוח. הבוט מזהה את המשלוח לפי המספר — מטקסט או מתוך התמונה ב-OCR (Claude vision) — משבץ את הקבלן ומשדר אליו בצורה גנרית (ליונוויל / SNL / שותף Shipnest), ממתין מספר שניות וקורא את מזהה השידור החיצוני (target_partner_task_id המאוחד), ומחזיר את מספר השידור לקבוצה. אם הקבלן טועה והמשלוח כבר משודר — הבוט מחזיר את מספר השידור הקיים במקום לשדר שוב. אם לא צוין מספר — הבוט מבקש אותו (ופותח relay לתשובה). כל חמשת התרחישים כבויים כברירת מחדל — הם אינם משנים את התנהגות הבוט של אף טננט עד שהוא בוחר להפעיל אותם — בהתאם לעקרון 'בספק → שתיקה'. התרחישים שמעדכנים נתונים או משבצים/משדרים (כתובת/טלפון/שידור) מסומנים ברמת סיכון 'פעולה'. ה-OCR לתמונות מוגבל לקבוצות שליח מקושרות שבהן תרחיש השידור מופעל בלבד (בקרת עלות). הקלסיפייר מקבל רמזי טריגר עם הבחנות מפורשות בין התרחישים (למשל 'אין מענה' מול 'טלפון שגוי' מול 'כשל מסירה' מול 'בקשת שידור') כדי למנוע בלבול.
- תרחיש כתובת שגויה — חילוץ כתובת ב-Haiku, עדכון משלוח וסנכרון ליונוויל
- תרחיש טלפון שגוי — בקשת מספר נכון מהלקוח, עדכון והעברה לשליח
- תרחיש בקשת תיאום/שינוי מועד — גישור לקוח↔שליח
- תרחיש דיווח כשל מסירה — יידוע חד-כיווני ללקוח העסקי
- תרחיש בקשת שידור — שיבוץ ושידור אוטומטי לקבלן (ליונוויל/SNL/שותף), כולל OCR לזיהוי מספר המשלוח מצילום מדבקה והחזרת מספר השידור
- זיהוי קיצור השליחים 'אמ'/'א.מ' (=אין מענה) בתרחיש 'אין מענה', והעברת הודעות קצרות עם מספר משלוח או קיצור מוכר את מסנן ה-substantive (כדי שדיווחים תמציתיים כמו '25510238 אמ' ייתפסו)
- כל התרחישים החדשים כבויים כברירת מחדל (opt-in פר-טננט)
v01.108.000חדשניהול / ניטור AIminorשדרוג דף ניטור שיחות ה-AI — חיפוש עומק, פילטר תאריכים, מיון, רינדור עשיר ועיצוב מחדש
דף /admin/ai-sessions לניטור שיחות ה-AI בכל הטננטים קיבל ארבע יכולות חדשות: (1) חיפוש העומק עכשיו סורק גם את תוכן ההודעות עצמן (מעבר לכותרת ושם הטננט) — מנוצל אינדקס ה-pg_trgm שכבר קיים על עמודת ה-content; (2) פילטר טווח…
פרטים נוספים ↓הסתר ↑
דף /admin/ai-sessions לניטור שיחות ה-AI בכל הטננטים קיבל ארבע יכולות חדשות: (1) חיפוש העומק עכשיו סורק גם את תוכן ההודעות עצמן (מעבר לכותרת ושם הטננט) — מנוצל אינדקס ה-pg_trgm שכבר קיים על עמודת ה-content; (2) פילטר טווח תאריכים דרך רכיב DateRangeFilter המשותף, מסנן לפי פעילות אחרונה (updatedAt); (3) בורר מיון — פעילות אחרונה / פעילות ישנה / הכי הרבה הודעות / תאריך יצירה; (4) רינדור הודעות עשיר בצד הפירוט: תצוגת מדיה inline (תמונה/סטיקר/אודיו/וידאו/קובץ עם fallback כש-URL פג), סטטוס מסירה (נשלח/נמסר/נקרא/נכשל), ייחוס שולח בהודעות קבוצה (senderName/senderPhone עם צבע דטרמיניסטי), אבחנה ויזואלית בין assistant לבין staff, ועיצוב נקי של קריאות לכלים (tool calls) במקום JSON גולמי. בנוסף, הדף עוצב מחדש בשפת העיצוב של צ'אט לקוחות הקצה (/messages/inbox): רשימת שיחות עם שורות rounded-xl ואווטרים עגולים ממופי-צבע (ראשי תיבות הטננט) עם טבעת active, חיפוש בשדה מעוגל (rounded-full) עם כפתור ניקוי, פילטר ההקשר הומר לשורת צ'יפים בסגנון ה-inbox, וכותרת הפירוט ובועות ההודעות (בועות שקופות מעוגלות עם פינה אסימטרית, border ו-shadow) תואמות עכשיו את מראה הצ'אט.
- חיפוש עומק בתוך תוכן ההודעות (pg_trgm)
- פילטר טווח תאריכים + ארבע אפשרויות מיון
- תצוגת מדיה inline, סטטוס מסירה וייחוס שולח בהודעות קבוצה
- רינדור מסודר של קריאות לכלים במקום JSON גולמי
- עיצוב מחדש בשפת ה-inbox — אווטרים עגולים, צ'יפים, בועות שקופות ושורות rounded-xl
v01.107.010שיפורתיבת הודעותאפקט בלור עדין מתחת לתיבת הכתיבה הצפה גם ב-business-inbox
אפקט ה-frosted blur שמתחת לתיבת הכתיבה הצפה (שכבר היה ב-/messages/inbox) הוחל גם על צ'אט הלקוחות העסקיים (business-inbox) — רצועת טשטוש עדין (backdrop-blur) בתחתית אזור ההודעות עם מסכת גרדיאנט שמתחזקת ליד האינפוט ודועכת …
פרטים נוספים ↓הסתר ↑
אפקט ה-frosted blur שמתחת לתיבת הכתיבה הצפה (שכבר היה ב-/messages/inbox) הוחל גם על צ'אט הלקוחות העסקיים (business-inbox) — רצועת טשטוש עדין (backdrop-blur) בתחתית אזור ההודעות עם מסכת גרדיאנט שמתחזקת ליד האינפוט ודועכת כלפי מעלה, כך שההודעות שנגללות מתחת לתיבה הצפה נראות 'מעושנות' במקום חתוכות. כעת שני הצ'אטים זהים באפקט.
v01.107.009שיפורממשק / Tooltipהחלפת tooltips נייטיביים (title) ב-Tooltip מעוצב בכל המערכת
כל השימושים שנותרו ב-title נייטיבי של הדפדפן בתור tooltip הומרו לרכיב ה-Tooltip המעוצב של המערכת — בהתאם לקונבנציה שאוסרת title כ-tooltip.
פרטים נוספים ↓הסתר ↑
כל השימושים שנותרו ב-title נייטיבי של הדפדפן בתור tooltip הומרו לרכיב ה-Tooltip המעוצב של המערכת — בהתאם לקונבנציה שאוסרת title כ-tooltip. הומרו: כפתורי הסרה ממועדפים בסיידבר, צ'יפ העדיפות בעמוד הפידבק, נקודת אירוע ביומן הנוכחות, פעולות בצ'אט לקוחות הקצה (סמן כנקרא/לא-נקרא, שלח קובץ, בחר תמונה אחרת, תבניות Meta), כפתור רענון באנליטיקס ההודעות, עריכה/מחיקה בתבניות תעריפי המשלוח, ארבע הפעולות במודאל סנכרון משלוחים, תצוגה מקדימה בכרטסת ובחשבונאות הלקוח, וכפתור 'שלח לאישור Meta' בטריגרים. ה-iframes (title כדרישת נגישות) ומרקר ה-Leaflet (title בתוך מחרוזת HTML) נותרו ללא שינוי. במקומות שבהם ה-title שכפל aria-label על אלמנט שלא ניתן לעטוף בבטחה (מתג הטננט בראש הסיידבר, פס הגרירה של הסיידבר) הוסר ה-title המיותר.
v01.107.007תיקוןתשתית / Next.js 16ניקוי אזהרות Next.js 16 בטרמינל — Edge Runtime, proxy ו-metadataBase
טופלו שלוש אזהרות שהוצפו בטרמינל הפיתוח: (1) המודול lib/encryption.ts (שמייבא את crypto של Node) נמשך אל ה-Edge Runtime דרך שרשרת instrumentation → logger → whatsapp → provider-factory, ויצר אזהרת קומפילציה חוזרת בכל בקש…
פרטים נוספים ↓הסתר ↑
טופלו שלוש אזהרות שהוצפו בטרמינל הפיתוח: (1) המודול lib/encryption.ts (שמייבא את crypto של Node) נמשך אל ה-Edge Runtime דרך שרשרת instrumentation → logger → whatsapp → provider-factory, ויצר אזהרת קומפילציה חוזרת בכל בקשה. נוסף guard לפי NEXT_RUNTIME ב-onRequestError כך שה-bundler משמיט את ייבוא ה-logger ואת התלויות הצד-שרתיות שלו מ-bundle ה-Edge לחלוטין. (2) הקובץ middleware.ts שונה ל-proxy.ts בהתאם לקונבנציה החדשה של Next.js 16 (middleware הוצא משימוש). (3) הוגדר metadataBase ב-root layout כך שכתובות תמונות ה-OG/Twitter נפתרות מול הדומיין הקנוני במקום http://localhost.
v01.107.006שיפורצ'אט / Inboxריענון ראש שני הצ'אטים — תפריט 3-נקודות, אייקון אחיד, והסרת בורדר מיותר
בתיבת צ'אט לקוחות הקצה (/messages/inbox) הוסר הקו (border-b) שהפריד בין הכותרת הראשית לבין שדה החיפוש — הוא היה מיותר ויצר חלוקה עודפת.
פרטים נוספים ↓הסתר ↑
בתיבת צ'אט לקוחות הקצה (/messages/inbox) הוסר הקו (border-b) שהפריד בין הכותרת הראשית לבין שדה החיפוש — הוא היה מיותר ויצר חלוקה עודפת. בנוסף, בשתי תיבות הצ'אט הפעולות שהיו מוצגות משמאל לכותרת קופלו אל תוך כפתור 3-נקודות אנכי (kebab): בתיבה העסקית — 'סנכרן קבוצות' ומעבר ל'ארכיון'; בתיבת לקוחות הקצה — 'שיחה חדשה' ו'אפשר התראות דסקטופ'. גם האייקון שליד כותרת התיבה העסקית הוחלף מאייקון בניין (כחול) לאייקון הצ'אט הקלאסי (MessageCircle אפור), זהה לתיבת לקוחות הקצה.
v01.107.005שיפורצ'אט / Inboxעיצוב אחיד לאינפוט החיפוש בשתי תיבות הצ'אט
שדה החיפוש בתיבת הצ'אט העסקי ובתיבת לקוחות הקצה אוחד, תוך לקיחת היתרונות מכל אחד: שוליים צרים של 8px משני צידי השדה (מ-business-inbox); רקע פנימי שמתמזג עם רקע הדף וצל עדין מסביב (מ-inbox); אייקון החיפוש בצד ימין עם רווח…
פרטים נוספים ↓הסתר ↑
שדה החיפוש בתיבת הצ'אט העסקי ובתיבת לקוחות הקצה אוחד, תוך לקיחת היתרונות מכל אחד: שוליים צרים של 8px משני צידי השדה (מ-business-inbox); רקע פנימי שמתמזג עם רקע הדף וצל עדין מסביב (מ-inbox); אייקון החיפוש בצד ימין עם רווח של 8px בדיוק בינו לבין הפלייסהולדר (תוקן הרווח שהיה גדול מדי); ופינות מעוגלות לגמרי (rounded-full) בסגנון וואטסאפ — שהיה חסר בשניהם. רצועת הצ'יפים ב-inbox יושרה ל-8px בהתאם, כדי שתישאר צמודה לשדה החיפוש.
v01.107.004שיפורתיבת הודעותתיבת כתיבת ההודעה צפה מעל הצ'אט בשני דפי השיחות
בשני הצ'אטים (/messages/inbox ו-/messages/business-inbox) אזור כתיבת ההודעה בתחתית עוצב מחדש כך ש'יצוף' מעל השיחה במקום לשבת על פס נפרד.
פרטים נוספים ↓הסתר ↑
בשני הצ'אטים (/messages/inbox ו-/messages/business-inbox) אזור כתיבת ההודעה בתחתית עוצב מחדש כך ש'יצוף' מעל השיחה במקום לשבת על פס נפרד. הוסר רקע הבר הנפרד (היה bg-muted) והבורדר העליון — הסביבה סביב האינפוט שקופה לחלוטין, כך שההודעות נגללות ונראות מאחוריה (מלמעלה ומלמטה). רק תיבת הקלט עצמה אטומה (רקע לבן/כהה + בורדר משלה + צל עדין) ונראית צפה. הסביבה השקופה היא click-through (pointer-events) כך שניתן לגלול את ההודעות גם דרך השוליים. אזור ההודעות מקבל padding תחתון כדי שההודעה האחרונה נחה מעל התיבה הצפה, וכפתור 'גלול למטה' הוזז להופיע מעליה.
- תיבת קלט צפה עם סביבה שקופה — ההודעות נראות נגללות מאחוריה
- ללא רקע נפרד וללא בורדר עליון; רק הקלט אטום עם צל עדין
- חל על שני דפי הצ'אט (לקוחות קצה + לקוחות עסקיים)
v01.107.003שיפורצ'אט / Inboxגלילת צ'יפי הסינון בשתי תיבות הצ'אט — גרירה בסגנון וואטסאפ במקום סקרולבר
צ'יפי הסינון בתיבת הצ'אט העסקי ובתיבת לקוחות הקצה כבר לא מציגים סרגל גלילה (שנראה לא נקי).
פרטים נוספים ↓הסתר ↑
צ'יפי הסינון בתיבת הצ'אט העסקי ובתיבת לקוחות הקצה כבר לא מציגים סרגל גלילה (שנראה לא נקי). במקום זאת ניתן לגרור את הצ'יפים הצידה עם העכבר — בדיוק כמו ברשימות הצ'יפים של וואטסאפ — וגם גלגלת העכבר וגלילת מגע/טראקפד פועלות. גרירה מעבר לסף קטן 'בולעת' את הקליק שאחריה כך שגרירה לעולם לא תחליף בטעות פילטר, והמנגנון מופעל רק כשהרצועה באמת גולשת. המימוש רוכז ב-hook משותף (useDragScroll) המשמש את שני הדפים, ומודע לכיוון RTL. בנוסף, הצ'יפ הפעיל קיבל מראה 'מתואר' (outlined) — בורדר דק בצבע המותג, רקע שקוף קלות, וטקסט באותו צבע המותג — במקום רקע מלא וטקסט לבן.
v01.107.002שיפורצ'אט לקוחות קצה / Inboxסינון תיבת לקוחות הקצה (/messages/inbox) עבר לצ'יפים בעיצוב אחיד
טאבי הסינון בתיבת צ'אט לקוחות הקצה (הכל / הסלמות / טופל) הוחלפו בצ'יפים באותו עיצוב בדיוק כמו בתיבת הצ'אט העסקי: אייקון ייעודי לכל צ'יפ (תיבה / משולש אזהרה / וי), בורדר עדין, ריווח קומפקטי, ושורה אחת שנגללת אופקית (כולל …
פרטים נוספים ↓הסתר ↑
טאבי הסינון בתיבת צ'אט לקוחות הקצה (הכל / הסלמות / טופל) הוחלפו בצ'יפים באותו עיצוב בדיוק כמו בתיבת הצ'אט העסקי: אייקון ייעודי לכל צ'יפ (תיבה / משולש אזהרה / וי), בורדר עדין, ריווח קומפקטי, ושורה אחת שנגללת אופקית (כולל גלגלת עכבר, מודע ל-RTL) אם תצר מדי. ספירת ההסלמות החיה (שיחות הדורשות טיפול אנושי) נשמרה — מוצגת כ-badge אדום בתוך צ'יפ 'הסלמות'. ההתנהגות הפונקציונלית של הסינון לא השתנתה.
v01.107.001תיקוןמשלוחים / טופס יצירהתיקון: לא ניתן היה לגלול ברשימות הנפתחות (מועדפות / עיר / לקוח) בטופס יצירת משלוח
ברשימות הנפתחות בטופס יצירת המשלוח — כתובות מועדפות (מוצא / יעד), בחירת עיר ובחירת לקוח — לא ניתן היה לגלול כשהרשימה ארוכה מ-300px.
פרטים נוספים ↓הסתר ↑
ברשימות הנפתחות בטופס יצירת המשלוח — כתובות מועדפות (מוצא / יעד), בחירת עיר ובחירת לקוח — לא ניתן היה לגלול כשהרשימה ארוכה מ-300px. הסיבה: הטופס נפתח בתוך Dialog שנועל גלילה (react-remove-scroll), ותוכן הבורר מרונדר ב-portal מחוץ ל-Dialog, כך שאירועי הגלילה שלו נחסמו. הבעיה צפה כעת כשהמועדפות יכולות להגיע ל-100 כתובות. הפתרון: הבוררים הללו הוגדרו כ-modal, כך שהם פותחים נעילת גלילה משלהם שמתירה גלילה בתוך הרשימה — בלי לפגוע במיקום. בורר הרחוב (typeahead) הושאר ללא שינוי בכוונה כדי לא לשבור את ההקלדה בשדה.
v01.107.000חדשטריגרים / שיווק / CRMminorטריגרים: טאב 'שיווק' חדש — אוטומציות לליד חדש (התראה לקבוצה + חימום ליד)
בדף הטריגרים (/messages/triggers) נוסף טאב שלישי — 'שיווק' — לצד 'הפצה' ו'תפעול'.
פרטים נוספים ↓הסתר ↑
בדף הטריגרים (/messages/triggers) נוסף טאב שלישי — 'שיווק' — לצד 'הפצה' ו'תפעול'. הטאב מאפשר להגדיר שני סוגי אוטומציות שמופעלות אוטומטית בכל פעם שנכנס ליד חדש (מטופס באתר, מהוובהוק של מקורות חיצוניים, או מיצירה ידנית): (1) 'התראה לקבוצה' — שולח הודעה לקבוצת WhatsApp של הצוות (כמו טריגר טעויות המיון) ו/או לרשימת מספרי טלפון, עם פרטי הליד ולינק לכרטיס; (2) 'חימום ליד' — שולח הודעת פתיחה/חימום ישירות לטלפון של הליד החדש, כשהנמען נקבע אוטומטית מהליד. שניהם בנויים על תשתית ה-SystemTriggerSetting הקיימת עם תבניות הודעה הניתנות לעריכה ומשתנים ייעודיים. שליחה היא fire-and-forget — כשל בשליחה לעולם לא חוסם את קליטת הליד. ייבוא לידים מרובה (CSV) אינו מפעיל את הטריגרים כדי למנוע הצפת הודעות.
- טאב 'שיווק' חדש בדף הטריגרים עם סינון וחיפוש משלו, נפרד מטריגרי התפעול
- טריגר 'ליד חדש - התראה לקבוצה' (NEW_LEAD_GROUP): שליחה לקבוצת WhatsApp ו/או רשימת טלפונים בכל ליד חדש
- טריגר 'ליד חדש - חימום ליד' (NEW_LEAD_WELCOME): הודעת חימום אוטומטית לטלפון של הליד
- משתני תבנית ייעודיים ללידים: שם, עסק, טלפון, עיר, מקור, סוכן, לינק לכרטיס ועוד
- מופעל מכל מסלולי קליטת הליד (טופס ציבורי, webhook, יצירה ידנית); ייבוא CSV מוחרג למניעת הצפה
v01.106.000חדשAI / WhatsApp inboxminorאווטר פר-הודעה בצ'אט הקבוצתי + זיהוי צוות מול קבלן לפי טלפון
בצ'אטים קבוצתיים ב-/messages/business-inbox כל הודעה נכנסת מציגה כעת את האווטר של המשתתף שכתב אותה, ובריחוף עליו tooltip עם השם המלא.
פרטים נוספים ↓הסתר ↑
בצ'אטים קבוצתיים ב-/messages/business-inbox כל הודעה נכנסת מציגה כעת את האווטר של המשתתף שכתב אותה, ובריחוף עליו tooltip עם השם המלא. מתחת למכסה נוסף יסוד משותף: כל הודעה נכנסת בקבוצה שומרת מעתה את שולח-המשנה (טלפון + שם ה-WhatsApp), וטלפון השולח מוצלב מול משתמשי הטננט — כך שהמערכת מבחינה בין נציג/ת צוות שלנו (שם אמיתי + אווטר + טבעת ירוקה + תווית 'צוות') לבין משתתף חיצוני (הקבלן — ראשי תיבות בצבע). היסוד הזה גם מאפשר שיוך מדויק לבוט: כל שורה במטח שמגיע למנוע התרחישים מתויגת כעת לפי מחברה — שורות שכתב נציג שלנו מקבלות תיוג [צוות: שם], בעוד הצד השני (הקבלן/הלקוח) נשאר ללא תיוג. ה-classifier הונחה ששורות [צוות] אינן טריגר (הטריגר חייב להגיע מהצד השני), כך שתשובה של נציגת השירות בקבוצת השליח כבר לא נחשבת בטעות כדיווח של הקבלן. בנוסף, הזנת תור הלמידה (כשל/הצלחת מסירה) רצה רק על הודעות הקבלן עצמן, לא על תשובות צוות. התיוג משפיע על הסיווג בלבד ואינו דולף להודעות יוצאות (הן מבוססות תבניות). טכנית: נוספו עמודות sender_phone/sender_name ל-ai_chat_messages, פונקציית resolveGroupSender עם cache פר-טננט, לכידת senderData.sender ב-Green API webhook, וזיהוי השולח ב-API טעינת השיחה ובמנוע התרחישים. כמו כן נוסף, בסגנון WhatsApp, שם השולח המלא מעל ההודעה הראשונה בכל רצף הודעות רצופות מאותו משתתף (בנוסף לאווטר) — בצבע ייחודי פר-משתתף התואם לצבע האווטר, ואנשי צוות מקבלים צבע ירוק ותווית 'צוות'.
- אווטר של שולח ההודעה ליד כל הודעה נכנסת בקבוצה, עם tooltip של השם המלא
- זיהוי צוות מול קבלן לפי הצלבת טלפון השולח מול משתמשי המערכת (טבעת ירוקה + 'צוות' לצוות)
- הבוט מבחין כעת בין תשובת נציג שלנו (תיוג [צוות]) לדיווח של הקבלן/לקוח — תיקון שיוך שגוי בקבוצות
v01.105.001שיפורסריקת מחסן / מוביילסריקת מצלמה: מנוע מהיר יותר (BarcodeDetector) במקום ZXing
סורק המצלמה בדף /shipments/scan עבר מ-@zxing/browser למנוע BarcodeDetector המובנה של הדפדפן — מהיר משמעותית (פי 2–5 ב-Android/Chrome, מואץ-חומרה), עם נפילה אוטומטית ל-zxing-wasm (ponyfill) ב-iOS Safari ו-Firefox, שגם הוא…
פרטים נוספים ↓הסתר ↑
סורק המצלמה בדף /shipments/scan עבר מ-@zxing/browser למנוע BarcodeDetector המובנה של הדפדפן — מהיר משמעותית (פי 2–5 ב-Android/Chrome, מואץ-חומרה), עם נפילה אוטומטית ל-zxing-wasm (ponyfill) ב-iOS Safari ו-Firefox, שגם הוא מהיר ומדויק יותר מהמנוע הישן. המצלמה נפתחת כעת ב-Full-HD לשיפור קריאה ממרחק. הוסרו התלויות @zxing/browser ו-@zxing/library. כל ה-UI (overlay, מסך שגיאות הרשאה, reticle, פנס) נשאר ללא שינוי. נוסף מסמך STRICH-UPGRADE.md עם מסלול שדרוג מוכן-להפעלה למנוע פרימיום (STRICH) מאחורי NEXT_PUBLIC_STRICH_LICENSE_KEY.
v01.105.000חדשוואטסאפ / בוט לקוחות קצהminorבוט וואטסאפ ללקוחות קצה: מענה אמפתי לפניות "המשלוח מתעכב" עם הסבר התחייבות ההפצה
בוט הוואטסאפ ללקוחות הקצה יודע כעת להתמודד עם פניות מסוג "כבר עברו כמה ימים והמשלוח לא הגיע" / "אמרתם X ימים".
פרטים נוספים ↓הסתר ↑
בוט הוואטסאפ ללקוחות הקצה יודע כעת להתמודד עם פניות מסוג "כבר עברו כמה ימים והמשלוח לא הגיע" / "אמרתם X ימים". הבוט עונה בטון מנומס, מתנצל ומכיל — מכיר בתסכול ובאי-הנוחות — אך מסביר בעדינות שלא חרגנו מההתחייבות שלנו (כשזה המצב): ימי ההפצה נספרים מהרגע שהמשלוח נקלט אצלנו ונאסף מבית העסק, ולא ממועד ההזמנה; לפני כן המשלוח היה ברשות בית העסק השולח. הבוט מסביר שיום האיסוף עצמו לא נספר, שישי/שבת וחגים לא נספרים, ושיעד רגיל = עד 3 ימי הפצה ויעד חריג = עד 7. החישוב משתמש בדיוק באותו מנגנון של דף המעקב הציבורי (delayClockStartedAt + countBusinessDays + סיווג יעד פר-tenant), כך שהמספרים זהים בכל המערכת. אם המשלוח כן חרג מההתחייבות — הבוט מתנצל בכנות ומסלים לנציג אנושי במקום לטעון שהכול תקין.
- מודול חדש computeShipmentSlaContext שמחשב את הקשר ההתחייבות (ימי הפצה שחלפו, האם בתוך החלון, תאריך הגעה צפוי) — אותו חישוב כמו דף המעקב הציבורי
- ה-classifier מקבל את הקשר ה-SLA וסעיף ייעודי בפרומפט: טון מתנצל ומכיל, אך הסבר ברור שספירת ימי ההפצה מתחילה מקליטת המשלוח אצלנו ולא ממועד ההזמנה
- תוך-התחייבות → תשובה מרגיעה (קטגוריה 2) עם תאריך הגעה צפוי כגבול עליון; חריגה מההתחייבות → הסלמה לנציג (קטגוריה 4) עם הערה פנימית
v01.104.001שיפורסריקת מחסן / מוביילסריקה: כפתור 'פתח סורק' מוסתר במחשב
בדף סריקת הברקודים (/shipments/scan) כפתור 'פתח סורק' (מצלמה) מוצג כעת רק במכשירי מגע (טלפון/טאבלט), שם המצלמה היא אמצעי הסריקה הרלוונטי.
פרטים נוספים ↓הסתר ↑
בדף סריקת הברקודים (/shipments/scan) כפתור 'פתח סורק' (מצלמה) מוצג כעת רק במכשירי מגע (טלפון/טאבלט), שם המצלמה היא אמצעי הסריקה הרלוונטי. במחשב — שבו סורקים עם קורא USB דרך שדה הקלט הנסתר — הכפתור מוסתר לחלוטין. הזיהוי מבוסס על יכולת מגע אמיתית (pointer: coarse) ולא על רוחב מסך, כך שטאבלט מציג את הכפתור ואילו חלון דפדפן צר במחשב לא. קלט ה-USB וההקלדה הידנית נותרו ללא שינוי. נוסף hook משותף useHasTouch.
v01.104.000שיפורתשתית / כלל-מערכתminorסבב שדרוגים בטוחים — ביצועים, אבטחה, אמינות, בדיקות ו-DevX
סבב רחב של שיפורים שעברו ביקורת רב-שלבית ואומתו מול הקוד, כולם תוכננו כאדיטיביים / משמרי-התנהגות כדי לא לשבור דבר קיים.
פרטים נוספים ↓הסתר ↑
סבב רחב של שיפורים שעברו ביקורת רב-שלבית ואומתו מול הקוד, כולם תוכננו כאדיטיביים / משמרי-התנהגות כדי לא לשבור דבר קיים. ביצועים ומסד נתונים: אינדקסים על shipment.meta_message_id ו-cod_tracking.settlement_id לנתיבים חמים (webhook של WhatsApp ותצוגת הזדכות מובייל), caching (withCache, TTL 5 דק') לאנליטיקות נהגים ולקוחות, וטעינה עצלה (next/dynamic) של דיאלוגי ה-PDF הכבדים (react-pdf/pdfjs) כך שלא נטענים ב-bundle הראשוני. אבטחה: דגלי opt-in ל-fail-closed ב-webhooks של ש.נ.ל ו-Green API (ברירת מחדל = התנהגות נוכחית, כי קיים tenant פעיל ללא secret) + אזהרה ברורה כשרצים ללא אימות; הגבלת קצב לפי IP לנתיבים ציבוריים (תוויות שיתוף, מעקב משלוח); ואימות קיום tenant ב-webhook של לידים. אמינות וניטור: timeout (AbortSignal) לכל לקוחות האינטגרציה (konimbo/shopify/woocommerce/cashcow/nopcommerce) כדי שספק תקוע לא יתקע קרון; instrumentation.ts שמנתב שגיאות שרת לא-תפוסות ללוגר; endpoint בריאות GET /api/health; ו-removeConsole בפרודקשן שומר כעת על console.error/warn (היו נמחקים — שחזור נראות בלוגי Vercel). בדיקות: 47 בדיקות חדשות שנועלות הצפנה (round-trip), חילוץ סכום COD (מגן מול באג ה-×100), אימות webhook fail-closed, ונרמול טלפון. נגישות: המרת tooltips של title= ל-Tooltip משותף + aria-label. איכות קוד: איחוד נרמול הטלפון הישראלי למודול קנוני אחד (lib/phone) — 5 מימושים כפולים אוחדו ובאג פיצול-שיחות בדף השליח תוקן. API: חילוץ helpers משותפים (parseJsonBody/parsePagination) ל-v1, זהים-בהתנהגות. DevX: תיקון באג ב-hook של ה-changelog, כלל lint שאוכף את קונבנציית ה-DatePicker, ו-typecheck ל-packages/shared ב-CI. ניקוי: הסרת תלויות מתות (react-datepicker, jsbarcode, zod ב-shared) וקבצי artifact מיותרים מ-git.
- DB: אינדקסים על shipment.meta_message_id ו-cod_tracking.settlement_id (מסירים full table scan מנתיבי webhook/מובייל) + caching לאנליטיקות
- ביצועים: lazy-load של דיאלוגי ה-PDF הכבדים מחוץ ל-bundle הראשוני
- לוגים: removeConsole שומר console.error/warn בפרודקשן — שחזור נראות בלוגי Vercel; + instrumentation.ts ו-/api/health
- אבטחה: opt-in fail-closed ל-webhooks (SNL/Green API), rate-limit לפי IP לנתיבים ציבוריים, אימות tenant ב-webhook לידים
- אמינות: timeout לכל לקוחות האינטגרציה החיצוניים
- בדיקות: 47 חדשות (הצפנה, סכום COD נגד ×100, webhook fail-closed, נרמול טלפון); DevX: תיקון hook, כלל lint ל-DatePicker, typecheck ל-shared ב-CI
- נגישות: המרת 8 tooltips של title= ל-Tooltip משותף + aria-label (כפתורים disabled נעטפים ב-span כדי שה-tooltip ימשיך לעבוד)
- איכות קוד: איחוד נרמול הטלפון הישראלי למודול קנוני אחד (lib/phone) — 5 מימושים כפולים אוחדו, ובאג פיצול-שיחות תוקן
- API: חילוץ helpers משותפים parseJsonBody + parsePagination ל-v1 (זהים-בהתנהגות, ללא שינוי חוזה)
v01.103.000חדשפורטל לקוחות / כתובות מועדפותminorכתובות מועדפות בפורטל — הפרדה בין כתובות מוצא לכתובות יעד
פנקס הכתובות המועדפות של הלקוח בפורטל פוצל לשתי רשימות: כתובות יעד (נמען) וכתובות מוצא (שולח).
פרטים נוספים ↓הסתר ↑
פנקס הכתובות המועדפות של הלקוח בפורטל פוצל לשתי רשימות: כתובות יעד (נמען) וכתובות מוצא (שולח). עמוד ההגדרות 'כתובות מועדפות' מציג כעת שתי לשוניות (יעד / מוצא) עם מונה לכל אחת, וכל כתובת ניתנת לסימון ככתובת יעד, כתובת מוצא, או שתיהן — כתובת המסומנת כשתיהן מופיעה בשתי הרשימות עם תווית 'מוצא + יעד'. בטופס יצירת המשלוח, בורר המועדפות של כתובת המוצא מציג רק כתובות מוצא, ובורר כתובת היעד מציג רק כתובות יעד. גם בייבוא משלוחים, בורר כתובת האיסוף (מוצא) מציג רק כתובות מוצא. כפתור 'שמור במועדפות' על כתובת נמען בפרטי משלוח שומר כברירת מחדל ככתובת יעד. כל הכתובות הקיימות סומנו אוטומטית ככתובות יעד (כפי שנשמרו עד היום), כך שאין רגרסיה. מגבלת הכתובות הוגדלה ל-100 (מאגר משותף לשתי הרשימות).
- שתי רשימות נפרדות — כתובות יעד וכתובות מוצא — בלשוניות בעמוד ההגדרות
- כל כתובת ניתנת לסימון כמוצא / יעד / שתיהן (תווית 'מוצא + יעד')
- בוררי המועדפות בטופס המשלוח ובייבוא מסננים לפי הצד הרלוונטי
- כל הכתובות הקיימות סומנו ככתובות יעד — ללא רגרסיה; המגבלה הוגדלה ל-100
v01.102.000חדשצ'אט לקוחות עסקיים / Inboxminorצ'יפים לסינון תיבת הצ'אט העסקי לפי שיוך — הכל / לקוחות / שליחים / קבלנים / לא משוייכים
מעל רשימת השיחות בצ'אט הלקוחות העסקיים נוספה שורת צ'יפים לסינון מהיר לפי בעל השיחה: הכל, לקוחות, שליחים, קבלנים, ולא משוייכים.
פרטים נוספים ↓הסתר ↑
מעל רשימת השיחות בצ'אט הלקוחות העסקיים נוספה שורת צ'יפים לסינון מהיר לפי בעל השיחה: הכל, לקוחות, שליחים, קבלנים, ולא משוייכים. הסינון מתבצע בצד השרת כך שהוא משתלב נכון עם הדפדוף (keyset pagination) והחיפוש — בחירת קטגוריה טוענת מחדש את העמוד הראשון מסונן. הסיווג נגזר מהשיוך הנוכחי: שיחת לקוח מזוהה (customerId) או קבוצת לקוח → 'לקוחות'; קבוצה המקושרת לשליח שכיר או קבלן פנימי (EMPLOYEE/CONTRACTOR) → 'שליחים'; קבוצה המקושרת לקבלן חיצוני (EXTERNAL) → 'קבלנים'; שיחה ללא לקוח וללא קישור לנהג/לקוח → 'לא משוייכים'. הקישור לקבוצה נקרא מהרשומה העדכנית של הנהג/לקוח (whatsappGroupChatId), כך שגם קבוצות שקושרו אחרי יצירת השיחה מסווגות נכון.
- 5 צ'יפים: הכל / לקוחות / שליחים / קבלנים / לא משוייכים, מעל רשימת השיחות
- סינון server-side שמשתלב עם דפדוף וחיפוש — ללא שבירת ה-pagination
- 'שליחים' = שכיר + קבלן פנימי; 'קבלנים' = קבלן חיצוני בלבד (לפי driverType)
- לכל צ'יפ אייקון ייעודי (לקוח / משאית / לחיצת יד / עיגול מקווקו), בורדר עדין ועיצוב קומפקטי
- שורה אחת שנגללת אופקית; גלגלת העכבר מניעה אותה הצידה (תיקון ל-Windows + עכבר, מודע ל-RTL)
v01.101.001שיפורפורטל לקוחות / משלוחים / SNLאפשרויות עמוד גדולות יותר ברשימת המשלוחים בפורטל הלקוח — עד 1000 בעמוד
לבקשת לקוחות פורטל, אפשרויות מספר המשלוחים לעמוד ברשימת 'המשלוחים שלי' עודכנו מ-25/50/100/250 ל-50/200/500/1000.
פרטים נוספים ↓הסתר ↑
לבקשת לקוחות פורטל, אפשרויות מספר המשלוחים לעמוד ברשימת 'המשלוחים שלי' עודכנו מ-25/50/100/250 ל-50/200/500/1000. במקביל הוּרם תקרת ה-limit ב-API של פורטל המשלוחים מ-500 ל-1000 כדי שהאפשרות החדשה תחזיר באמת 1000 שורות ולא תיחתך בשקט. תוקנו שתי בעיות ב-webhook SNL: (1) webhook ישן/רטרואקטיבי יכול היה להוריד סטטוס COMPLETED חזרה ל-IN_INVENTORY — נוספה הגנת regression שמונעת כל שינוי סטטוס לאחור ממצב סופי; (2) Lionwheel המשיך לדרוס את targetPartnerTaskId של SNL — תוקן באג ב-data-service שבו delete extraFields.targetPartnerTaskId לא השפיע כי shipmentData כבר הועתק, הgarden עבר ל-safeShipmentData.
v01.101.000חדשAPI ציבורי / זמני הפצה / פורטל לקוחותminorנקודת קצה ציבורית להטמעה באתר הלקוח — בדיקת ישוב: יעד רגיל (עד 3 ימים) או חריג (עד 7)
נוספה נקודת קצה ציבורית שלקוחות עסקיים יכולים להטמיע ישירות באתר שלהם: כשהקונה בוחר ישוב, האתר מקבל בזמן אמת האם זה יעד רגיל (עד 3 ימי הפצה) או יעד חריג (עד 7 ימי הפצה).
פרטים נוספים ↓הסתר ↑
נוספה נקודת קצה ציבורית שלקוחות עסקיים יכולים להטמיע ישירות באתר שלהם: כשהקונה בוחר ישוב, האתר מקבל בזמן אמת האם זה יעד רגיל (עד 3 ימי הפצה) או יעד חריג (עד 7 ימי הפצה). GET /api/public/delivery-type/{slug}?city=... — הטננט מזוהה דרך ה-slug הציבורי שלו ב-URL (ללא מפתח סודי, בטוח לקריאה מהדפדפן), עם CORS פתוח ו-rate-limit לפי IP. הבדיקה משתמשת באותו מנגנון פתרון שמות שמשמש את כל המערכת: התאמה מדויקת → נרמול (ניקוד/גרשיים/מקפים) → שמות חלופיים (aliases) → הסרת קידומת/סיומת של 'מושב'/'קיבוץ'/'כפר'/'ישוב'/'יישוב' — כך שגם שם שנכתב בשונה מהרישום הקנוני נתפס נכון. הסיווג רגיל/חריג מחושב לפי ההגדרה הפר-טננט (override של הטננט, אחרת ברירת המחדל הגלובלית), כך שכל חברה רואה את הסיווג שלה. הבקשה מוגבלת בכוונה לישוב בודד בלבד: פרמטר city יחיד, ותווי הפרדה (פסיק/נקודה-פסיק/קו-אנכי/שורה חדשה) נדחים — אין אפשרות לבדיקה מרובת ישובים בבקשה אחת. תשובה כוללת את השם הקנוני שזוהה, deliveryType, isExceptional, maxDeliveryDays ותווית מוכנה לתצוגה. בנוסף, נוסף בפורטל הלקוחות (עמוד 'זמני הפצה') כפתור 'הטמעה באתר שלכם' שפותח מודל עם מדריך קצר ושלוש דרכי הטמעה — פרומט ל-AI (מומלץ), HTML מוכן, ו-cURL — בכל אחת מהן כתובת ה-API כבר כוללת את ה-slug של הלקוח, כך שמה שמעתיקים עובד מיד. ה-slug נשלף בצד שרת מהטננט המשויך ללקוח המחובר.
- GET /api/public/delivery-type/{slug}?city=... — ללא מפתח, CORS פתוח, מזוהה לפי slug של הטננט
- שימוש באותו פותר שמות (aliases + נרמול + הסרת מושב/קיבוץ/כפר/ישוב) כמו כל המערכת
- ישוב בודד בלבד — פרמטר city יחיד, תווי הפרדה נדחים; סיווג רגיל/חריג פר-טננט
- כפתור 'הטמעה באתר שלכם' בפורטל (עמוד 'זמני הפצה') — מודל עם מדריך, פרומט ל-AI, HTML ו-cURL; ה-slug של הלקוח כבר מוטמע בכתובת
v01.100.001תיקוןפורטל לקוחות / משלוחיםביטול משלוח בפורטל הלקוח מסמן 'בוטל' במקום למחוק — המשלוח נשאר גלוי למעקב
תוקן באג שבו לקוח שביטל משלוח בפורטל ('ביטול משלוח') איבד אותו לחלוטין: הפעולה ביצעה מחיקה רכה (deletedAt), וה-soft-delete extension הסתיר את השורה מכל הקריאות — כולל מרשימת המשלוחים של הלקוח עצמו, כך שלא ניתן היה לעקוב …
פרטים נוספים ↓הסתר ↑
תוקן באג שבו לקוח שביטל משלוח בפורטל ('ביטול משלוח') איבד אותו לחלוטין: הפעולה ביצעה מחיקה רכה (deletedAt), וה-soft-delete extension הסתיר את השורה מכל הקריאות — כולל מרשימת המשלוחים של הלקוח עצמו, כך שלא ניתן היה לעקוב אחר משלוחים מבוטלים. כעת ביטול משלוח משנה את הסטטוס ל'בוטל' (CANCELED) ב-additionalData במקום למחוק, כך שהמשלוח נשאר גלוי בפורטל עם תווית 'בוטל' וניתן לסינון. בנוסף, הביטול נדחף גם ל-Lionwheel (status=4) באמצעות הקרדנציאלים הפר-tenant, כדי שנהג לא יאסוף אותו בטעות ושסנכרון עתידי לא יחזיר את הסטטוס. כשל בדחיפה ל-Lionwheel אינו חוסם את הביטול המקומי (נרשם lionwheel_sync=false).
v01.100.000חדשAI / WhatsApp inboxminorמנוע תרחישים לבוט הקבוצות — opt-in פר-חברה, גישור בין שליח ללקוח, ושתיקה כברירת מחדל
הבוט שמגיב בקבוצות WhatsApp (דרך Green API) הוחלף ממענה חופשי לכל הודעה למנוע תרחישים מסודר.
פרטים נוספים ↓הסתר ↑
הבוט שמגיב בקבוצות WhatsApp (דרך Green API) הוחלף ממענה חופשי לכל הודעה למנוע תרחישים מסודר. כל חברה בוחרת אילו תרחישים להפעיל ועורכת את נוסח התגובות בעמוד הגדרות חדש ('תרחישי הבוט'). העיקרון: בכל מקרה שאינו תואם בוודאות תרחיש מופעל — הבוט שותק (precision over recall). חל רק על צ'אטים משויכים (קבוצת לקוח עסקי או קבוצת שליח/קבלן); קבוצה לא-משויכת או הודעה מעורפלת → שתיקה. שני תרחישים בגרסה זו, שניהם גישור בין שתי קבוצות: (1) 'אין מענה' — שליח/קבלן מדווח בקבוצתו שאין מענה מהנמען → הבוט מודיע ללקוח העסקי ושואל על טלפון/הנחיה חלופית → אם הלקוח עונה, הבוט מעביר את העדכון לשליח (ומעדכן טלפון במשלוח אם נמסר מספר). (2) 'צפי מסירה' — לקוח שואל מתי משלוח יימסר → אם משובץ לשליח, הבוט שואל את השליח ומעביר את התשובה (אם תקינה) חזרה ללקוח. מתחת למכסה: registry מרכזי של תרחישים, מסווג Haiku זול שמכיר רק תרחישים מופעלים (ברירת מחדל 'none'→שתיקה), טבלת ai_scenario_relay שזוכרת לאן להעביר חזרה כל תשובה, debounce של 8 שניות שמאחד 'מטח' הודעות לתגובה אחת, ורישום החלטות ל-ai_learning_queue כבסיס ללולאת למידה עתידית. תגובות קצרות בלבד וניתנות לעריכה פר-חברה. צ'אט 1:1 פרטי עם לקוח לא הושפע. הערה: בקבוצות שליח מקושרות, הסוכן ההיברידי החופשי הקודם (הצעות פעולה/תובנות אוטומטיות) הוחלף במנוע התרחישים — יכולות אלו יחזרו בהמשך כתרחישים נוספים. בנוסף שופר פאנל 'פעולות שהבוט מציע' בראש שיחת הקבוצה (משמש להצעות מהמערכת ההיברידית הקודמת): כל הצעה מציגה כעת את מועד יצירתה (שעון + זמן יחסי) ואת הודעת המקור מהקבוצה שהובילה אליה ('מההודעה בקבוצה'), כדי שיהיה ברור מי אמר מה; תוכן ההודעה היוצאת תויג במפורש 'ההודעה שתישלח' ומופיע רק כשהפעולה אכן שולחת הודעה (notifyBusinessCustomer/sendWhatsappToDriver) — עדכון כתובת/סטטוס אינו שולח דבר לאיש אלא מעדכן במערכת; ונמנעות כפילויות: הצעת PENDING קיימת לאותה פעולה+משלוח באותה שיחה מתעדכנת בנימוק/בנתונים האחרונים במקום ליצור כרטיס שני. בנוסף, בדף המשלוח (כרטיסיית 'זיהוי וסטטוס') הערות ה-AI כבר לא משתלטות על הכרטיס ומעוותות את הפריסה: מוצגות 3 ההערות האחרונות בלבד, והשאר מאחורי כפתור 'הצג עוד N הערות' שפותח מודל עם כל ההערות (תוכן מלא + מועד כל אחת). זה ממתן את ההצפה שנוצרה כשהסוכן הקודם הוסיף הערה כמעט-זהה על כל הודעה בקבוצה.
- עמוד הגדרות 'תרחישי הבוט' — הפעלה/כיבוי פר-תרחיש + עריכת נוסח התגובות
- שני תרחישי גישור: 'אין מענה' (שליח↔לקוח) ו'צפי מסירה' (לקוח↔שליח)
- בכל ספק הבוט שותק; חל רק על צ'אטים משויכים; debounce שמאחד מטח הודעות לתגובה אחת
v01.99.000חדשפורטל לקוחותminorסימן 'הודפסה מדבקה' על משלוחים בפורטל הלקוחות
לקוחות הפורטל מקבלים כעת סימן ויזואלי על כל משלוח שעבורו כבר הופקה מדבקה — אייקון מדפסת ירוק לצד הברקוד בטבלת המשלוחים (עם tooltip של מועד ההדפסה), ובדף המשלוח המלא + בדראוור התצוגה המהירה מוצג תג 'מדבקה הודפסה' לצד שורת…
פרטים נוספים ↓הסתר ↑
לקוחות הפורטל מקבלים כעת סימן ויזואלי על כל משלוח שעבורו כבר הופקה מדבקה — אייקון מדפסת ירוק לצד הברקוד בטבלת המשלוחים (עם tooltip של מועד ההדפסה), ובדף המשלוח המלא + בדראוור התצוגה המהירה מוצג תג 'מדבקה הודפסה' לצד שורת מועד ההדפסה. נוספה עמודת מעקב label_printed_at למשלוח שמתעדכנת בפעם הראשונה שמופק PDF מדבקה (sticky — לא מתאפסת), מכל מסלולי ההדפסה: הדפסת לקוח מהפורטל (בודד ובאצווה), הדפסת צוות מממשק הניהול, וקישורי שיתוף מדבקה (בודד/מרובה) — כך שהסימן משקף שמדבקה הודפסה ללא תלות במי שהדפיס. העדכון מתבצע כ-fire-and-forget שלא חוסם או מכשיל את הפקת המדבקה.
- אייקון מדפסת לצד הברקוד בטבלת המשלוחים בפורטל, עם מועד ההדפסה ב-tooltip
- תג 'מדבקה הודפסה' + מועד בדף המשלוח ובדראוור התצוגה המהירה
- מעקב הדפסה נרשם מכל מסלולי המדבקה — פורטל (בודד/אצווה), ניהול, וקישורי שיתוף
v01.98.001שיפורתיבת הודעותעיצוב בועות הצ'אט ב-/messages/inbox בסגנון צ'אט הלקוחות העסקיים
בועות הצ'אט ב-/messages/inbox עוצבו מחדש כך שיתאימו לעיצוב הנעים יותר של צ'אט הלקוחות העסקיים (business-inbox) — רק הצ'אט עצמו (בועות, טקסט, מדיה), בלי שינוי בסיידבר/כותרת.
פרטים נוספים ↓הסתר ↑
בועות הצ'אט ב-/messages/inbox עוצבו מחדש כך שיתאימו לעיצוב הנעים יותר של צ'אט הלקוחות העסקיים (business-inbox) — רק הצ'אט עצמו (בועות, טקסט, מדיה), בלי שינוי בסיידבר/כותרת. בועה יוצאת עברה מרקע כהה-מלא (zinc-900/לבן עם טקסט הפוך) ל-tint רך בצבע המותג (bg-primary/10 עם border עדין) וטקסט בצבע foreground רגיל; הבועה הנכנסת רוככה ל-bg-muted/50; ריווח פנימי נדיב יותר (px-3.5 py-2.5) עם leading-relaxed; ושעת/סטטוס ההודעה (✓/✓✓, אדום לכשל, כחול לנקרא) הותאמו לבועה הבהירה. גם המדיה שודרגה בהתאם ל-business-inbox: תמונות וסרטונים גדולים יותר בדסקטופ (md:max-h-96), מדבקות קומפקטיות (max-h-32), ומסמכים מוצגים כקופסה ממוסגרת ('קובץ מצורף') במקום קישור טקסט. אטריביוציית מקור ההודעה (אייקון נציג/AI/מערכת/טריגר) ושאר הפיצ'רים נשמרו במלואם. בנוסף תוקן באג קאש ב-/messages/inbox: בטאבים 'הסלמות' ו'טופל' לא הוצגו צ'אטים במובייל בעוד שבדסקטופ עבדו — iOS Safari קישש תגובת API ריקה לכל URL של ?filter= (מהזמן שבו הטבלה המנורמלת whatsapp_conversations הוזרמה והעמודות status/last_message_dir היו עדיין ריקות) והגיש אותה גם אחרי רענון. נוסף Cache-Control: no-store לתגובות (conversations + counts) ו-cache:"no-store" לבקשות הלקוח, כך שרשימת השיחות והספירות נטענות תמיד טריות בכל מכשיר. המשך כוונון לזהות מלאה: כיוון הצד והצבעים זהים כעת ל-business-inbox — הודעה יוצאת ממוקמת באותו צד (flex-row-reverse) כמו ב-business-inbox, וצבע הבועה היוצאת נקבע לפי מחבר ההודעה: נציג אנושי = ירוק (emerald), AI/אוטומטי/מערכת = סגול המותג, נכנסת = muted — בדיוק כמו ההבחנה assistant/staff שם. גם פינת ה'זנב' של הבועה הותאמה (rounded-tr/tl). בנוסף תוקן סקלטון טעינה ייעודי לצ׳אט בניווט: בניווט client-side בין /messages/inbox ל-/messages/business-inbox הוצג סקלטון של טבלה (יורש מ-messages/loading.tsx האב) במקום סקלטון צ׳אט. נוסף loading.tsx ייעודי לכל אחד משני דפי הצ׳אט שמרנדר שלד בצורת צ׳אט (סיידבר רשימה + אזור שיחה ריק), כך שגם בניווט וגם בריענון מופיע אותו סקלטון. לבסוף אוחד צבע הבועה היוצאת: בועה יוצאת ירוקה אחידה בשני הצ׳אטים (emerald) ללא קשר למחבר — ב-/messages/inbox היה סגול (לפי מקור: טריגר/AI) וב-business-inbox assistant היה סגול; כעת כל הודעה יוצאת ירוקה בשני הדפים, נכנסת נשארת אפורה. ההבחנה בין מחברים נשמרת דרך אייקון המקור/תפקיד ולא דרך צבע הבועה. כמו כן סיידבר רשימת הצ׳אטים הורחב בדסקטופ ל-380px (md:w-95) בשני הצ׳אטים — היה צר (320px) ביחס לכמות הנתונים בכל כרטיס, על חשבון פאנל הצ׳אט שהיה רחב מדי (הוא flex-1 ומתכווץ אוטומטית). רלוונטי לדסקטופ בלבד; במובייל הרשימה נשארת ברוחב מלא. השלד בטעינה עודכן בהתאם. כמו כן אוחד שלד הטעינה הפנימי של business-inbox לסקלטון היפה: בריענון הדף הופיע שלד פנימי מכוער (בלוקים h-16 ריקים) בעוד בניווט הופיע השלד היפה של loading.tsx (אווטאר + שתי שורות טקסט). חולץ רכיב ConversationCardsSkeleton משותף שמשמש גם את loading.tsx וגם את מצב הטעינה הפנימי, כך שהסקלטון זהה ויפה בשני המצבים. בנוסף תוקנו שלושה דברים בצ׳אט לקוחות הקצה (/messages/inbox): (1) באג תאריך — ה-classifier לא קיבל את התאריך הנוכחי ולכן ניחש שגוי איזה יום זה 'יום ראשון' (חשב 23.6 במקום 21.6); כעת מוזרק להקשר התאריך הנוכחי באזור-זמן ישראל + טבלת הימים הקרובים עם שמות הימים בעברית, וה-AI ממפה מתוכה ולא מנחש. (2) הסלמה — בקשת הגבלת מועד מסירה (אל תספקו לפני/רק אחרי/החזיקו עד תאריך) מסווגת כעת כקטגוריה 4 (הסלמה לאדם) במקום שה-AI יאשר ויבטיח תיאום מול השליח שאיננו יכולים לאכוף; הובהר ההבדל בין 'אהיה בבית ביום X' (זמינות, cat 2) להגבלה קשיחה (cat 4). (3) עיצוב — הרווח האנכי בין בועות ההודעה הוגדל מ-2px ל-8px (mb-0.5→mb-2). כמו כן תוקן ששיתוף מיקום מלקוח הקצה מוצג כקישור למפה (/messages/inbox): הודעת location של WhatsApp הוצגה כ'קובץ מצורף' ריק ולא ניתן לפתיחה, כי ה-webhook שמר רק type=location בלי הקואורדינטות. כעת ה-webhook לוכד את ה-lat/long ושומר קישור Google Maps (וגם שם/כתובת אם סופקו), וה-UI מציג את ה-location כקישור-מפה לחיץ עם אייקון נעץ (גם בתצוגה המקדימה ברשימה — 'מיקום'). חל על הודעות מיקום חדשות; הודעה ישנה שכבר נשמרה בלי קואורדינטות תוצג כ'מיקום שהתקבל' ללא קישור. לבסוף הוקשח ה-Service Worker כדי שעדכוני קוד יגיעו אוטומטית: התברר שמשתמש במובייל המשיך לראות רשימת 'הסלמות'/'טופל' ריקה גם אחרי מחיקת קאש (בעוד שבלשונית פרטית עבד) — כי ה-SW המשיך להגיש את ה-build הישן. ה-SW כבר לא מקאש את ה-HTML של מסלולי האפליקציה (shell מאומת שמצביע על chunks של ה-build הנוכחי) — ניווטים תמיד נטענים מהרשת, ורק אם אין רשת מוצג דף offline; וגרסת הקאש הועלתה (v1→v2) כך שה-SW החדש מוחק את הקאש הישן בהפעלה. כך deploy חדש מגיע למכשירים בלי צורך בניקוי ידני. בנוסף תוקנו הסלמות-שווא של שיחות שכבר טופלו (/messages/inbox): שיחה שטופלה הופיעה שוב תחת 'הסלמות' רק כי הלקוח שלח 'תודה' סוגרת — כל הודעה נכנסת איפסה את הסטטוס ל-pending. שני תיקונים: (1) תשובת נציג אנושי מהתיבה מסמנת את השיחה כ-handled (קודם תשובה ידנית לא שינתה סטטוס); (2) אישור-סיום קצר בלבד ('תודה'/'תודה רבה'/👍/אוקיי וכו', allowlist מחמיר) שמגיע לשיחה שכבר handled — משאיר אותה handled במקום להחזיר ל-pending. כך 'תודה' סוגרת לא פותחת מחדש שיחה פתורה. תוקן באג שורש משמעותי: הודעות המשך מלקוח הקצה לא עובדו ע״י ה-AI (ולכן עדכוני כתובת/קומה/טלפון שהלקוח כתב לא הוחלו, ושיחות נתקעו ב'הסלמות'). ב-scheduleDeliverySession ה-fallback לאיתור המשלוח לפי טלפון השתמש בהתאמה מדויקת (phone = '972…'/'0…'), אבל טלפוני משלוחים מאוחסנים בפורמטים שונים (למשל '+972…') — כך שאחרי שתשובה (נציג/AI) שינתה את ה-wamid האחרון, הודעת המשך של הלקוח לא מצאה משלוח ולא נוצר סשן AI כלל. ה-fallback עבר להתאמה מנורמלת (regexp_replace ספרות-בלבד, עם MATERIALIZED CTE שמכריח את אינדקס הטלפון) — כך כל הודעת המשך מאתרת את המשלוח ומקבלת סשן AI. כמו כן (בדומה ל-location) שיתוף איש קשר (contacts) מוצג כשם+טלפון: כשלקוח משתף כרטיס איש-קשר ב-WhatsApp (type=contacts), קודם הוצג 'קובץ מצורף' ריק כי ה-webhook שמר רק את הסוג; כעת ה-webhook לוכד את השם והטלפון(ים) של אנשי הקשר כתוכן ההודעה, וה-UI מציג אותם בתיבת איש-קשר עם אייקון (ובתצוגה המקדימה — 'איש קשר'). שימושי במיוחד כשהלקוח משתף את המספר הנכון של הנמען. כמו כן תוקנה הגלילה בצ׳אט הלקוחות העסקיים (business-inbox): גלילה אחורה לקריאת הודעות קודמות 'נחטפה' חזרה לתחתית כל כמה שניות, כי ה-polling (כל 8 שניות) החליף את מערך ההודעות והפעיל מחדש את הגלילה-לתחתית בכל מחזור — גם כשלא נכנסה הודעה חדשה. כעת הגלילה האוטומטית קורית רק בפתיחת שיחה (קפיצה מיידית לתחתית) או כשבאמת נכנסה הודעה חדשה ורק אם המשתמש כבר קרוב לתחתית; אם גלל למעלה לקרוא היסטוריה — לא נוגעים במיקום הגלילה שלו. בנוסף רוסן הבוט שמגיב בקבוצות לקוח ב-business-inbox: הוא נהג להגיב לכל הודעה בודדת (גם תמונות, 'וזה הבית', 'אפשר להשאיר בתיבה?'), לערום כמה תגובות ארוכות באותה שיחה (race condition כשכמה הודעות הגיעו באותה שנייה — כל webhook הריץ סוכן בנפרד), לכתוב 'מאמרים' ארוכים, ואפילו לפרש מספר טלפון/@אזכור כברקוד. כעת: (1) debounce של 8 שניות לקבוצות שמאחד 'מטח' הודעות לתגובה אחת במקום אחת-לכל-הודעה; (2) prompt ייעודי לקבוצות עם כללי התערבות מפורשים — הבוט עונה אך ורק על שאלת סטטוס עם ברקוד ברור, בקשה מפורשת לפתוח בירור עם ברקוד, או שאלת כמות/סיכום מהלקוח; (3) בכל מקרה אחר או בכל ספק — הבוט פולט סנטינל [NO_REPLY] ופשוט שותק (precision over recall); (4) תגובות קצרות בלבד (שורה-שתיים, סטייל וואטסאפ, ללא כותרות/רשימות, maxTokens מוקטן); (5) pre-filter שמדלג על מטח לא-מהותי (תמונה בלבד / אישור קצר). צ'אט 1:1 פרטי עם לקוח לא הושפע — ההתנהגות הקיימת נשמרה. נוסף טאב 'בעיבוד' חדש בתיבת ההודעות (/messages/inbox): עד כה כל הודעה נכנסת נכנסה ל'הסלמות' מיד — גם בזמן שהבוט עומד לטפל בה (debounce 60ש + cron), מה שגרם לנציגים לקפוץ ולענות בזמן שהבוט גם עונה. כעת כשנוצר סשן AI להודעה, השיחה מסומנת 'processing' ומופיעה תחת טאב 'בעיבוד' (אייקון שעון-חול + מונה כחול) ולא תחת 'הסלמות'; כשהבוט מסיים — היא עוברת אוטומטית ל'טופל' או ל'הסלמות' (אם הוסלמה). הודעה שאין לה סשן (אין משלוח/סוג לא נתמך) ממשיכה ישר ל'הסלמות'. נוסף גם חיווי 'בעיבוד' על כרטיס השיחה, וה-counts/סינון עודכנו כך ש-processing לא נספר כהסלמה. נוסף טשטוש עדין מתחת לאינפוט בצ׳אט (/messages/inbox): שכבת backdrop-blur עדינה (2px) ברצועה התחתונה של אזור ההודעות, עם מסכת gradient שחזקה ביותר מתחת לתיבת הקלט ומתעמעמת כלפי מעלה — כך שההודעות מקבלות מראה 'זכוכית מט' רק כשהן חולפות מתחת לאינפוט, בלי לטשטש את שאר השיחה. תוקן באג: תמלול הודעה קולית נשמר ומוצג — ה-webhook תמלל אודיו אך שמר את ההודעה לפני התמלול (body=null), כך שהתמלול אבד: הנציג לא ראה טקסט וה-classifier לא עיבד את תוכן ההקלטה. כעת התמלול נשמר על שורת ההודעה אחרי שהוא מוכן, מוצג בבועה מתחת לנגן עם תווית 'תמלול אוטומטי', והבוט מעבד את מה שהלקוח אמר בפועל (במקום שההקלטה תיתקע ללא מענה). שופרו מהירות ויעילות העדכונים (polling מהיר ויעיל ב-/messages/inbox): במקום לשלוף את רשימת השיחות + counts + הודעות הצ׳אט הכבדות כל 15ש׳, הלקוח בודק כעת כל 5ש׳ דגל-שינוי זעיר (endpoint חדש /version שמחזיר רק MAX(updated_at) של השיחות + MAX(occurred_at) של הצ׳אט הפתוח — שאילתה אחת מאונדקסת; נוסף אינדקס (tenant_id, updated_at desc)), ושולף את הנתונים הכבדים רק כשהדגל זז. בנוסף ה-polling נעצר לחלוטין כשהטאב מוסתר ומתרענן מיידית כשחוזרים אליו, עם רשת-ביטחון של רענון מלא כל 60ש׳. התוצאה: latency ~5ש׳ במקום 15ש׳, רענון מיידי בפוקוס, וכמעט אפס עומס DB כשאין שינוי/כשהטאב ברקע.
v01.98.000חדשAI / WhatsApp inboxminorהבוט הופך לאיש צוות תפעולי בקבוצות WhatsApp
הבוט שצורף לקבוצות שליחים ולקוחות מתקדם מ"קורא" ל"איש צוות תפעולי".
פרטים נוספים ↓הסתר ↑
הבוט שצורף לקבוצות שליחים ולקוחות מתקדם מ"קורא" ל"איש צוות תפעולי". שלב 1 (קישור קבוצות): ניתן לקשר כל שיחת קבוצה ב-business-inbox לשליח או ללקוח בלחיצה (כפתור 'קשר קבוצה' בכותרת השיחה, עם בורר חיפוש) — כך הבוט יודע לשייך את הקבוצה ולפעול עליה (קובע whatsappGroupChatId). קבוצה לא-מקושרת מסומנת, ומקושרת מציגה צ'יפ עם השם. שלב 2 (הבנת מדיה): הקלטות קוליות נכנסות מתומללות אוטומטית (Whisper) כך שהבוט מבין ומסווג אותן, ותמונה/אודיו עם טקסט (כיתוב או תמלול) מפעילים את הסוכן במקום להידלג. (דורש מפתח תמלול OpenAI מוגדר לחברה.) שלב 3 (סוכן תפעול היברידי — backend): בקבוצת שליח מקושרת, הודעה תפעולית מפעילה כעת סוכן AI אוטונומי שמבצע לבד פעולות בטוחות/הפיכות (הוספת הערת AI, תזמון MARK_FAILED מותנה, תובנות) — ומציע פעולות רגישות (שינוי סטטוס, עדכון כתובת, שליחה ללקוח/שליח) דרך proposeAction לאישור צוות, במקום לבצען לבד. ההצעות נשמרות בטבלת ai_action_proposals. קבוצה לא-מקושרת ממשיכה במסלול ה-Haiku הפשוט. (פאנל אישור ההצעות בשלב הבא.) שלב 3b (אישור הצוות): נוסף פאנל 'פעולות שהבוט מציע' בראש שיחת הקבוצה ב-business-inbox — כל הצעה מוצגת עם הפעולה, הנימוק, ותוכן ההודעה (אם רלוונטי) + כפתורי 'אשר ובצע' / 'דחה'. אישור מבצע את הכלי בפועל (מיוחס למאשר ב-audit) ומסמן את ההצעה כבוצעה; דחייה סוגרת אותה. שלב 4 (תיקון אישורי-מסירה): אותר שורש 69 אישורים שפגו ו-0 שאושרו — ה-Meta webhook התאים תשובות אישור-מסירה רק להודעת טקסט, אבל לקוחות עונים לתבנית גם דרך כפתור Quick Reply / interactive / ריאקציית 👍. כעת כל סוגי התגובות נתפסים (חולץ הטקסט מ-button/interactive ונוסף לטיפוס ולגוף ההודעה), כך שאישור מסירה אמיתי מסמן את המשלוח כנמסר. (תגובות שליח קוליות כבר מטופלות דרך התמלול בשלב 2.) שלב 5 (לולאת למידה לקבוצות): סוכן התפעול של הקבוצות משתמש כעת בתובנות המאושרות (הזרקה להנחיות) וכותב תובנות חדשות בעצמו (addEntityInsight) על דפוסי שליחים/לקוחות. בנוסף, תוצאות מסירה משליחים בקבוצות (כשל/הצלחה) מוזנות לתור הלמידה (ai_learning_queue) כך ש-ai-learning-digest כורה דפוסים פר-שליח אוטומטית — משלים את לולאת הלמידה (שתשתיתה נבנתה במקביל) גם לצד השליחים. כמו כן הוסרה תווית הטריאז' 'ממתין' מכרטיסי השיחות ב-business-inbox (יותרה כמיותרת); אייקון ה-✨ למענה-AI נשאר. בנוסף נוסף כפתור 'סנכרן קבוצות' בכותרת ה-business-inbox: שיחת קבוצה הופיעה ברשימה רק אחרי שעברה בה הודעה, אז קבוצות שקטות מאז שהעוזר צורף לא הופיעו. הכפתור מושך מ-Green API (getContacts) את כל הקבוצות שהעוזר חבר בהן ויוצר רשומת שיחה לכל קבוצה שעדיין לא ברשימה — כך ניתן לראות ולקשר את כולן מיד.
- קישור קבוצה → שליח/לקוח מתוך כותרת השיחה ב-business-inbox
- בורר חיפוש לשליחים/לקוחות + סימון קבוצות שכבר מקושרות
- שלבים הבאים: הבנת אודיו/תמונה, סוכן תפעול היברידי, ולולאת למידה
v01.97.001תיקוןמשלוחים / שיבוץ שליחיםשיבוץ שליח מסירה מעדכן אוטומטית את סטטוס המשלוח לפי סוג השליח
תוקן באג שבו סטטוס המשלוח לא השתנה בשיבוץ קבלן הפצה חיצוני שאינו ש.נ.ל (למשל 'זיפ') — המשלוח נשאר תקוע על 'נקלט במחסן'.
פרטים נוספים ↓הסתר ↑
תוקן באג שבו סטטוס המשלוח לא השתנה בשיבוץ קבלן הפצה חיצוני שאינו ש.נ.ל (למשל 'זיפ') — המשלוח נשאר תקוע על 'נקלט במחסן'. עד כה שינוי הסטטוס ל'בהעברה' התרחש רק כתופעת לוואי של שידור ל-SNL (לפי providerCode) ולא לפי סוג השליח, כך ש-ש.נ.ל עבד במקרה בלבד. כעת, בשיבוץ שליח לביקור פתוח — בין אם דרך סריקת הוצאת מחסן, שיבוץ ידני מדף המשלוח, או שיבוץ מרובה מהמפה — הסטטוס מתעדכן לפי הכלל: ביקור מסירה לקבלן חיצוני → 'בהעברה'; ביקור מסירה לקבלן פנימי/שכיר → 'יצא להפצה'; ביקור איסוף → 'נאסף'. ספקי שידור (SNL / שותף פנימי) ממשיכים לקבל את הסטטוס דרך מסלול השידור שלהם. השינוי כולל דחיפת סטטוס ל-Lionwheel, חותמות sticky (inTransferAt/outInventoryAt), זיכוי עמלה, אירוע realtime ויומן ביקורת — בהתאם לדפוס עדכון הסטטוס הקיים.
v01.97.000חדשAI / תובנותminorתובנות ה-AI נסגרות למעגל למידה — העוזר קורא ומשתמש בהן בפועל
עד היום העוזר הדיגיטלי רק כתב תובנות (על שליח/לקוח/משלוח/חברה) — אך מעולם לא קרא אותן חזרה, כך שהידע הצטבר בעמוד 'תובנות AI' בלי להשפיע על התשובות.
פרטים נוספים ↓הסתר ↑
עד היום העוזר הדיגיטלי רק כתב תובנות (על שליח/לקוח/משלוח/חברה) — אך מעולם לא קרא אותן חזרה, כך שהידע הצטבר בעמוד 'תובנות AI' בלי להשפיע על התשובות. כעת המעגל נסגר: כשהעוזר שולף פרטי משלוח או לקוח, הוא מקבל גם את התובנות המאושרות הרלוונטיות לאותו משלוח, ללקוח שלו ולשליח המשויך (שליפה ממוקדת — רק מה שנוגע לשאלה, לא כל בסיס הידע), וידע כללי מאושר ברמת החברה מוזרק לראש ההנחיות. רק תובנות בסטטוס 'אושר' משפיעות — ניחושים שטרם אושרו לעולם לא. במקביל הועלה רף האיכות של הלמידה האוטומטית (דורשת דפוס חוזר וניתן להכללה, לא הערה נקודתית), נוסף מנגנון מניעת כפילויות בכל מסלולי הכתיבה, וניהול התובנות בעמוד ההגדרות שודרג: אישור/דחייה זמינים תמיד (לא רק על 'ממתין'), עריכת תוכן תובנה, סימון תובנות ישנות (120+ יום) עם אפשרות 'אמת מחדש', אינדיקציית מקור (נוצר תוך כדי שיחה), ותג מונה של תובנות הממתינות לאישור בתפריט הצד.
- העוזר קורא תובנות מאושרות רלוונטיות בעת שליפת משלוח/לקוח — שליפה ממוקדת לפי ההקשר
- ידע מאושר ברמת החברה מוזרק להנחיות; רק סטטוס 'אושר' משפיע על תשובות
- רף איכות גבוה יותר ללמידה האוטומטית + מניעת כפילויות בכל מסלולי הכתיבה
- ניהול משופר: אישור/דחייה תמידיים, עריכת תובנה, סימון 'ישנה' + 'אמת מחדש', אינדיקציית מקור
- תג מונה לתובנות ממתינות לאישור בתפריט הצד
- כלי getDriverDetails חדש לעוזר — פרטי שליח מלאים (סוג, סטטוס, עומס משימות, מסירות/כשלים ב-30 יום) + תובנות מאושרות עליו
v01.96.001שיפוראינטגרציות / e-shopתמיכה ב-Static Egress IP לאינטגרציות הדורשות IP allow-list (אישופ/e-shop)
נוספה שכבת proxy יוצא בעל כתובת IP קבועה: כשמוגדר משתנה הסביבה EGRESS_PROXY_URL, קריאות ה-API היוצאות לאישופ (e-shop) מנותבות דרך proxy בעל IP יציב — כדי לעמוד בדרישת אישופ ל-allow-list של הכתובת שממנה אנו פונים ל-API של…
פרטים נוספים ↓הסתר ↑
נוספה שכבת proxy יוצא בעל כתובת IP קבועה: כשמוגדר משתנה הסביבה EGRESS_PROXY_URL, קריאות ה-API היוצאות לאישופ (e-shop) מנותבות דרך proxy בעל IP יציב — כדי לעמוד בדרישת אישופ ל-allow-list של הכתובת שממנה אנו פונים ל-API שלהם. נדרש מכיוון ש-Shipnest רץ על Vercel serverless, שיוצא מ-pool של כתובות IP מתחלפות וללא IP יציב יחיד. ה-helper החדש (lib/egress-proxy.ts, fetchViaEgress) טוען את undici ProxyAgent רק כשה-proxy מוגדר בפועל, כך שברירת המחדל (ללא proxy) זהה ל-fetch רגיל — no-op מוחלט. השינוי מבודד לאדפטר של e-shop בלבד ואינו נוגע בשאר המערכת, וניתן לשימוש חוזר לכל שותף עתידי שדורש IP allow-listing.
v01.96.000חדשמשלוחים / תמחורminorעלות איסוף ועלות מסירה לכל משלוח — לצד המחיר ללקוח והרווח
לכל משלוח, בנוסף למחיר שהלקוח משלם, נשמרות כעת שתי עלויות ביצוע: עלות האיסוף ועלות המסירה — כל אחת מתומחרת לפי מחירון השליח שביצע בפועל את המשימה (תעריף בסיס, אזורי תעריף, חבילות נוספות וכללי תמחור — בדיוק כמו בתחשיב התש…
פרטים נוספים ↓הסתר ↑
לכל משלוח, בנוסף למחיר שהלקוח משלם, נשמרות כעת שתי עלויות ביצוע: עלות האיסוף ועלות המסירה — כל אחת מתומחרת לפי מחירון השליח שביצע בפועל את המשימה (תעריף בסיס, אזורי תעריף, חבילות נוספות וכללי תמחור — בדיוק כמו בתחשיב התשלום החודשי לשליח). התמחור נשמר ברגע השלמת המשימה: עלות האיסוף מופיעה כשהאיסוף הושלם, ועלות המסירה כשהמסירה הושלמה. כששליח אוסף 2+ משלוחים מאותו לקוח באותו יום מוחל תעריף האיסוף העסקי המקובץ (זהה לתשלום החודשי). העלות מחושבת מחדש אוטומטית אם השליח של המשימה משתנה או אם עורכים את מחירון השליח בדיעבד. בכרטיסיית 'תמחור' של המשלוח נוסף בלוק 'עלויות ורווח' (עלות איסוף, עלות מסירה, סה"כ עלות ורווח = מחיר − עלויות), ובטבלת המשלוחים נוספו עמודות אופציונליות 'עלות איסוף', 'עלות מסירה' ו'רווח'. הנתונים הפיננסיים האלה גלויים רק למשתמשים עם הרשאת 'צפייה בפיננסים' (finance:view).
- עלות איסוף ועלות מסירה פר-משלוח, לפי מחירון השליח שביצע
- תמחור נשמר ברגע השלמת המשימה, ומחושב מחדש אוטומטית בשינוי שליח/מחירון
- תעריף איסוף עסקי מקובץ — זהה לתחשיב התשלום החודשי
- בלוק 'עלויות ורווח' בכרטיסיית התמחור + עמודות אופציונליות בטבלה
- מוגבל להרשאת finance:view
v01.95.004שיפורפורטל לקוחות / תוויותבורר התוויות בפורטל הלקוחות מציג צ'יפים במקום רשימת שורות
בעקבות בקשת לקוחות — רשימת התוויות שנפתחת בעת שיוך תווית למשלוח בפורטל הוסבה מרשימת שורות עם תיבות-סימון לתצוגת צ'יפים צבעוניים בפריסת flex-wrap.
פרטים נוספים ↓הסתר ↑
בעקבות בקשת לקוחות — רשימת התוויות שנפתחת בעת שיוך תווית למשלוח בפורטל הוסבה מרשימת שורות עם תיבות-סימון לתצוגת צ'יפים צבעוניים בפריסת flex-wrap. שני בוררי התוויות הומרו: (1) TagAssignPopover — המשמש בדף המשלוח, בעמודת הטבלה, בבחירה מרובה ובסינון; (2) TagMultiSelect — בורר התוויות בטופס הקמת משלוח חדש (וגם באשף הייבוא). תווית משויכת מוצגת כצ'יפ מלא בצבע התווית עם וי, תווית לא-משויכת כצ'יפ עם מתאר ונקודת צבע, ובבחירה מרובה מצב חלקי מוצג כצ'יפ דהוי עם מינוס. גם פעולת 'צור תווית' הפכה לצ'יפ מקווקו בתוך אותה פריסה. עקבי עם הצ'יפים הקיימים (TagBadge) המציגים תוויות נבחרות.
v01.95.003תיקוןטריגרים / הודעותהודעת 'נוצר משלוח' תישלח ללקוח פעם אחת בלבד — לתמיד
חיזוק לתיקון הקודם של הטריגרים, בעקבות לקוחה שקיבלה 7 הודעות על אותו משלוח (רובן הודעת 'נוצר משלוח').
פרטים נוספים ↓הסתר ↑
חיזוק לתיקון הקודם של הטריגרים, בעקבות לקוחה שקיבלה 7 הודעות על אותו משלוח (רובן הודעת 'נוצר משלוח'). התיקון הקודם סגר את הנתיב שבו סנכרון ידני (manual-sync) שידר מחדש את task_created דרך הברירת-מחדל מהסטטוס. אבל נשארו שתי פרצות: (1) הענף המפורש — webhook מליונוויל שה-trigger_field שלו עצמו הוא 'task_created' — שנשלח ללא תנאי, כך ש-re-delivery של אותו webhook יכול לברך את הלקוח מחדש; (2) backlog של הודעות מתוזמנות שכבר נוצרו לפני התיקון (כשזמן השליחה של הטריגר אינו 'מיידי'), שממשיכות להישלח ע"י ה-cron. התיקון הופך את task_created ל-idempotent — נשלח פעם אחת בלבד לכל משלוח: לפני השליחה נבדק ב-auditLog אם כבר נרשמה שליחת task_created מוצלחת למשלוח הזה, ואם כן — מדלגים (כולל מניעת יצירת הודעה מתוזמנת חדשה). בנוסף נוסף שומר ב-cron של ההודעות המתוזמנות: הודעת task_created שכבר נשלחה למשלוח נזרקת מהתור במקום להישלח, כך שגם backlog היסטורי לא יבריך מחדש לקוח. הבהרה חשובה: ההודעות שהלקוחה כבר קיבלה נשלחו לפני שהתיקון עלה לפרודקשן; מרגע ה-deploy כל משלוח יקבל הודעת יצירה אחת בדיוק. בנוסף חוזק תיעוד הודעות הטריגר: ה-catch על recordOutboundMessage במסלול הטריגר הפך מבליעה שקטה ללוג שגיאה (logError), כך שגם כשל-תיעוד נדיר של הודעה שכבר שודרה משאיר עקבה בלוגים ולא נעלם בשקט — אבטחה לכך שהודעות שטריגרים שולחים ששודרו לא ייעלמו מהתיבה.
v01.95.002שיפורנהגים / לקוחותבורר קבוצות WhatsApp בדף הנהג ובדף הלקוח
בכרטיסיית 'פרטים אישיים' בדף הנהג, עריכת קבוצת ה-WhatsApp (Green API) הומרה מ-popover עם הקלדה ידנית בלבד לדיאלוג קטן שכולל את בורר הקבוצות המשותף (כפתור 'בחר קבוצה').
פרטים נוספים ↓הסתר ↑
בכרטיסיית 'פרטים אישיים' בדף הנהג, עריכת קבוצת ה-WhatsApp (Green API) הומרה מ-popover עם הקלדה ידנית בלבד לדיאלוג קטן שכולל את בורר הקבוצות המשותף (כפתור 'בחר קבוצה'). כך אפשר לבחור קבוצה מתוך רשימת הקבוצות של ה-instance במקום להדביק מזהה @g.us ידנית — הבחירה ממלאת אוטומטית גם את מזהה הקבוצה וגם את שמה, וההקלדה הידנית נשארה כגיבוי. עד כה הבורר היה זמין רק בטופס עריכת הנהג; כעת הוא נגיש גם ישירות מדף הנהג. (ההמרה מ-popover לדיאלוג גם נמנעת מ-popover מקונן בתוך popover, שהיה סוגר את החלונית בעת בחירה.) כעת נוסף אותו עורך מהיר (דיאלוג עם בורר הקבוצות) גם לדף הלקוח העסקי — בכרטיס 'קבוצת וואטסאפ' חדש בעמודה הימנית, שמציג את הקבוצה המשויכת ומאפשר בחירה/עדכון ישירות מדף הלקוח (PATCH ל-API של הלקוח, עם הוספת השדות whatsappGroupChatId/whatsappGroupName ל-handler). כך השיוך לקבוצה זמין מדף הישות עצמה — גם לנהגים וגם ללקוחות — ולא רק מטופסי העריכה.
v01.95.001תיקוןטעויות מיוןטעות מיון נשלחה שוב (התראה + וואטסאפ) בכל סנכרון אחרי שטופלה
המשך לתיקון הקודם של הודעות כפולות בסנכרון — הפעם בנתיב טעויות המיון, שהוא נפרד לחלוטין מטריגרי המשלוח ולא הושפע מהתיקון הקודם.
פרטים נוספים ↓הסתר ↑
המשך לתיקון הקודם של הודעות כפולות בסנכרון — הפעם בנתיב טעויות המיון, שהוא נפרד לחלוטין מטריגרי המשלוח ולא הושפע מהתיקון הקודם. כשמשלוח נמצא בטעות מיון (נהג שובץ לאזור שאינו מורשה לו), הזיהוי (detectSortingErrors) רץ על *כל* סנכרון של המשלוח — סנכרון ידני מרענון/ליקוט/פערי-חלוקה/יעד-שבת וכו', וגם כל webhook — בלי בדיקה אם משהו השתנה. ההגנה היחידה מפני כפילות הייתה שאילתת dedup שחיפשה טעות קיימת בסטטוס PENDING בלבד. לכן ברגע שמישהו סימן את הטעות כ'טופלה'/'התעלם' — או שהיא נסגרה אוטומטית ע"י אישור 👍 בקבוצת הוואטסאפ (תרחיש נפוץ במיוחד) — בלי להוסיף בפועל את האזור לנהג, הסנכרון הבא של אותו משלוח (שעדיין עם אותו נהג לא-מורשה ועדיין בסטטוס איסוף/בדרך/החזרה) יצר רשומת טעות חדשה, שידר שוב את ההתראה בזמן-אמת (מודאל אדום + סירנה לכל הדשבורדים הפתוחים של הטננט) ושלח שוב הודעת וואטסאפ לכל הנמענים המוגדרים בטריגר (כל הטלפונים + הקבוצה) — וחוזר חלילה בכל סנכרון. התיקון: שאילתת ה-dedup ב-checkDriverZoneAllowance כבר לא מסננת לפי PENDING — היא מתאימה לטעות קיימת לאותו (ברקוד, נהג, סוג) בכל סטטוס. כך טעות מיון נרשמת ומתריעה פעם אחת בלבד, ולא משוחזרת אחרי שטופלה. שיבוץ נהג *אחר* לאותו משלוח עדיין נחשב טעות חדשה ומתריע כרגיל, כך שלא מפספסים טעויות אמיתיות. בונוס: גם נמנעת הצטברות בלתי-מוגבלת של רשומות טעות מאותו סוג. הובהר אגב שהמילה 'נכשל' שתיארה את התקלה אינה מדויקת — סטטוס FAILED כלל לא נכנס לזיהוי טעויות מיון; המשלוחים שמייצרים את ההתראות הם אלה שבסטטוס בדרך/איסוף/החזרה עם נהג לא-מורשה.
v01.95.000חדשControl Plane / AIminorמעקב שיחות AI בלוח הבקרה
נוסף עמוד ניטור מלא בלוח הבקרה של הפלטפורמה (Control Plane → מעקב AI) המציג את כל שיחות ה-AI בכל הטננטים.
פרטים נוספים ↓הסתר ↑
נוסף עמוד ניטור מלא בלוח הבקרה של הפלטפורמה (Control Plane → מעקב AI) המציג את כל שיחות ה-AI בכל הטננטים. ממשק split-pane: רשימת שיחות עם חיפוש, סינון לפי טננט והקשר, ו-pagination — ולחיצה על שיחה פותחת את כל ההודעות עם עיבוד Markdown, הצגת קריאות לכלים, ומספר טוקנים. מטרה: לאפשר זיהוי כשלים, שיפור prompt וניטור שוטף של התנהגות הדגם. בנוסף תוקן רינדור של הודעות מערכת (system) של WhatsApp ב-/messages/inbox: אירוע מערכת (למשל שינוי מספר טלפון של לקוח) הוצג כקישור-מסמך עם הטקסט הגולמי system שנפתח לטאב ריק (href=#). כעת ה-webhook לוכד את טקסט ההודעה (system.body) ושומר אותו כתוכן ללא mediaType, וה-UI מציג אירועי מערכת כהערה עדינה במקום קישור שבור. כמו כן תווית קובץ מצורף שונתה מהצגת ה-mediaType הגולמי לטקסט קבוע, וקישור נפתח רק כשקיים URL אמיתי. (תוקנה שגיאת type-check שהפילה את ה-build: ב-page של מעקב ה-AI, הביטוי שקבע אם להציג קריאות לכלים פתח ב-msg.toolCalls שטיפוסו unknown, כך ש-hasTools קיבל טיפוס unknown ולא boolean — מה שגרם ל-child מסוג unknown שאינו ReactNode חוקי. הוחלף ל-Array.isArray(...) מוביל שמצמצם ל-boolean.)
- רשימת שיחות עם חיפוש, סינון טננט/הקשר ו-pagination (50 שיחות לעמוד)
- צפייה בשיחה מלאה — בועות הודעה, Markdown, timestamps ומספר טוקנים
- תגיות הקשר צבעוניות: עוזר פנימי (סגול), פורטל לקוחות (כחול), לקוח קצה (ירוק)
- API endpoints מאובטחים עם requirePlatformRole
v01.94.003תיקוןפערי הפצהפערי הפצה — משלוחים הוצגו כ'ללא אזור' למרות שיש להם אזור
בדף 'פערי הפצה', פילטר 'אזור הפצה' הציג משלוחים תחת 'ללא אזור' למרות שבדף המשלוח עצמו מופיע אזור הפצה תקין.
פרטים נוספים ↓הסתר ↑
בדף 'פערי הפצה', פילטר 'אזור הפצה' הציג משלוחים תחת 'ללא אזור' למרות שבדף המשלוח עצמו מופיע אזור הפצה תקין. הסיבה: הרשימה גזרה את האזור מ-regionStr של ביקור ה-DELIVERY (שלעיתים ריק), בעוד דף המשלוח מציג את shipment.regionCode (האזור שנשמר מליונוויל בעת יצירת המשלוח). כעת הרשימה נופלת ל-shipment.region_code כש-regionStr של הביקור ריק (COALESCE), כך שהאזור עקבי בין הרשימה לדף המשלוח. התיקון חל על כל הטאבים ועל פילטר האזור. בנוסף, בעקבות בקשת לקוחות, נוספה עמודה 'ימים אצל השליח' לטבלת פערי ההפצה (וגם בייצוא ל-Excel) — מציגה כמה ימי עסקים המשלוח כבר משובץ לשליח הנוכחי, עם תאריך השיבוץ ב-tooltip. לשם כך נוסף שדה driver_assigned_at על ביקור (Visit) שנקבע בעת שיבוץ שליח (סנכרון מליונוויל, שיבוץ אצווה, או עריכת ביקור) ומתאפס בהחלפת שליח או בביטול שיבוץ — כך הספירה מתחילה מחדש בכל החלפה. הספירה לכל טאב מתבססת על הביקור הרלוונטי (מסירה / איסוף / החזרה). אין חותמת שיבוץ היסטורית מליונוויל, ולכן למשלוחים שכבר היו משובצים בעת ההטמעה הוצב תאריך השיבוץ לרגע ההטמעה (כולם מתחילים מ-0 היום) — הספירה מדויקת לחלוטין מכאן והלאה.
v01.94.002תיקוןטריגרים / הודעותטריגר 'נוצר משלוח' נשלח שוב ושוב למשלוחים ישנים
לקוחות קיבלו את הודעת הוואטסאפ של טריגר 'נוצר משלוח' (task_created) פעמים נוספות, ימים אחרי שהמשלוח באמת נוצר.
פרטים נוספים ↓הסתר ↑
לקוחות קיבלו את הודעת הוואטסאפ של טריגר 'נוצר משלוח' (task_created) פעמים נוספות, ימים אחרי שהמשלוח באמת נוצר. הסיבה: מנגנון בחירת סוג הטריגר היה נופל לברירת מחדל שגוזרת את הטריגר מ*הסטטוס הנוכחי* של המשלוח כש-trigger_field אינו אחד מ-5 הסוגים המוכרים — וסטטוס UNASSIGNED ממופה ל-task_created. כל מסלולי הסנכרון (sync-shipment-status שמופעל מרענון דף המשלוחים, ליקוט, פערי חלוקה, יעד שבת/אקספרס, התראות אזור ושגיאות מיון; וכן manual-sync) שולחים trigger_field='manual-sync'/'manual_sync' שאינו מוכר — כך שכל סנכרון של משלוח שעדיין UNASSIGNED (טרם שובץ לשליח) גזר מחדש task_created ושלח שוב את הודעת ה'נוצר משלוח'. אותה תקלה חלה גם בוובהוק על עדכון לא-קשור (עריכת כתובת, הגדרת גוביינא) למשלוח UNASSIGNED. התיקון: הברירת-מחדל מהסטטוס שוב לא יכולה לסנתז task_created — הודעת 'נוצר משלוח' נשלחת רק כשהשורה באמת נוצרת באירוע הזה (shipmentAction='created') או דרך אות ה-task_created המפורש של ליונוויל; שאר טריגרי מחזור-החיים (שובץ/נמסר/בוטל/נכשל) נשלחים מהברירת-מחדל רק כששינוי הסטטוס באמת התרחש באירוע (previousStatus≠statusMapped), כך שסנכרון חוזר של משלוח ללא שינוי לא שולח כלום. הודעת ה-welcome הלגיטימית שמגיעה מהוובהוק המפורש של ליונוויל לא הושפעה.
v01.94.001תיקוןCRM / הצעות מחירשיפורי הצגה בהצעת מחיר — יישור הנוסח המשפטי ותעריפי 0 ₪
בקובץ ה-PDF של הצעת מחיר שנשלח ללקוח, הערת הנוסח המשפטי שבתחתית ('הצעה זו אינה מהווה התחייבות חוזית מצד הצדדים.
פרטים נוספים ↓הסתר ↑
בקובץ ה-PDF של הצעת מחיר שנשלח ללקוח, הערת הנוסח המשפטי שבתחתית ('הצעה זו אינה מהווה התחייבות חוזית מצד הצדדים. הסכם מחייב טעון חתימה נפרדת.') נדחקה לקצה הימני של העמוד ואף חרגה מעט מעבר לשוליים, במקום לקבל הזחה מימין כמו שאר התוכן בהצעה. הסיבה: react-pdf ממקם את שורת ה-RTL הזו בהיסט קבוע (~13pt) ימינה מקצה הריפוד של הקופסה — תקלת מיקום שורה ב-RTL שגדלה עם אורך השורה ומופיעה רק במסמך המלא. התיקון מוסיף ריפוד-ימני נוסף לכרטיס ההערה (כך שהריפוד השמאלי תואם את שאר הסקציות וההיסט נבלע בריפוד הימני), והטקסט יושב כעת מוזח מהקצה הימני באותו מרווח כמו 'פרטי הלקוח', 'תעריפי בסיס' ו'הערות'. אומת אמפירית ע״י רינדור ה-PDF ומדידת מיקום הגליפים — קצה השורה הימני עבר מ-3pt מעבר לשוליים ל-16pt בתוך השוליים, בהתאמה לשאר הבלוקים, גם בהצעה מינימלית וגם בהצעה מקסימלית בת שני עמודים. בנוסף: תעריפי בסיס שהוגדרו על 0 ₪ ('שירות ללא תשלום') מוצגים כעת ברשימת התעריפים עם '0.00 ₪' במקום להיעלם — גם ב-PDF, גם בתצוגה הציבורית (/q/[token]) וגם בתצוגה הפנימית. שיווקית זה מבליט שירותים ללא עלות. הסינון שונה מ'הסתר אם 0 או ריק' ל'הסתר רק אם השדה חסר ב-JSON' — כך תעריף שהוגדר במפורש ל-0 מוצג, בעוד שדות שכלל לא היו חלק מהצעות ישנות (שנוספו אחרי יצירתן) עדיין מוסתרים.
v01.94.000שיפורזמני הפצה / מחירוןminorסיווג יעד חריג/רגיל — פר-לקוח (במקום גלובלי)
עד היום הסיווג של ישוב כ'יעד חריג' או 'רגיל' היה גלובלי ומשותף לכל הלקוחות, והוא זה שמפעיל גם את תוספת החיוב 'יעד חריג' וגם את זמן האספקה המוצג (3 מול 7 ימים).
פרטים נוספים ↓הסתר ↑
עד היום הסיווג של ישוב כ'יעד חריג' או 'רגיל' היה גלובלי ומשותף לכל הלקוחות, והוא זה שמפעיל גם את תוספת החיוב 'יעד חריג' וגם את זמן האספקה המוצג (3 מול 7 ימים). מאחר שרוב הישובים סווגו כחריגים בברירת מחדל, הפעלת תוספת יעד חריג במחירונים הייתה גורמת לגביית-יתר על כמעט כל משלוח. כעת רשימת הישובים נשארת גלובלית, אבל הסיווג חריג/רגיל הוא פר-לקוח: כל לקוח מתחיל מהמצב הגלובלי הקיים (כברירת מחדל, ללא שינוי) ויכול לסווג מחדש ישובים לעצמו דרך מסך 'זמני הפצה → ישובים'. ה-override חל גם על תוספת החיוב וגם על זמן האספקה בהקשרים שיש בהם לקוח (פאנל החיוב, מעקב, פורטל, כלי AI). בדיקת-המשלוח הציבורית-הגלובלית ממשיכה להציג את ברירת המחדל הגלובלית. בנוסף (business-inbox): סימן המסירה (✓) בהודעה יוצאת מוקם כעת בצד שמאל של הבועה ב-RTL (כמו ב-WhatsApp) במקום בצד ימין. כמו כן נוספה תמונת פרופיל WhatsApp של הלקוח/הקבוצה ב-business-inbox: ה-adapter של Green API שולף את התמונה דרך getAvatar, היא נשמרת ב-cache על ה-session (avatar_url + avatar_checked_at, רענון עצל כל 6 שעות בפתיחת שיחה כדי לא להעמיס על Green API), ומוצגת גם בכותרת השיחה וגם ברשימת הצ׳אטים — עם נפילה אוטומטית לראשי-תיבות כשאין תמונה, היא מוסתרת, או ה-URL פג תוקף. כמו כן עוצב מחדש שדה הכתיבה ב-business-inbox כך שיתאים ל-/messages/inbox: תיבה מעוגלת עם בורר אימוג'י וכפתור שליחה עגול, ונוסף רקע צ׳אט ייחודי (דפוס אלכסוני עדין, שונה מדפוס הנקודות של ה-inbox כדי להבדיל בין הדפים). זהו שלב 1; צירוף קבצים והצגת מדיה נכנסת יגיעו בשלב הבא. בנוסף תוקנו שני פערי פריסה ב-business-inbox: (1) פער מיותר בתחתית הדף — הדף השתמש בגובה קבוע h-[calc(100vh-4rem)] במקום למלא את ה-main בפועל; הוחלף ל-flex-1 min-h-0 (כמו ב-/messages/inbox) כך שאין שוליים בתחתית. (2) רווח חיצוני בין סיידבר רשימת הצ׳אטים לסיידבר הראשי — רקע הסיידבר שונה מ-bg-muted/10 ל-bg-background כך שהוא נבלע ברווח של הסיידבר הצף ונראה צמוד אליו, והריפוד של 8px הפך לפנימי (הוסר md:ps-0). בנוסף נוסף md:-ms-2 ל-root (בדיוק כמו ב-inbox) שמושך את הדף 8px לתוך הרווח של הסיידבר הצף — כך שסיידבר רשימת הצ׳אטים ממש צמוד לסיידבר הראשי ללא שום רווח. כמו כן רוכך קלט החיפוש בראש הסיידבר כך שייטמע ברקע: מילוי muted עדין במקום bg-background לבן, border רך וללא shadow (לא נראה כקופסה צפה), ובפוקוס מבהיר ל-bg-background. שלב 2 (מדיה) הושלם ב-business-inbox: תמיכה בשליחה והצגה של קבצים דרך Green API. נוסף כפתור צירוף (אטב) בתיבת הכתיבה שפותח דיאלוג לבחירת קובץ (תמונה/וידאו/אודיו/מסמך עד 16MB) עם תצוגה מקדימה וכיתוב; הקובץ מועלה דרך sendFileByUpload של Green API (host המדיה הייעודי) ונשמר עם ה-urlFile שהספק מחזיר. מדיה נכנסת (תמונה/וידאו/אודיו/מדבקה/מסמך) שה-webhook קודם זרק — נלכדת כעת מ-fileMessageData.downloadUrl ונשמרת ב-inbox (ללא תגובת AI, כי הסוכן הטקסטואלי לא 'רואה' מדיה). הבועות מציגות תמונות/מדבקות לחיצות, נגן אודיו, נגן וידאו, וקישור למסמכים — עם נפילה לאייקון מתויג כשה-URL חסר. נוספו עמודות media_url + media_type לטבלת ai_chat_messages, וצבע כפתור השליחה שונה מ-zinc לצבע המותג (primary). הערה: שליחת/הצגת מדיה תלויות ב-endpoint וב-downloadUrl של Green API — דורש בדיקה חיה. כמו כן לחיצה על תמונה פותחת כעת חלון תצוגה מעוצב בתוך האפליקציה (lightbox עם זום/הורדה/פתיחה-בטאב/ESC) במקום טאב דפדפן חדש — נלקח מ-/messages/inbox. בנוסף הוגדלה התמונה/וידאו המוצגים בתוך הבועה בדסקטופ (תקרת גובה max-h-60→md:max-h-96) כדי שלא ייראו קטנים מדי, תוך שמירה על הגודל במובייל. כמו כן (תיבת ההודעות /messages/inbox): לכל הודעה יוצאת נוסף אייקון מקור המאפשר לעקוב אחר מי כתב כל תגובה — אווטאר הנציג ששלח (עם שמו בריחוף), אייקון AI לתשובות אוטומטיות של עוזר ה-AI, אייקון מערכת להודעות fallback שלא טופלו, ולוגו העסק להודעות אוטומטיות (טריגרים/מתוזמנות/פרואקטיביות). נוספה עמודה source לטבלת ההודעות שמסמנת את מקור כל שליחה. בנוסף רועננה רשימת הצ׳אטים בסיידבר של /messages/inbox: היא צמודה כעת לסרגל הניווט הראשי (בוטל רווח מיותר של 8px מול הסיידבר הצף), הכותרת שונתה ל'צ׳אט לקוחות קצה', הטאב 'לא טופל' שונה ל'הסלמות', ואזור תוויות הסיכום ('טופל היום' / 'לא טופל') שמעל הטאבים הוסר כמיותר. עוצבו גם שורות השיחה עצמן: לשיחה הפעילה נוסף פס-מבטא בצבע המותג בקצה ההתחלה וטבעת תואמת סביב האווטאר (במקום רק הדגשת רקע), והתצוגה המקדימה התעשרה — הודעה אחרונה יוצאת מקבלת קידומת 'את/ה:', והודעת מדיה ללא טקסט מוצגת עם אייקון לפי סוג (תמונה/וידאו/הודעה קולית/מסמך/מדבקה) במקום '[ מדיה ]'. לשם כך נוסף enrichment חסום ב-API של רשימת השיחות שמביא את סוג המדיה של ההודעה האחרונה לכל טלפון. בנוסף, הודעות מדיה מלקוח הקצה (תמונה/מדבקה/וידאו/מסמך) נכנסות כעת לסיווג ה-AI במקום להישאר תקועות כ'לא טופל': ה-webhook תופס גם את הכיתוב (caption) של המדיה ומתזמן סשן AI גם להודעות מדיה, וה-classifier מקבל את ההודעה כשורת הקשר מתויגת ('[sent an IMAGE]' וכו'). ה-AI מסווג לפי ההקשר — מדבקה כמעט תמיד נחשבת אישור חיובי ונסגרת כטופל, בעוד תמונה/וידאו/מסמך נסגרים כטופל רק כשההקשר חיובי בבירור; אחרת (או כשאין הקשר כלל) הם מוסלמים לבדיקה אנושית עם הערה, כדי לא לפספס למשל תמונה של חבילה פגומה. כמו כן עוצבו כרטיסיות רשימת הצ׳אטים ב-/messages/inbox בסגנון הקרוב ל-business-inbox: מעבר מרשימה צפופה עם קווים מפרידים לכרטיסים מעוגלים (rounded-xl) עם רווחים, מצב פעיל רך (רקע סגול עדין + טבעת פנימית במקום פס-מבטא בקצה), טבעת עדינה סביב האווטאר והקטנתו ל-h-9, ושעה שמתעמעמת בריחוף. כל הפיצ׳רים העשירים נשמרו (באדג' לא-נקרא, צ׳יפ מקור, באדג' AI, אייקון סטטוס מסירה, אייקון מדיה, סמן-כנקרא ותפריט קליק-ימני). בכיוון ההפוך — הובאו ל-business-inbox פיצ׳רים מ-/messages/inbox: (1) צ׳יפ טריאז' 'ממתין' (ענבר) כשהלקוח כתב אחרון ומחכה למענה, ובאדג' ✨ כשה-AI ענה אחרון — שני סיגנלים שנגזרים מ-lastMessageRole ללא backend; (2) תפריט קליק-ימני על כרטיס שיחה (העברה/שחזור מארכיון); (3) רספונסיביות מובייל מלאה — חילוף בין רשימת הצ׳אטים לתוכן הצ׳אט עם כפתור חזרה בכותרת (md:hidden), בדיוק כמו ב-/messages/inbox וב-WhatsApp. (זהו v1 של תוכנית ההשוואה ב-planning/business-inbox-parity-plan.md; שלב הביצועים לקנה מידה גדול ימשיך בנפרד.) בנוסף שופר זמן פתיחת שיחה ב-/messages/inbox (בעקבות תלונת משתמשים על השהיה קלה): נוסף cache משותף של הודעות עם stale-while-revalidate — פתיחה חוזרת של שיחה מציגה מיידית מה-cache ואז מרעננת ברקע; ה-prefetch מופעל מוקדם יותר (גם ב-pointerdown, כך שזה עובד גם במגע ולא רק ב-hover); ובוצע איחוד בקשות-תעופה (dedup) כך שה-prefetch וטעינת השיחה חולקים בקשה אחת במקום שתיים. ה-cache מתנקה אוטומטית במעבר tenant (התחזות) כדי שלא תוצג היסטוריה חוצת-לקוחות. כמו כן, בשני הצ׳אטים (לקוחות קצה ועסקיים) נוספה טבעת halo בצבע המותג סביב האווטאר של השיחה הפעילה ברשימה — סימון ויזואלי ברור של הצ׳אט הנבחר (ring-2 ring-primary עם ring-offset, במקום הטבעת העדינה הרגילה). בנוסף הושלם שלב הביצועים של business-inbox (Workstream 3 בתוכנית ההשוואה) — הדף מחזיק כעת עשרות אלפי צ׳אטים: ה-API עבר מ-take:100 קשיח + חיפוש client-side ל-keyset pagination על updatedAt עם infinite-scroll, וחיפוש server-side עמוק שמחפש גם בתוכן ההודעות (ILIKE מואץ ע״י אינדקס pg_trgm על ai_chat_messages.content) בנוסף לשם/טלפון/chatId/כותרת. נוספו אינדקסים: (tenant_id, context, is_archived, updated_at DESC) לסריקת הרשימה ו-(session_id, created_at DESC) לתת-שאילתת ההודעה-האחרונה (שגם מביאה כעת את סטטוס המסירה — ✓/✓✓ מוצג ברשימה). הטעינה מביאה עמוד-ראשון בלבד ומרחיבה בגלילה, עם poll שקט שממזג את העמוד החד ביותר כך שעמודים שנטענו בגלילה נשמרים. כמו כן תוקנה איטיות אמיתית בפתיחת צ׳אט ב-/messages/inbox: שאילתת ה-shipment שמלווה את טעינת ההודעות לא השתמשה באינדקס הטלפון — ה-ORDER BY createdAt גרם ל-planner לסרוק לאחור את אינדקס ה-createdAt ולסנן טלפון שורה-שורה (~10k שורות נסרקות, ~146ms ב-DB, וגרוע יותר ככל שיש יותר משלוחים בטננט). השאילתה נעטפה ב-CTE מסוג MATERIALIZED שמכריח את סינון הטלפון (idx_shipment_phone_digits) לרוץ קודם ואז ממיין רק את ההתאמות — צניחה ל-~12ms (פי ~12). זו הייתה השאילתה הדומיננטית בפתיחת צ׳אט (לעומת ~6ms של שליפת ההודעות עצמה). כמו כן תוקן באג בבורר קבוצות הוואטסאפ (בטריגרים ובכרטיס הנהג): אחרי החלפת מספר/instance ב-Green API הבורר המשיך להציג את קבוצות המספר הקודם, כי הדפדפן הגיש את תשובת ה-API מה-cache שלו והבקשה כלל לא הגיעה לשרת (גם ריענון קשיח לא עזר, כי הוא לא מכריח fetch מאוחר לעקוף cache). התיקון: הראוט /api/messages/green-api-groups מסומן force-dynamic ומחזיר Cache-Control: no-store, וה-fetch בבורר משתמש ב-cache: no-store ומושך רשימה טרייה בכל פתיחה. כמו כן תוקן באג מובייל בבחירת שליח/קבלן מתוך רשימת ה-Combobox (כרטיסיית המשימות בדף המשלוח, וכל בורר מבוסס Combobox): במובייל לחיצה על שורת שליח ברשימה פשוט לא בחרה כלום, בעוד בדסקטופ זה עבד. הסיבה — רכיב ה-Combobox (diceui) משחרר במגע את ה-pointer capture ומסתמך על אירוע click שהדפדפן מסנתז, שמותנה בכך ש-pointerdown ו-pointerup פוגעים באותו אלמנט; במובייל סגירת המקלדת בלחיצה גורמת ל-reflow של הרשימה המעוגנת, ה-pointerup פוגע במקום אחר וה-click אובד. התיקון מפעיל את הבחירה ישירות על השורה (currentTarget.click) ב-pointerup במגע, עם סף תנועה כדי שגלילה לא תבחר בטעות; מסלול העכבר בדסקטופ נשאר ללא שינוי.
- סיווג חריג/רגיל הפך לפר-לקוח (רשימת הישובים נשארת גלובלית)
- ברירת מחדל = המצב הגלובלי הקיים — אפס שינוי התנהגות עד שמסווגים מחדש
- פותר גביית-יתר אפשרית בתוספת 'יעד חריג' כשמגדירים מחירונים
- ה-override חל גם על החיוב וגם על זמן האספקה (מעקב, פורטל, AI)
- עריכה במסך 'זמני הפצה → ישובים' כותבת override פר-לקוח (יחיד + קבוצתי)
- אטריביוציה חזותית בתיבת ההודעות — אייקון מקור לכל הודעה יוצאת (נציג/AI/מערכת/טריגר) עם שם הנציג בריחוף
- הודעות מדיה מלקוח הקצה מסווגות ע״י AI לפי הקשר — מדבקת תודה נסגרת כטופל, תמונה ללא הקשר חיובי מוסלמת (שלא לפספס חבילה פגומה)
- תוקן בורר קבוצות הוואטסאפ שהציג את קבוצות ה-instance הקודם אחרי החלפת מספר ב-Green API (cache של הדפדפן) — no-store + רענון בכל פתיחה
- תוקן באג מובייל — בחירת שליח/קבלן מרשימת ה-Combobox (כרטיסיית משימות בדף משלוח) לא עבדה במגע; הבחירה נורית כעת ישירות ב-pointerup, מסלול הדסקטופ ללא שינוי
v01.93.000שיפורלקוחות / מחירוןminorמשלוח כפול / כפולה — תוספת על מחיר המסירה
תעריף 'משלוח כפול / כפולה' מטופל כעת כתוספת המתווספת מעל מחיר המסירה הרגיל — בדומה לתוספת גוביינא — ולא כמחיר נפרד.
פרטים נוספים ↓הסתר ↑
תעריף 'משלוח כפול / כפולה' מטופל כעת כתוספת המתווספת מעל מחיר המסירה הרגיל — בדומה לתוספת גוביינא — ולא כמחיר נפרד. מבחינה פונקציונלית: כל משלוח כפולה (isRoundtrip) מקבל אוטומטית תוספת בגובה roundtripRate בחישוב החיוב של הלקוח (משלים את תוספת 'כפולה' שהייתה מוגדרת אך לא חושבה). מבחינת תצוגה: מחירון הלקוח, הצעות מחיר, חוזים וייבוא המחירון מציגים כעת את השדה כתוספת ('תוספת'), עם הסבר ברור שמדובר בתוספת על המשלוח הרגיל.
- תוספת 'כפולה' אוטומטית = roundtripRate מעל מחיר המסירה (כמו גוביינא)
- מחושב במנוע החיוב ומופיע בפאנל החיוב של המשלוח ובדוח עמלות הסוכן
- תצוגה עקבית כ'תוספת' במחירון, הצעות מחיר, חוזים וייבוא מחירון
- עמודת 'מחירון' חדשה בטבלת הלקוחות — פתיחת המחירון ישירות מהרשימה ('ערוך מחירון' / 'לא הוגדר מחירון'), בדומה לטבלת השליחים
- פילטר 'מחירון' (הוגדר / לא הוגדר) ופעולת אצווה 'הגדר מחירון' לקבוצת לקוחות — אחידות מלאה עם טבלת השליחים
v01.92.002שיפורפורטל לקוחות / יצירת משלוחבחירת כתובת מוצא מהמועדפות בטופס יצירת המשלוח
בטופס יצירת המשלוח בפורטל נוסף כפתור 'מועדפות' גם לסקציית כתובת המוצא — עד כה ניתן היה לבחור כתובת שמורה רק ליעד.
פרטים נוספים ↓הסתר ↑
בטופס יצירת המשלוח בפורטל נוסף כפתור 'מועדפות' גם לסקציית כתובת המוצא — עד כה ניתן היה לבחור כתובת שמורה רק ליעד. כעת הלקוח יכול למלא גם את כתובת המוצא (שולח) מאותו מאגר הכתובות המועדפות.
v01.92.001תיקוןסנכרון משלוחים / איסוףתיקון שם השולח במשלוחי איסוף — תמיד שם החברה
במשלוחי איסוף, עמודת ה'שולח' הציגה לעיתים את שם נקודת האיסוף (צד שלישי) במקום את שם החברה (הלקוח).
פרטים נוספים ↓הסתר ↑
במשלוחי איסוף, עמודת ה'שולח' הציגה לעיתים את שם נקודת האיסוף (צד שלישי) במקום את שם החברה (הלקוח). הסיבה: חלק ממסלולי הסנכרון (cron / ניסיונות חוזרים) קוראים ל-upsert ללא שם הלקוח, ואז המערכת נפלה לשם המוצא מליונוויל. כעת שם השולח נפתר תמיד ממזהה החברה בליונוויל (company_id), גם כשהשם לא מועבר — כך ש'שולח' תמיד מציג את החברה. הפתרון משתמש ב-cache לפי מזהה חברה כדי לא להעמיס על נתיב הסנכרון.
v01.92.000חדשלקוחות / מחירוןminorייבוא מחירון לקוחות מאקסל
נוסף מסך ייבוא מחירון בכמות גדולה ללקוחות, בסגנון ייבוא המשלוחים.
פרטים נוספים ↓הסתר ↑
נוסף מסך ייבוא מחירון בכמות גדולה ללקוחות, בסגנון ייבוא המשלוחים. מעלים קובץ אקסל עם עמודת שם לקוח, תאריך תחולה, ושש עמודות תעריף (מסירה, איסוף, איסוף מבית העסק, משלוח כפול, תוספת גוביינא, תוספת יעד חריג) + מחירי חבילה שניה ושלישית והלאה. המערכת מזהה אוטומטית את הלקוחות לפי השם, ומאפשרת לתקן זיהוי כושל בעזרת חיפוש והשלמה אוטומטית מתוך רשימת הלקוחות. שדות חובה חסרים (מסירה/איסוף) או ערכים לא תקינים מסומנים כשגויים עם עריכה inline וטאב 'שגויות'. שורה עם תאריך תחולה יוצרת כלל מתוזמן (REPLACE) שנכנס אוטומטית בתאריך — בדיוק כמו עדכון תעריף בטופס הלקוח; שורה ללא תאריך מעדכנת מיידית את תעריפי הבסיס. תא ריק לא משנה את הערך הקיים. כל שינוי נכנס להיסטוריית המחירון של הלקוח כולל שם המשתמש שהעלה את הקובץ, ובנוסף נשמרת היסטוריית יבואים ייעודית עם אפשרות ייבוא חוזר. הייבוא מאפשר תאריכי תחולה היסטוריים (עד שנתיים אחורה) — ללא מגבלת 45 הימים של הטופס, כי זו פעולה יזומה של מנהל. שורות שנכשלו מוצגות כעת במסך הסיום עם הסיבה לכל שורה.
- זיהוי לקוחות אוטומטי לפי שם + תיקון עם חיפוש והשלמה אוטומטית
- ולידציה ועריכה inline לשדות חובה וערכים לא תקינים, עם טאב 'שגויות'
- תאריך תחולה → כלל מתוזמן (כמו בטופס); ללא תאריך → עדכון בסיס מיידי
- תמיכה בתאריכי תחולה היסטוריים (עד שנתיים אחורה) — ללא מגבלת 45 הימים של הטופס
- שורות שנכשלו מוצגות במסך הסיום עם הסיבה לכל שורה
- תמיכה במחירי חבילה שניה ושלישית והלאה
- כל שינוי נכנס להיסטוריית המחירון של הלקוח, כולל מי העלה את האקסל
- היסטוריית יבואים ייעודית עם ייבוא חוזר
v01.90.000חדשסוכנים / עמלות ושכרminorמערכת חישוב עמלות ושכר לסוכני מכירות
נבנה מנוע חישוב עמלות מלא לסוכני מכירות, התומך בכל סוגי ההתקשרות הנפוצים בענף.
פרטים נוספים ↓הסתר ↑
נבנה מנוע חישוב עמלות מלא לסוכני מכירות, התומך בכל סוגי ההתקשרות הנפוצים בענף. עד היום עמוד הסוכנים אִפשר רק להגדיר עמלה — כעת המערכת מחשבת בפועל את הסכום לתשלום לכל חודש, עם פירוט מלא וייצוא לאקסל. החישוב מבוסס על מנוע טהור (אגורות, ללא שגיאות עיגול) בתבנית של מנוע שכר הנהגים, עם 22 בדיקות יחידה. משלוח משויך לחודש שבו הגיע לראשונה לסטטוס מזכה (כל סטטוס פרט ל'משלוח חדש', 'שובץ לשליח איסוף' ו'בוטל'), דרך עמודת commissionableAt חדשה (sticky) שנקבעת אוטומטית בכל מסלולי שינוי הסטטוס. מקור החיוב לאחוז ולמרווח הוא החיוב הפנימי של הלקוח (CustomerPricingProfile). דוח העמלות, ניהול כללי העמלה וה-ledger לחיוב/זיכוי חד-פעמי זמינים בכרטיס הסוכן (דורש הרשאת 'צפייה בעמלות סוכנים').
- מודל מרווח: רווח הסוכן = חיוב הלקוח פחות עלות בסיס למשלוח
- סכום קבוע למשלוח, עם תעריף שונה פר-לקוח
- אחוז מהדוח החודשי של הלקוח, לתקופה מוגבלת (X חודשים מהשיוך או טווח תאריכים)
- בונוס חודשי קבוע + עלויות חוזרות שהסוכן נושא בהן (קבוע-חודשי או פר-משלוח)
- חיוב/זיכוי חד-פעמי בחשבון הסוכן (ledger)
- דוח חודשי עם בורר חודש, פירוט מלא וייצוא Excel
- דף סוכן ייעודי ומעוצב (/agents/[id]) — hero, נתוני מפתח, דוח עמלות, כללים, לקוחות ולידים; לחיצה על שורה פותחת אותו במקום חלון צד
v01.89.005תיקוןמשלוחים / טופס יצירהטופס יצירת משלוח מתאפס בכל פתיחה
תוקן באג שבו לאחר שמירת משלוח, פתיחת טופס חדש זכרה את הפרטים של המשלוח הקודם.
פרטים נוספים ↓הסתר ↑
תוקן באג שבו לאחר שמירת משלוח, פתיחת טופס חדש זכרה את הפרטים של המשלוח הקודם. הסיבה: לחלק משדות הטופס (שם נמען, כתובת יעד ועוד) לא הוגדר ערך ברירת מחדל, ולכן ה-reset לא ניקה אותם באופן אמין. כעת לכל השדות יש ברירת מחדל ריקה, ובנוסף הטופס מתאפס לחלוטין בכל פתיחה — ללא תלות באופן שבו נסגר (כפתור סגירה, לחיצה מחוץ, Esc, או לאחר שמירה).
v01.89.004תיקוןסוכן WhatsApp / AI Chatסוכן WhatsApp: תיקון JSON קטוע עם Gemini 2.5 Flash
Gemini 2.5 Flash מפעיל thinking tokens שאכלו את רוב תקציב ה-max_tokens (2048), וה-JSON נקטע באמצע.
פרטים נוספים ↓הסתר ↑
Gemini 2.5 Flash מפעיל thinking tokens שאכלו את רוב תקציב ה-max_tokens (2048), וה-JSON נקטע באמצע. הוגדל max_tokens ל-8192 כדי לאפשר לסוכן לסיים את התשובה גם כשהמודל חושב רבות. בנוסף: תיקון ברקודים ב-AI Chat — מזהה משלוח מוצג כעת כרכיב לחיץ עם אייקוני העתקה וניווט (כמו בכל שאר המערכת) ואינו מתבלבל עם מספרי טלפון או תאריכים. כמו כן תוקן עיצוב רשימת הצ׳אטים ב-business-inbox: טקסט ארוך (שם לקוח / תצוגה מקדימה של ההודעה האחרונה) גלש מחוץ לכרטיסיה ושבר את הפריסה. הסיבה: ScrollArea של Radix עוטף את התוכן ב-display:table שמתרחב לרוחב השורה הארוכה ביותר ומבטל את ה-truncate; נכפה display:block על המעטפת ונוסף min-w-0 לשם — וכעת הטקסט מתקצר כראוי. בנוסף הוקפד עקרון הריווח (עד 8px בין אלמנטים): צומצמו mb-3→mb-2 בכותרת ו-gap-2.5→gap-2 בין האווטאר לטקסט בכרטיסיה, וה-skeletons בטעינה יושרו ל-p-2/space-y-1 כך שיתאימו למיקום הכרטיסיות האמיתיות. גם שולי הכותרת צומצמו מ-px-4/py-3 (16px) ל-p-2 (8px), כך שתיבת החיפוש והכותרת מתיישרות עם מיכל הרשימה ושוליים אחידים של 8px לאורך כל הסיידבר. בנוסף תוקנה אסימטריה פנימית בכרטיסיות: ה-pe-5 (20px) שריפד רק את צד הסוף הוסר, כעת הריפוד סימטרי (px-3 משני הצדדים), ובריחוף חותמת הזמן מתפוגגת וכפתור הארכיון מופיע במקומה עם רקע נקי — ללא חפיפה על הטקסט וללא שמירת מקום קבועה. ולבסוף צומצם הרווח הכפול בין סיידבר הצ׳אטים לסיידבר הראשי: התוכן (חיפוש, כותרת, כרטיסיות) הוצמד לקצה בדסקטופ (md:ps-0) כך שהרווח של הסיידבר הצף (8px) הוא הרווח היחיד, במקום 16px (8px צף + 8px ריפוד פנימי). מאחר שהכרטיסיה צמודה כעת לקצה, ה-ring של הכרטיסיה הפעילה שונה ל-ring-inset כדי שלא ייחתך ע״י ה-overflow בקצה. כמו כן תוקן באג כפילות שיחות ב-business-inbox: ה-webhook של Green API חיפש session קיים רק בחלון של 24 שעות, כך ששיחה ששתקה מעל 24 שעות יצרה רשומת session חדשה לאותו chatId — ואותה שיחה הופיעה ככמה כרטיסיות. כעת מאותרת שיחה אחת לכל chatId (ללא חלון זמן), והקשר ה-AI מוגבל בנפרד ל-20 ההודעות האחרונות (תוקן גם סדר טעינת ההיסטוריה ל-desc במקום asc). בנוסף בוצע מיזוג חד-פעמי של הכפילויות הקיימות (איחוד ההודעות לשיחה הוותיקה, מחיקת הרשומות הכפולות). ולבסוף תוקן באג שקיפות בשליחה ידנית מה-inbox: ה-route החזיר success:true גם כשהמסירה ל-Green API נכשלה, כך שהנציג ראה ✓ למרות שההודעה לא נמסרה ללקוח. כעת המסירה נרשמת כ-failed/sent, ה-route מחזיר delivered, וה-UI מציג אייקון אדום + toast 'ההודעה נשמרה אך לא נמסרה' כשהמסירה נכשלה. ה-route גם מחזיר את סיבת הכשל (deliveryError) וה-toast מציג אותה, כך שהנציג רואה מיד *למה* נכשלה המסירה במקום לחפש בלוגים. ובאמצעות זה אותר ותוקן שורש הבעיה: שליחה ידנית מה-inbox נכשלה לחלוטין (TypeError 'Cannot read properties of undefined (reading _sendToChat)') כי ה-route שלף את adapter.sendToChat למשתנה וקרא לו לא-מאוגד, כך ש-this היה undefined. תוקן לקריאה ישירה על ה-adapter (כמו ב-driver-tools). רגרסיה מאז commit 776179e0.
v01.89.003תיקוןmessages/inboxתיקון: שיחות צ׳אט מפוצלות — היסטוריה לא הופיעה ללקוח שפנה
בחלק מהשיחות ב-/messages/inbox הופיעה רק התגובה האחרונה של הלקוח (למשל '👍' או 'תודה') בלי ההיסטוריה, כך שהנציג לא ידע על מה הפנייה.
פרטים נוספים ↓הסתר ↑
בחלק מהשיחות ב-/messages/inbox הופיעה רק התגובה האחרונה של הלקוח (למשל '👍' או 'תודה') בלי ההיסטוריה, כך שהנציג לא ידע על מה הפנייה. הסיבה: מספרי טלפון נורמלו לא-עקבית — הודעות יוצאות (התראות משלוח) נשמרו לעיתים במספר מקומי בן 9 ספרות ללא קידומת (5XXXXXXXX, כשמקור הנתון מליונוויל השמיט את ה-0 המוביל), בעוד תגובות נכנסות מ-Meta מגיעות בפורמט בינלאומי (9725XXXXXXXX) — מה שפיצל את אותה שיחה לשניים. כעת normalizePhone מזהה נייד ישראלי בן 9 ספרות ומוסיף 972, ובוצע מיזוג חד-פעמי של ההודעות וההיסטוריה הקיימת (1,647 הודעות אוחדו, 118 שיחות כפולות מוזגו). השיחות מציגות כעת את ההקשר המלא. בנוסף: שליפת המשלוח בצ׳אט (ברקוד לחיץ + שם לקוח/שולח) לא מצאה משלוחים שטלפונם שמור בפורמט 9-ספרות חשוף — כעת היא מתאימה את שלושת הפורמטים (972…, 0…, 5XXXXXXXX), והברקוד חזר להיות לחיץ.
v01.89.002תיקוןסנכרון משלוחים / אבטחת נתוניםתיקון קריטי: שיוך משלוח ללקוח לפי החברה בליונוויל ולא לפי שם המוצא
תוקן באג חמור שבו משלוחים נשייכו ללקוח השגוי (או נותרו ללא לקוח).
פרטים נוספים ↓הסתר ↑
תוקן באג חמור שבו משלוחים נשייכו ללקוח השגוי (או נותרו ללא לקוח). זיהוי הלקוח של משלוח נכנס מליונוויל התבסס על שם המוצא (השולח); בעקבות שינוי שגרם לשם המוצא להציג את נקודת האיסוף האמיתית, משלוחי איסוף — שבהם המוצא הוא כתובת של גורם אחר (למשל מחסן של לקוח אחר) — שויכו לפי שם נקודת האיסוף ולא לפי הלקוח שהזמין. כעת השיוך נקבע אך ורק לפי מזהה החברה בליונוויל (company_id → lionwheelId, ייחודי), עם נפילה לשם החברה בלבד — לעולם לא לפי שם המוצא. בנוסף תוקנו 561 משלוחים שנפגעו (שויכו מחדש ללקוח הנכון לפי החברה). כמו כן הוחזרה עמודת ה'שולח' להציג את שם החברה (הלקוח) במקום את נקודת האיסוף — ותוקנו 721 משלוחים שבהם הוצג שם נקודת האיסוף.
v01.89.001שיפורמשלוחים / איסוף / סנכרוןזיהוי איסוף אוטומטי גם כשליונוויל לא שולח את הסוג
ליונוויל החל לשלוח את שדה task_type ב-webhooks רק לאחרונה ובאופן לא עקבי, כך שמשלוחי איסוף שהגיעו לפני כן (או שהשדה הושמט עבורם) לא זוהו.
פרטים נוספים ↓הסתר ↑
ליונוויל החל לשלוח את שדה task_type ב-webhooks רק לאחרונה ובאופן לא עקבי, כך שמשלוחי איסוף שהגיעו לפני כן (או שהשדה הושמט עבורם) לא זוהו. נוספה רשת ביטחון בזמן הסנכרון: כשמגיע משלוח מליונוויל ללא task_type, המערכת גוזרת 'איסוף' אוטומטית אם כתובת היעד זהה לכתובת בית-העסק הרשומה — אותו עיקרון של ה-backfill, אך מיושם חי על כל משלוח נכנס. הבדיקה ממוקדת ויעילה (cache לכתובות העסק לפי מזהה החברה) כדי לא להעמיס על נתיב הסנכרון.
v01.89.000חדשמשלוחים / איסוףminorזיהוי וסימון משלוחי איסוף
משלוחי איסוף (שבהם היעד הוא כתובת בית-העסק) מזוהים ומסומנים כעת בפורטל: תווית 'איסוף' מופיעה ליד מספר המשלוח ברשימה ובדף המשלוח, ונוסף פילטר 'סוג משלוח' (מסירה / איסוף) לרשימת המשלוחים.
פרטים נוספים ↓הסתר ↑
משלוחי איסוף (שבהם היעד הוא כתובת בית-העסק) מזוהים ומסומנים כעת בפורטל: תווית 'איסוף' מופיעה ליד מספר המשלוח ברשימה ובדף המשלוח, ונוסף פילטר 'סוג משלוח' (מסירה / איסוף) לרשימת המשלוחים. הזיהוי מבוסס על השדה taskType מליונוויל; משלוחים שנוצרים מהטופס מקבלים את הסוג אוטומטית לפי מצב היצירה (מסירה/איסוף). בנוסף בוצע backfill למשלוחים היסטוריים: 2,175 משלוחים שבהם כתובת היעד זהה לכתובת בית-העסק סומנו כ'איסוף'. תוקן גם באג תצוגה: שם המוצא (sourceName) הציג את שם החברה במקום את שם המוצא האמיתי בסנכרון מליונוויל — קריטי במשלוחי איסוף שבהם המוצא הוא צד שלישי.
- תווית 'איסוף' ברשימת המשלוחים ובדף המשלוח בפורטל
- פילטר 'סוג משלוח' (מסירה / איסוף) ברשימה
- סימון אוטומטי לפי מצב היצירה + backfill ל-2,175 משלוחים היסטוריים
- תיקון שם המוצא (sourceName) שהוצג כשם החברה במקום המוצא האמיתי
v01.88.000שיפורmessages/inboxminorצ׳אט מהיר + חיפוש לפי תוכן הודעה
אופטימיזציה עמוקה לדף /messages/inbox + חיפוש לפי תוכן הודעה, וארכיטקטורה שמחזיקה גם בעשרות אלפי שיחות.
פרטים נוספים ↓הסתר ↑
אופטימיזציה עמוקה לדף /messages/inbox + חיפוש לפי תוכן הודעה, וארכיטקטורה שמחזיקה גם בעשרות אלפי שיחות. שלב א': תוקנה איטיות קריטית — עבור כל שיחה ברשימה בוצעה שאילתת LATERAL נפרדת על טבלת המשלוחים שלא ניצלה אינדקס, ובטאב "לא טופל" זה הצטבר ל-~54 שניות וגרם ל-timeout (הטאב לא נטען כלל). שלב ב': רשימת השיחות והמונים נקראים כעת מטבלת whatsapp_conversations הדנורמלית (שורה אחת לשיחה, מתוחזקת בכל הודעה נכנסת/יוצאת + backfill) — כל טאב הוא סריקת אינדקס יחידה עם דפדוף, בזמן קבוע ללא תלות בכמות ההודעות הכוללת.
- טאב "לא טופל" / "ללא מענה": מ-~54 שניות (timeout) ל-מילישניות
- תצוגת ברירת המחדל של רשימת השיחות: מ-~2.9 שניות ל-~21ms
- חיפוש חדש לפי מילות מפתח בתוך תוכן ההודעות (אינדקס pg_trgm — ~5ms במקום ~1.1 שניות)
- מקור-אמת דנורמלי (whatsapp_conversations) + מונה unread, עם דפדוף בכל הטאבים — נשאר מהיר גם בעשרות אלפי שיחות
- התיקון חל על כל מצבי הסינון: הכל, לא טופל, טופל, ללא מענה, חיפוש
v01.87.000חדשהודעות / צ׳אט עסקי / Green APIminorצ׳אט לקוחות עסקיים — מראה מלאה של כל הודעות ה-WhatsApp
צ׳אט הלקוחות העסקיים (תיבת ההודעות) משקף כעת את כל ההודעות היוצאות מה-WhatsApp העסקי — לא רק תשובות ידניות ותגובות סוכן ה-AI.
פרטים נוספים ↓הסתר ↑
צ׳אט הלקוחות העסקיים (תיבת ההודעות) משקף כעת את כל ההודעות היוצאות מה-WhatsApp העסקי — לא רק תשובות ידניות ותגובות סוכן ה-AI. עד כה הודעות אוטומטיות שנשלחו דרך טריגרים (התראות טעויות מיון, טריגרים מערכתיים וכו') נשלחו ישירות ל-WhatsApp ולא נרשמו כלל בצ׳אט, כך שהמשתמש ראה רק חלק מהשיחה. כעת כל הודעה יוצאת ש-Green API מהדהד אלינו נלכדת ברמת ה-webhook ונשמרת ב-inbox, כולל יצירת שיחה אוטומטית לצ׳אט/קבוצה שטרם הופיעו. הלכידה היא תוספת בלבד בצד קבלת ה-webhook — אינה נוגעת בנתיב שליחת ההודעות.
- הודעות טריגר אוטומטיות (טעויות מיון, טריגרים מערכתיים) מופיעות כעת בתוך הת׳רד של הקבוצה/הלקוח בצ׳אט העסקי
- הודעות שנשלחו ידנית מהטלפון יוצרות שיחה ב-inbox גם אם לא הייתה היסטוריה קודמת לאותו צ׳אט
- מניעת כפילויות: הודעות סוכן AI/שליחה ידנית לא יירשמו פעמיים (התאמה לפי externalId)
- הלכידה ברמת ה-webhook בלבד — אפס שינוי בנתיב שליחת ההודעות, ללא סיכון למשלוח
v01.86.002תיקוןmessages/inboxתיקון איטיות קריטית בצ׳אט — טאב "לא טופל" שלא נטען
שאילתות רשימת השיחות ב-/messages/inbox עברו אופטימיזציה משמעותית.
פרטים נוספים ↓הסתר ↑
שאילתות רשימת השיחות ב-/messages/inbox עברו אופטימיזציה משמעותית. הבעיה: עבור כל שיחה ברשימה בוצעה שאילתת LATERAL נפרדת על טבלת המשלוחים (לשליפת שם הלקוח/השולח), שלא ניצלה את האינדקס idx_shipment_phone_digits וסרקה את כל הטבלה מחדש בכל פעם. בטאב "לא טופל"/"ללא מענה" (ללא הגבלת מספר שורות) זה הצטבר ל-~54 שניות וגרם ל-timeout — הטאב לא הציג תוצאות כלל. התיקון מאחד את שליפת המשלוחים למעבר אינדקס אחד (= ANY(ARRAY(...))) לכל חמשת מצבי השאילתה (הכל, לא טופל, טופל, ללא מענה, חיפוש). הפלט זהה לחלוטין; זמן השרת ירד מ-~2.9 שניות ל-~21ms בתצוגת ברירת המחדל ומ-~54 שניות ל-~48ms בטאב "לא טופל".
v01.86.001שיפוראבטחה / Middlewareהקשחת CSRF — חסימת בקשות שינוי ללא מקור מאומת
בדיקת ה-CSRF על בקשות שינוי (POST/PUT/PATCH/DELETE) ל-API הפנימי הוקשחה: עד כה בקשה ללא כותרת Origin עברה ללא בדיקה.
פרטים נוספים ↓הסתר ↑
בדיקת ה-CSRF על בקשות שינוי (POST/PUT/PATCH/DELETE) ל-API הפנימי הוקשחה: עד כה בקשה ללא כותרת Origin עברה ללא בדיקה. כעת המערכת מאמתת את מקור הבקשה דרך Origin, ובהיעדרו נופלת אחורה ל-Referer; בקשה ללא אף אחד מהם — או עם מקור שאינו תואם לדומיין — נדחית. השינוי נוגע אך ורק ב-routes פנימיים מבוססי-session (דפדפן); אפליקציית המובייל (api/v1), ה-Public API וה-webhooks מוחרגים ואינם מושפעים. ללא שינוי בחוויית המשתמש בדפדפן.
v01.86.000חדשמשלוחים / טופס יצירהminorכתובת מוצא בטופס יצירת המשלוח — מסירה / איסוף / חופשי
בטופס יצירת המשלוח נוסף בורר סוג משלוח עם 3 מצבים (כמו בליונוויל): 'מסירה' — כתובת המוצא נלקחת אוטומטית מכתובת בית העסק הרשומה והיעד חופשי (התנהגות ברירת המחדל הקיימת); 'איסוף' — היעד הוא בית העסק והמוצא חופשי להזנה; 'חו…
פרטים נוספים ↓הסתר ↑
בטופס יצירת המשלוח נוסף בורר סוג משלוח עם 3 מצבים (כמו בליונוויל): 'מסירה' — כתובת המוצא נלקחת אוטומטית מכתובת בית העסק הרשומה והיעד חופשי (התנהגות ברירת המחדל הקיימת); 'איסוף' — היעד הוא בית העסק והמוצא חופשי להזנה; 'חופשי' — שתי הכתובות חופשיות. הצד של בית העסק ממולא אוטומטית מהכתובת הרשומה אך נשאר ניתן לעריכה. נוסף סקשן 'כתובת מוצא' (שם, טלפון, עיר, רחוב, מספר) שנשלח לליונוויל, ונשמר גם מקומית כדי שכתובת המוצא תוצג מיד. כתובת בית העסק נגזרת מנתוני החברה שכבר מסונכרנים מליונוויל (lionwheelData.location), ללא צורך בהגדרה נוספת.
- בורר 'מסירה / איסוף / חופשי' בטופס יצירת המשלוח (פורטל וצוות)
- סקשן 'כתובת מוצא' חדש שנשלח לליונוויל ונשמר מקומית
- צד בית-העסק ממולא אוטומטית מהכתובת הרשומה וניתן לעריכה
v01.85.000חדשפורטל לקוחות / כתובות מועדפותminorשמירת כתובת נמען בכתובות המועדפות
נוסף כפתור 'שמור במועדפות' שמאפשר ללקוח לשמור את כתובת הנמען לפנקס הכתובות שלו, ישירות מתוך טופס יצירת המשלוח (ליד בורר הכתובות המועדפות) וגם מתוך דף המשלוח (בכרטיס פרטי היעד, וגם בתצוגה המהירה).
פרטים נוספים ↓הסתר ↑
נוסף כפתור 'שמור במועדפות' שמאפשר ללקוח לשמור את כתובת הנמען לפנקס הכתובות שלו, ישירות מתוך טופס יצירת המשלוח (ליד בורר הכתובות המועדפות) וגם מתוך דף המשלוח (בכרטיס פרטי היעד, וגם בתצוגה המהירה). לחיצה פותחת דיאלוג קצר עם שם הכתובת (ברירת מחדל: שם הנמען) וסיכום הכתובת, ושמירה מוסיפה אותה לאותו מאגר שממנו ממלאים כתובת יעד בלחיצה אחת ביצירת משלוח. כך לקוחות יכולים לבנות בקלות פנקס נמענים קבועים מתוך משלוחים אמיתיים.
- כפתור 'שמור במועדפות' בטופס יצירת המשלוח ובדף המשלוח
- הכתובת נשמרת לאותו מאגר שממלא כתובת יעד בבחירה מהירה
- דיאלוג קצר עם שם כתובת ניתן לעריכה וסיכום הכתובת
v01.84.000חדשליקוט / משלוחיםminorסימון משלוחים לליקוט מסרגל הבחירה המרובה
בסרגל הפעולות של בחירה מרובה נוסף כפתור 'סמן לליקוט' שמאפשר לסמן את כל המשלוחים הנבחרים כמיועדים לליקוט בבת אחת, תוך בחירת תדירות (שוטף / מזדמן), סוג (עלונים / מוצרים), ובמקרה של עלונים — בחירת פרשה אחת או יותר (מהשבתות …
פרטים נוספים ↓הסתר ↑
בסרגל הפעולות של בחירה מרובה נוסף כפתור 'סמן לליקוט' שמאפשר לסמן את כל המשלוחים הנבחרים כמיועדים לליקוט בבת אחת, תוך בחירת תדירות (שוטף / מזדמן), סוג (עלונים / מוצרים), ובמקרה של עלונים — בחירת פרשה אחת או יותר (מהשבתות הקרובות או בהזנה ידנית). הפרשות נשמרות כפריטי המשלוח ויעד השבת נגזר מהפרשה הקרובה ביותר, בדיוק כמו במסך הליקוט. הכפתור זמין בכל הטבלאות שמשתמשות בסרגל — דף המשלוחים, מודל המשלוחים של לקוח, יעד שבת, יעד אקספרס ופערי הפצה.
- כפתור 'סמן לליקוט' בסרגל הבחירה המרובה — בדף המשלוחים ובמודל משלוחי הלקוח
- בחירת תדירות (שוטף/מזדמן) וסוג (עלונים/מוצרים) בפעולה אחת על כל הנבחרים
- לעלונים — בחירת פרשות מרובות שנשמרות כפריטי המשלוח, ויעד השבת נגזר אוטומטית
v01.82.000שיפורפורטל לקוחות / משלוחיםminorתצוגה מהירה של משלוח בפורטל + שינוי התנהגות שורה
בטבלת המשלוחים בפורטל, לחיצה על שורה כבר לא מנווטת אוטומטית לדף המשלוח — כדי למנוע מעבר בטעות תוך כדי בחירה או גלילה.
פרטים נוספים ↓הסתר ↑
בטבלת המשלוחים בפורטל, לחיצה על שורה כבר לא מנווטת אוטומטית לדף המשלוח — כדי למנוע מעבר בטעות תוך כדי בחירה או גלילה. במקום זה, ליד מספר המשלוח הופיעו שני אייקונים שמתגלים במעבר עכבר: אייקון העתקה (מימין) להעתקת מזהה המשלוח, ואייקון פתיחה (משמאל) לניווט לדף המשלוח המלא. לחיצה על מספר המשלוח עצמו פותחת תצוגה מהירה (Drawer) עם כל פרטי המשלוח — סטטוס, יעד, פרטי משלוח, תוויות, מפה, ציר מעקב והוכחת מסירה — בלי לעזוב את הרשימה. ההתנהגות זהה לזו שכבר קיימת בממשק הניהול. בנוסף תוקן באג סקופ ב-API: פתיחת משלוח של חשבון מקושר (לקוח-בן) החזירה 404. כמו כן נוסף אייקון העתקה ליד מספר המשלוח הגדול בראש דף המשלוח המלא. עיצוב התצוגה המהירה אוחד לזה של דף המשלוח — שניהם מרנדרים כעת את אותו רכיב משותף, כך שהתוכן והמראה זהים לחלוטין.
- לחיצה על שורה לא מנווטת יותר בטעות — הפעולות עברו לאייקונים ליד מספר המשלוח
- אייקון העתקה ואייקון ניווט לדף המלא מתגלים במעבר עכבר על המספר
- לחיצה על מספר המשלוח פותחת תצוגה מהירה (Drawer) עם כל פרטי המשלוח
v01.80.003ייעולחיפוש גלובלי / ביצועיםחיפוש גלובלי מהיר — אינדקסי trigram וריצה מקבילה
החיפוש הגלובלי בסרגל העליון היה איטי (עד ~900ms לכל הקלדה) אצל לקוחות עם כמות משלוחים גדולה.
פרטים נוספים ↓הסתר ↑
החיפוש הגלובלי בסרגל העליון היה איטי (עד ~900ms לכל הקלדה) אצל לקוחות עם כמות משלוחים גדולה. הסיבה: החיפוש סורק עמודות עם ILIKE '%טקסט%', וללא אינדקס מתאים Postgres ביצע סריקה מלאה של טבלת המשלוחים בכל בקשה — מורגש רק אצל ה-tenant הגדול ורק במונחים סלקטיביים (טלפון/ברקוד/אימייל) או באמצע הקלדה, ולכן 'לפעמים אצל חלק מהמשתמשים'. נוספו אינדקסי GIN trigram (pg_trgm) על כל העמודות שהחיפוש סורק, כך ש-Postgres משתמש ב-BitmapOr במקום סריקה מלאה — זמן השאילתה ב-DB צנח מ-~810ms לפחות ממילישנייה. בנוסף, שלוש שאילתות החיפוש (משלוחים/לקוחות/שליחים) רצות כעת במקביל במקום בטור, ותקרת הבקשות לדקה הועלתה מ-30 ל-60 כדי למנוע חסימה שגויה בהקלדה מהירה.
v01.80.002תיקוןwebhooks / Green API / אבטחהאימות webhook נכנס מ-Green API — תמיכה יציבה בסוד אימות
תוקן אימות ה-Authorization header של webhookים נכנסים מ-Green API.
פרטים נוספים ↓הסתר ↑
תוקן אימות ה-Authorization header של webhookים נכנסים מ-Green API. נמצא (מצרף של יומיים דגימות בפרודקשן) ש-Green API שולח את הסוד בפורמט 'Bearer <token>', בעוד שבמערכת הסוד נשמר לעיתים בלי ה-prefix — מה שגרם לדחיית כל ה-webhookים הנכנסים (תגובות שליחים, סטטוסי מסירה, תגובות AI) ברגע ש-tenant הגדיר סוד אימות. כעת ההשוואה מנרמלת את שני הצדדים (מסירה 'Bearer ' ורווחים) לפני ההשוואה הבטוחה — כך שהגדרת סוד אימות פשוט עובדת ויציבה, בלי לשבור webhookים ובלי להחליש את האבטחה.
v01.80.001תיקוןסוכן WhatsAppסוכן WhatsApp: שיחה מחוץ לחלון 24 שעות מועברת לנציג
תוקן באג: כאשר לקוח שלח הודעה שהסוכן סיווג כקטגוריה 2 או 3 (שאלת משלוח / הפניה לשולח) אך לא ניתן לשלוח תגובה כי החלון חופשי של Meta (24 שעות) נסגר, השיחה סומנה 'טופל' בעוד שהלקוח לא קיבל מענה.
פרטים נוספים ↓הסתר ↑
תוקן באג: כאשר לקוח שלח הודעה שהסוכן סיווג כקטגוריה 2 או 3 (שאלת משלוח / הפניה לשולח) אך לא ניתן לשלוח תגובה כי החלון חופשי של Meta (24 שעות) נסגר, השיחה סומנה 'טופל' בעוד שהלקוח לא קיבל מענה. כעת השיחה מסומנת 'לטיפול' עם הערה 'מחוץ לחלון 24 שעות — יש לשלוח תבנית ידנית', כך שהנציג מקבל התראה ויכול להמשיך ידנית.
v01.80.000חדשיבוא משלוחיםminorיבוא משלוחים רץ ברקע — אפשר להמשיך לעבוד בזמן ההעלאה
יבוא משלוחים מאקסל (גם בדף הצוות וגם בפורטל הלקוחות) רץ כעת ברקע: מיד עם תחילת הייבוא אפשר לנווט לכל דף אחר במערכת, וטוסט גלובלי בתחתית המסך מציג את קצב ההתקדמות (X/Y משלוחים, כולל מספר אצווה בקבצים גדולים).
פרטים נוספים ↓הסתר ↑
יבוא משלוחים מאקסל (גם בדף הצוות וגם בפורטל הלקוחות) רץ כעת ברקע: מיד עם תחילת הייבוא אפשר לנווט לכל דף אחר במערכת, וטוסט גלובלי בתחתית המסך מציג את קצב ההתקדמות (X/Y משלוחים, כולל מספר אצווה בקבצים גדולים). בסיום מוצג טוסט סיכום עם כפתור 'צפה בסיכום' שמחזיר לדף הייבוא, שם מוצג מסך התוצאות המלא. חזרה לדף באמצע ייבוא מתחברת מחדש להתקדמות החיה. צד השרת לא השתנה כלל — כל לוגיקת הייבוא, הכפילויות וההיסטוריה נשארה זהה.
- ניווט חופשי במערכת בזמן שהייבוא רץ — בלי להישאר 'תקועים' בדף
- טוסט התקדמות גלובלי ששורד מעבר בין דפים, בדומה לשידור SNL
- טוסט סיום עם כפתור 'צפה בסיכום' שמוביל חזרה למסך התוצאות
- חזרה לדף הייבוא באמצע ריצה מתחברת מחדש להתקדמות החיה
- אזהרת דפדפן לפני סגירת הטאב בזמן שייבוא פעיל — מניעת איבוד אצוות שטרם נשלחו
- חסימת ייבוא מקביל שני (כולל בין דף הצוות לפורטל) עד לסיום הריצה הפעילה
v01.79.002חדשעוזר AI / הודעות / תובנות / אודיוminorעוזר AI — שליחת תבנית Meta לנמען עם אישור
עוזר ה-AI תומך כעת בשליחת הודעות WhatsApp לנמענים (לקוחות קצה) דרך תבניות Meta מאושרות.
פרטים נוספים ↓הסתר ↑
עוזר ה-AI תומך כעת בשליחת הודעות WhatsApp לנמענים (לקוחות קצה) דרך תבניות Meta מאושרות. הזרימה: העוזר מציג למשתמש תצוגה מקדימה מדויקת של ההודעה הממולאת בנתוני המשלוח, עם כפתור 'אשר שליחה' ייעודי — ורק לאחר לחיצה על הכפתור ההודעה נשלחת. בנוסף, נוספה מערכת ניהול תובנות AI: דף ניהול מרכזי שמציג את כל התובנות שנאגרו על ידי העוזר, עם אפשרות אישור/דחייה ולמידה ידנית של תובנות חדשות. נוסף גם תמלול אודיו: מיקרופון בצ'אט הפנימי להקלטה ושליחה קולית, ותמלול הודעות קוליות נכנסות מ-WhatsApp — פר-טננט, דרך OpenAI Whisper.
- תצוגה מקדימה ויזואלית של ההודעה בועיל ירוקה (סגנון WhatsApp) לפני שליחה
- כפתור 'אשר שליחה' — העוזר אינו שולח אוטומטית ללא אישור מפורש
- דף ניהול תובנות AI (הגדרות → תובנות AI) — אישור/דחייה/מחיקה של תובנות
- לימוד ידני: הוספת תובנה חדשה מהדף, או על ידי אמירת 'תדע ש...' לעוזר בצ'אט
- תובנות כוללות כעת שדות status/source — ממתין לאישור / אושר / נדחה
- AiInsightsCard בכרטיסי שליח/לקוח/משלוח מציג כפתורי אישור/דחייה inline
- דוח חודשי למנהל שליחים: טבלת סיכום ביקורים לפי שליח עם פירוט מסירות / איסופים / החזרות
- מיקרופון בצ'אט AI פנימי — הקלטה קולית שמומרת לטקסט ומוכנסת לתיבת הקלד (זמין רק לאחר הגדרת מפתח OpenAI בהגדרות AI)
- תמלול הודעות קוליות ב-WhatsApp — הודעות audio/voice נכנסות מתומללות ומועברות לסוכן AI לניתוח
- סקציית 'תמלול אודיו' חדשה בהגדרות AI — הגדרת מפתח OpenAI פר-טננט עבור Whisper
- פורטל מנהל שליחים: כפתור 'לינק כניסה' ליצירת קישור הגדרת סיסמה ישיר (ניתן לשליחה בווצאפ) עבור מנהלים שלא קיבלו מייל
- פורטל שליחים: הרחבה לקבלנים פנימיים — יצירת חשבון פורטל ודוח הכנסות חודשי גם לשליחי CONTRACTOR ללא ניהול
- Idempotency לכלי-כתיבה של AI — שליחת WhatsApp, עדכון סטטוס ועוד לא יבוצעו פעמיים גם אם הבקשה שוגרה שוב (retry)
- דף שליח: מזהה השליח במערכת מוצג כעת בכרטיסיית פרטים אישיים, לצד מזהה Lionwheel
- תיקון בדיקת מסירה: שליחת הודעת 'האם קיבלת?' מחייבת כעת תבנית Meta מאושרת — אם לא מוגדרת תבנית, העוזר/הכפתור מחזירים שגיאה ברורה. ניתן לסמן תבנית כ'תבנית בדיקת מסירה' בהגדרות → הודעות → תבניות
- דף שליח-מנהל: כפתור 'תיוג היסטורי' בסקציית הסאב-שליחים — שיוך רטרואקטיבי של משלוחים שהסאבים ביצעו לפני יצירת הקישור לדוח המנהל, מתאריך נבחר, עם תצוגה מקדימה (כמה ביקורים יתויגו לכל סאב) לפני החלה
- תיקון ספירת משלוחים ב-AI: נוסף כלי countShipments לספירה מדויקת ללא הגבלת שורות. תוקנה הנחיית הסיסטם שגרמה ל-AI לספור 50 תוצאות מ-searchShipments ולדווח עליהן כסכום שגוי. תוקן בלבול בין operationalStatus ('נקלט במחסן') לבין deliveryStatus מ-Lionwheel
- הקשחת אבטחה: אימות הסוד ב-webhook של הלידים (/api/leads/webhook) עבר להשוואה בזמן-קבוע (timingSafeEqual) למניעת דליפת הסוד דרך הבדלי timing — השוואה זהה לוגית, ללא שינוי התנהגות עבור קוראים קיימים
- טופסי עריכת שליח ולקוח: כפתור 'בחר קבוצה' ליד שדה קבוצת ה-WhatsApp — בחירה מתוך רשימת הקבוצות הזמינות ב-Green API (כמו בטריגרי תפעול) במקום הקלדת chatId ידנית; הבחירה ממלאת אוטומטית גם את שם הקבוצה
- ניטור SSRF (log-only) ביעדים יוצאים: webhooks יוצאים, ספק AI חיצוני ולולאת סוכן ה-AI מתעדים כעת אזהרה כשכתובת היעד מצביעה ל-IP פנימי/שמור (loopback, RFC1918, link-local/metadata) — תיעוד בלבד, ללא חסימה וללא שינוי התנהגות, כהכנה לאכיפה עתידית
- הקשחת אבטחה: שדרוג Next.js ל-16.2.9 — סוגר סדרת חולשות אבטחה רשמיות בגרסאות 16.x, כולל עקיפת middleware (הרשאות), SSRF ו-DoS
- תיקון Permissions-Policy: מצלמה, מיקרופון ומיקום הותרו לאפליקציה עצמה (self) — עד כה ה-header חסם אותם גם לעמודי המערכת (סורק ברקוד, הקלטה קולית בצ'אט AI, מעקב שליח חי)
- נוסף header של Content-Security-Policy (frame-ancestors / object-src / base-uri) — משקף את מדיניות ה-framing הקיימת ומקשיח מפני XSS, ללא שינוי התנהגות
- שדרוג Anthropic SDK לגרסה מתוקנת (0.91.1) בעקבות advisory רשמי
- הגדרות → אינטגרציות: נוסף כפתור 'הסר את הסוד השמור' לשדה Webhook Secret — עד כה לא הייתה דרך למחוק סוד שמור דרך ה-UI (שדה ריק נשמר כ'ללא שינוי'), מה שחייב איפוס ידני ב-DB. כעת ניתן להסיר סוד webhook ולחזור ל-fail-open ישירות מהממשק
- פירוט מלא לפי סאב-שליח בדוחות מנהל: הסיכום לפי שליח (בפורטל המנהל ובדף השליח באדמין) מציג כעת לכל סאב בנפרד גם איסופים עסקיים (לפי עצירות) וחבילות נוספות, בנוסף למסירות/איסופים/החזרות — באותה סמנטיקה של הסיכום הכללי. עד כה איסופים עסקיים נבלעו בעמודת האיסופים וחבילות נוספות נבלעו בסכומים ללא ספירה
- פורטל מנהל שליחים: לחיצה על סאב-שליח ברשימת השליחים פותחת סיכום אישי מלא שלו (מסירות / איסופים / איסופים עסקיים / החזרות / חבילות נוספות + סה״כ), וטאב הביקורים מסונן להציג רק את הביקורים שלו — עם באנר ברור וכפתור 'הצג הכל' לחזרה לתצוגה המשותפת
v01.79.001חדשפורטל מנהלי שליחיםפורטל מנהל שליחים — יצירת חשבון והתחזות
מנהלי מערכת יכולים ליצור חשבון פורטל למנהל שליחים ישירות מדף השליח ללא Prisma Studio.
פרטים נוספים ↓הסתר ↑
מנהלי מערכת יכולים ליצור חשבון פורטל למנהל שליחים ישירות מדף השליח ללא Prisma Studio. כפתור 'צור חשבון פורטל' מופיע כשיש isManagerEnabled=true ואין עדיין חשבון: מזינים מייל, נוצר החשבון ונשלח מייל הגדרת סיסמה. לאחר שהמנהל מגדיר סיסמה, מופיע כפתור 'כניסה כמנהל' שמאפשר לאדמין להתחזות ולצפות בפורטל כמו המנהל. תוקן: עוזר AI כעת מציג תוכן הודעה מתוכנן ומבקש אישור לפני כל שליחת WhatsApp לשליח או לקוח — ללא אישור מפורש מהמשתמש אין שליחה אוטומטית. שיפור עיצוב פורטל מנהל שליחים: כרטיס גיבור עם סכום לתשלום בולט, כרטיסי סטטיסטיקה עם אייקונים ופירוט לפי שליח עם בר-יחסי, ביקורים מוצגים כקלפים במובייל.
v01.79.000חדשמשלוחים / מחסן / SNLminorתמונת מחסן — תצוגת עגלות לפי אזורי הפצה
נוספה תמיכה בחיפוש גלובלי לפי מספר משלוח פנימי (ID).
פרטים נוספים ↓הסתר ↑
נוספה תמיכה בחיפוש גלובלי לפי מספר משלוח פנימי (ID). עד כה ניתן היה לחפש רק לפי ברקוד — כעת חיפוש ב-6 ספרות ומעלה שהוא מספרי בלבד יתאים גם ל-ID הפנימי. דף חדש תחת לשונית משלוחים: תמונת מחסן. מציג את כל המשלוחים בסטטוס מחסן (IN_INVENTORY) מקובצים לפי אזור ההפצה של הישוב (מיפוי Lionwheel). כל אזור מוצג כ'עגלה' עם ספירת המשלוחים, אייקוני חבילה אינטראקטיביים, ממוצע ימי שהייה ותצבוע לפי עומס. לחיצה על עגלה פותחת כעת מודל עם שני חלקים: בראש — תמונת מצב עכשווית עם כל המשלוחים הנמצאים כרגע בעגלה (ממוין ישן לחדש, עם נקודת צבע לפי גיל), ובהמשך — היסטוריה שבועית עם אקורדיון לכל יום (נקלטו / יצאו להפצה). סדר העגלות ניתן לשינוי בגרירה ושחרור ונשמר פר-חשבון. כולל חיפוש ברקוד/שם/עיר, רענון אוטומטי כל 4 דקות ואפשרות הדפסה. בנוסף, נוסף אינבוקס לצ'אט לקוחות עסקיים (Green API) תחת מסרונים — רשימת שיחות עם חיפוש, חלון שיחה עם היסטוריה מלאה ואפשרות שליחה ידנית, בהמשך ישיר לתשתית ה-AI שכבר ענתה אוטומטית. תוקן: הערת AI בצ'אט WhatsApp נעלמה לאחר שניה — הבאנר כעת יציב (לא מושפע מ-pagination refresh) ומוצג לכל שיחה עם הערת AI שטרם טופלה. תוקן: API של תמונת מחסן סומן כ-force-dynamic למניעת cache של Next.js שגרם להצגת נתונים ישנים לאחר רפרש. תוקן: טולטיפ ממוצע ימי שהייה הציג רק שעה ללא תאריך — formatHe הופרד ל-toLocaleDateString + toLocaleTimeString לתצוגה אמינה של תאריך ושעה. שיפור אמינות סוכן WhatsApp: פרסינג JSON חזק יותר (מתמודד עם טקסט-פתיח לפני ה-JSON), הערת שגיאה בבאנר מציגה כעת את הסיבה האמיתית ולא הודעה גנרית. שיפור אמינות webhook SNL: נוסף fallback lookup לפי additionalData.snl_barcode — מבטיח שהמשלוח יימצא גם אם targetPartnerTaskId הוחלף בזמן שהיה ב-Lionwheel.
- כל אזור הפצה מוצג כעגלה עם אייקוני חבילה (hover = tooltip עם פרטי משלוח)
- תצבוע לפי עומס: ריק=אפור, 1-5=כחול, 6-15=כתום, 16+=אדום
- ממוצע ימי שהייה במחסן וחיווי משלוח ותיק ביותר
- לחיצה על עגלה: תמונת מצב עכשווית (כל המשלוחים כרגע, עם נקודת צבע לפי גיל) + היסטוריה שבועית
- גרירה ושחרור לסידור עגלות לפי מבנה המחסן — נשמר פר-חשבון
- חיפוש חי מדגיש עגלה רלוונטית ומעמעם את השאר
- אינבוקס לצ'אט לקוחות עסקיים (Green API): רשימת שיחות, חלון שיחה ושליחה ידנית — כעת מציג גם שיחות מאנשים לא מזוהים (מספר טלפון במקום שם לקוח), שם קבוצה אוטומטי, תמיכה ב-3 webhook types נוספים: הודעות יוצאות מהטלפון (role: staff, ירוק), הודעות יוצאות דרך API (שמירת idMessage), ועדכוני סטטוס מסירה (✓ sent / ✓✓ delivered / 🔵 read) — מוצגים ב-inbox בדומה ל-WhatsApp
- תוקן: סוכן WhatsApp שלח הודעת 'לא הצלחנו להבין' כשהמודל החזיר טקסט לפני ה-JSON — כעת נשלף ה-JSON הנכון תמיד
- תוקן: עגלות שמתחת לגובה המסך נחתכו ללא אפשרות גלילה — דף תמונת מחסן כעת גולל כראוי
- תוקן: אזור 19 הופיע עם משלוח אחד בלבד — נורמליזציה של regionCode (Lionwheel שולח 19 / '19 - אילת והערבה' לאותו אזור) אוחדה לאזור יחיד
- תוקן: פורטל לקוחות לא ניתן לגלילה במובייל — הלייאאוט השתמש ב-100vh שגדול מה-viewport הנראה כשסרגל הכתובת גלוי; הוחלף ל-svh
- חדש: פורטל מנהלי שליחים (/driver-portal) — כניסה ייעודית, דוח חודשי עם KPI cards, פירוט לפי סאב-שליח, טבלת ביקורים והתאמות ידניות
v01.78.001שיפורעוזר AI פנימי / שאלות ממתינותAI Nudge — תזכורת שאלות ממתינות בפתיחת שיחה
כשה-AI פותח שיחה חדשה ויש שאלה ממתינה לאישורך שטרם נענתה, הוא יזכיר אותה בסיום תשובתו הראשונה.
פרטים נוספים ↓הסתר ↑
כשה-AI פותח שיחה חדשה ויש שאלה ממתינה לאישורך שטרם נענתה, הוא יזכיר אותה בסיום תשובתו הראשונה. תוקן באג: הפרמטרים hasFailedVisitToday/hasDeliveredVisitToday לא הועברו לשאילתת המשלוחים בפועל — כך שחיפוש 'נכשלו היום' החזיר 50 המשלוחים האחרונים ללא סינון. בנוסף, כל ברקוד בצ'אט ה-AI הפך לניתן ללחיצה לפתיחת דראאר פרטי משלוח. מדבקות רב-חבילה מציגות badge עם מספר החבילה. ניתן לשנות רוחב פאנל ה-AI בשולחן עבודה — גרירת קצה הפאנל, הגדרה נשמרת. תוקן באג קריטי: כלי listDelayedShipments השתמש בשדה sendStatus (סטטוס שליחת WhatsApp) לסינון משלוחים 'שנמסרו' — sendStatus לא קשור כלל למסירה פיזית ולכן כל המשלוחים החזירו תוצאה שגויה. הסינון תוקן לשימוש ב-additionalData.status (סטטוס ספק ליונוויל) לפי ערכי COMPLETED/ROUNDTRIP_DELIVERED/CANCELED/FAILED/FINAL_FAILED. הבאג גרם ל-AI להציג עשרות משלוחים שנמסרו כ'מעוכבים 45 ימים'. תוקן: ה-AI לא הבין את הפיצ'ר 'יעד שבת' — שאל שאלות במקום לחפש. נוסף פילטר hasTargetShabbat ו-targetShabbat לכלי searchShipments, נוסף השדה targetShabbat לתוצאות, ונוספה הסבר ב-system prompt: יעד שבת הוא תיוג של משלוח שחייב להגיע לפני שבת ספציפית (שם פרשה). כעת 'כמה פתוחים על יעד שבת?' ישירות מריץ searchShipments({ hasTargetShabbat: true }).
v01.78.000חדשהגדרות AI / עוזר פנימי / פורטל לקוחות / עובדיםminorספקי AI מרובים לכל סוכן + מערכת מכסת שאלות
כל אחד משלושת סוכני ה-AI (WhatsApp, עוזר פנימי, פורטל לקוחות) תומך כעת בכל ספק — Anthropic, Google ו-OpenAI-compatible.
פרטים נוספים ↓הסתר ↑
כל אחד משלושת סוכני ה-AI (WhatsApp, עוזר פנימי, פורטל לקוחות) תומך כעת בכל ספק — Anthropic, Google ו-OpenAI-compatible. כשהטנאנט לא מגדיר מפתח משלו, המערכת משתמשת במפתח ה-Anthropic הכללי עם מגבלת 5 שאלות ליום. הצ'אט מציג פס התקדמות ונחסם כשהמכסה מוצתה. דף הגדרות AI עוצב מחדש לחלוטין — קטע נפרד לכל סוכן עם ניהול מפתח inline, נקודת סטטוס צבעונית ועיצוב ברור ואינטואיטיבי. נוסף גם הגדרת מדבקות ברמת החברה: ניתן להשבית ברקוד נפרד לכל חבילה (סיומת -1, -2...) — כל המשתמשים בחשבון ידפיסו ברקוד בסיסי ללא סיומת.
- כל ספק (Anthropic, Google Gemini, OpenAI-compatible) זמין לכל שלושת הסוכנים — ניתן לבחור ספק ומודל נפרד לכל סוכן
- מנוע אחיד (run-agent.ts) תומך בפרוטוקולי Anthropic SDK ו-OpenAI-compatible fetch כולל tool-calling מרובה תורות
- מכסת שאלות: 5 שאלות ביום כשמשתמשים במפתח המערכת — ללא מגבלה עם מפתח API מוגדר
- פס התקדמות בחלון הצ'אט מציג שאלות בשימוש/מגבלה; חסימת קלט ותיאור ברור כשהמכסה מוצתה
- דף הגדרות AI עודכן: בחירת ספק ומודל מלאה לעוזר הפנימי ולפורטל הלקוחות (לא רק מפתח API)
- סוכן פורטל הלקוחות תומך כעת בפתיחת פניות בירור (שאלות למחסן, צפי, אובדן, בחוסר, כלליות) ישירות מהצ'אט
- streaming אמיתי: תוצאות ה-AI מוצגות למשתמש token-by-token בזמן אמת — Anthropic דרך ה-streaming SDK, OpenAI-compatible דרך SSE
- הערות AI: הסוכן הפנימי יכול לשמור תובנות על משלוח (כשלים חוזרים, חריגות) בטבלה ייעודית — מוצגות בדף המשלוח ברצועה צהובה בולטת עם אפשרות העתקה
- sendWhatsappToDriverGroup: שליחה ממוקדת לקבוצת WhatsApp של שליח ספציפי; אם אין קבוצה מוגדרת — נפתח AdminTask לטיפול ידני אוטומטית
- עדכון סטטוס משלוח ע"י AI: confidence=certain מבצע מיד עם רשומה ב-AuditLog; confidence=low פותח AdminTask לבדיקה ידנית. כפתור 'בטל' בציר הזמן מאפשר ביטול כל שינוי AI בלחיצה אחת
- תובנות AI מצטברות (AiInsight): הסוכן בונה ידע ארוך-טווח על שליחים, לקוחות ומשלוחים — מוצג בדפי הישות ברצועה ענברית
- שאלות AI לאישור אנושי (AiPendingQuestion): הסוכן שומר שאלות כשיש חוסר ודאות; badge ב-FAB + פאנל תשובה עם כן/לא/דחה ישירות מהוידג'ט
- הנחיות מותאמות אישית לעוזר הפנימי: כל טנאנט יכול להגדיר טקסט חופשי שמוזרק ל-System Prompt — מגדיר כללים עסקיים ייחודיים (שעות, לקוחות מיוחדים, הגבלות) שהסוכן מכבד בכל שיחה
- AiLearningQueue — pipeline ללמידה מהודעות WhatsApp: אישורי/הכחשות מסירה נרשמות אוטומטית בתור לימוד; cron שעתי מנתח דפוסים לפי לקוח ומחלץ תובנות AI ארוכות-טווח
- התראות פרואקטיביות: cron פעמיים ביום מזהה משלוחים שחרגו מ-3+ ימים ושולח אוטומטית בקשת אישור מסירה ב-WhatsApp לנמען — תגובת הלקוח מעובדת על-ידי המערכת הקיימת
- כלי getDeliveryRiskScore לסוכן AI: מחשב ציון סיכון (low/medium/high/critical) לפי ימי חריגה, ניסיונות כושלים ונוכחות טלפון — מאפשר לסוכן לקבל החלטה מושכלת לגבי התערבות פרואקטיבית
- טופס עובד: הוספת סקשן שכר ותנאים — תעריף שעתי, שכר חודשי, סוג העסקה וקצובת נסיעות (יומי/חודשי). שדות אלה מאפשרים לחישוב שכר האוטומטי לפעול כראוי
v01.77.001שיפורהגדרות AIהגדרות AI פר-סוכן + תיקון retry על rate limit
כל אחד משלושת סוכני ה-AI (WhatsApp, עוזר פנימי, פורטל לקוחות) ניתן כעת להגדרה עם מפתח API נפרד.
פרטים נוספים ↓הסתר ↑
כל אחד משלושת סוכני ה-AI (WhatsApp, עוזר פנימי, פורטל לקוחות) ניתן כעת להגדרה עם מפתח API נפרד. בנוסף תוקנה בעיה שבה שגיאת 429 (rate limit) לא גרמה לניסיון חוזר — מה שגרם לכישלון מיידי של סוכן ה-WhatsApp כשהגיע למגבלת קצב של Google Gemini.
v01.77.000חדשפורטל לקוחות / מדבקותminorשיפורי פורטל לקוחות — הדפסה, כתובות, הערות
סדרת שיפורים לפורטל הלקוחות לפי בקשות משתמשים: הדפסת מדבקה מיידית לאחר יצירת משלוח, autocomplete לשדות עיר ורחוב, הצגת הערות על המדבקה, ואפשרות הדפסת 4 או 8 מדבקות בדף A4.
פרטים נוספים ↓הסתר ↑
סדרת שיפורים לפורטל הלקוחות לפי בקשות משתמשים: הדפסת מדבקה מיידית לאחר יצירת משלוח, autocomplete לשדות עיר ורחוב, הצגת הערות על המדבקה, ואפשרות הדפסת 4 או 8 מדבקות בדף A4.
- לאחר יצירת משלוח בפורטל — מוצג מסך הצלחה עם כפתור הדפסה מיידית (ללא חיפוש ידני)
- שדה עיר הפך ל-combobox עם ישובים מה-DB; שדה רחוב מציע השלמה אוטומטית מ-data.gov.il (debounce 300ms)
- הערות משלוח (הערת יעד + הערת משלוח) מוצגות כעת על המדבקה — מופעל כברירת מחדל
- הגדרות מדבקה: אפשרות להדפיס 4 מדבקות על A4 לאורך (2×2) או 8 מדבקות על A4 לרוחב (4×2) לגזירה עצמית
- אפשרות להוסיף עד 3 מספרי טלפון נוספים למשלוח ישירות מהפורטל
- עריכה וביטול משלוח בפורטל — זמין בלבד לפני שהנהג אסף את החבילה; לאחר עריכה מוצגת הנחיה להדפסת מדבקה חדשה
- משלוח עם מספר חבילות מדפיס מדבקה נפרדת לכל חבילה עם ברקוד ייחודי (למשל 12345678-1, 12345678-2); סריקה של ברקוד עם סיומת מזהה את המשלוח האב ורושמת את מספר החבילה ביומן
v01.76.000חדשמחסן / תפעולminorסריקות מחסן — קליטה ומיון חבילות
הוספת מערכת סריקות מחסן: עובד מחסן סורק ברקוד של חבילה כדי לסמן אותה כ"נקלט במחסן" (קליטה) או לשייך אותה לנהג (מיון).
פרטים נוספים ↓הסתר ↑
הוספת מערכת סריקות מחסן: עובד מחסן סורק ברקוד של חבילה כדי לסמן אותה כ"נקלט במחסן" (קליטה) או לשייך אותה לנהג (מיון). הממשק Web עובד עם סורק USB/Bluetooth שמזין ברקוד אוטומטית, כולל גם הקלדה ידנית. האפליקציה הניידת מאפשרת סריקה בקמרה עם רשימה מצטברת של פריטים שנסרקו ופידבק מיידי. בנוסף, בדף המשלוחים הוסף פילטר תאריך חדש: "תאריך קליטה במחסן" המציג רק משלוחים שנסרקו לתוך המחסן בטווח הנבחר; "תאריך קליטה" שונה שמו ל"תאריך איסוף" להבהרת המשמעות.
- דף Web חדש /shipments/scan עם שני מצבים: קליטה במחסן ומיון לנהג
- קלט אוטומטי מסורק USB/Bluetooth — מיקוד אוטומטי, Enter מפעיל סריקה
- מסך סריקה חדש באפליקציה הניידת (Admin) עם קמרה + בחירת נהג
- API endpoint POST /api/shipments/scan עם אימות tenant ורישום ביומן פעילות
- גישה מהירה מ-dashboard הניהולי במובייל
- פילטר תאריך חדש בדף המשלוחים: "תאריך קליטה במחסן" — מסנן לפי תאריך הסריקה הראשונה במחסן
- שינוי שם: "תאריך קליטה" ← "תאריך איסוף" (תאריך האיסוף מבית העסק)
- סריקת מיון עם נהג SNL — שידור אוטומטי לאחר כל סריקה עם תג סטטוס משדר/שובר על כל שורה
- סריקה בקמרה ב-Web — overlay מסך מלא עם מסגרת מרצדת, ניתוח ברקוד רציף ועצירה אוטומטית, תמיכה בפנס, עדיפות למצלמה אחורית בטאבלט
- תיקון: מיקוד אוטומטי בדף הסריקה לא חוסם יותר פוקוס על אלמנטים אחרים (חיפוש גלובלי, כפתורים וכו')
- שינוי מינוח: "אזור חלוקה" → "אזור הפצה" בכל ממשק המשתמש
- הכרזה קולית על אזור החלוקה בסריקת קליטה — הקול מבוסס שם ישוב (לא אזור ליונוויל), עם כפתור הפעלה/כיבוי ותג ויזואלי על כל שורה
- סריקת שיבוץ נהג: צליל אישור דיגיטלי על סריקה תקינה, וצליל אזעקה כאשר הנהג אינו מורשה לאזור החלוקה של המשלוח (טעות מיון בזמן אמת)
- שידור SNL — תמיכה במשימות איסוף ו-exchange (task_type): כתובות מוסחות בהתאם לסוג המשימה — נהג רואה רק מה שצריך, לא כתובת הלקוח האמיתית
- אבטחה: שדה כתובת המחסן (Warehouse Address) נשמר כעת בהגדרות אינטגרציה SNL ומשמש אוטומטית בשידורי איסוף ו-exchange
- תיקון אזהרת UX: ניתן כעת למחוק את ה-Webhook Secret בכרטיסיית שידורים בדף הנהג — כפתור 'מחק Secret' עם אינדיקציה ויזואלית לפני השמירה
- תיקון: webhook כשל מ-SNL עכשיו מסמן את ביקור המסירה כנכשל וכולל סיבת כשל בציר הזמן
- תיקון: עדכוני סטטוס מ-SNL נרשמים כעת ביומן הפעולות
- תיקון: מזהה יוצא של SNL לא נדרס יותר ע"י מזהה ליונוויל כאשר שניהם שידרו את אותו משלוח
- יומן סריקות בדף המשלוח — קטע חדש 'יומן סריקות' מציג את כל הסריקות: קליטה במחסן, שיוך שליח, וסריקות אפליקציית שליח (Lionwheel webhook)
v01.75.001תיקוןSNL / יומן פעולות / AIשידור SNL — תיקון יומן פעולות ועדכון ליונוויל
שידור SNL לא רשם רשומה ביומן הפעולות ולא דחף את סטטוס IN_TRANSFER לליונוויל.
פרטים נוספים ↓הסתר ↑
שידור SNL לא רשם רשומה ביומן הפעולות ולא דחף את סטטוס IN_TRANSFER לליונוויל. תוקן: כל שידור מוצלח רושם כעת רשומת 'שידור ל-SNL' עם מזהה הברקוד המוחזר מ-SNL, ומעדכן את ליונוויל לסטטוס 10 (בהעברה). בנוסף, תוקן סוכן ה-AI: כשמשתמש שואל על מספר משלוח מספרי (כגון 24955894) הסוכן מחפש אותו כברקוד ולא כמזהה פנימי.
v01.75.000חדשאינטגרציות / שידור משלוחיםminorשידור ישיר לש.נ.ל — אינטגרציה עם קבלן חיצוני
הוספת אינטגרציה ישירה עם ש.נ.ל פתח תקווה 13 לשידור משלוחים ללא תלות בליונוויל.
פרטים נוספים ↓הסתר ↑
הוספת אינטגרציה ישירה עם ש.נ.ל פתח תקווה 13 לשידור משלוחים ללא תלות בליונוויל. כאשר מאקצים נהג SNL למשלוח, המשלוח נשדר אוטומטית ל-API שלהם והסטטוס עובר להעברה. עדכוני סטטוס מ-SNL מתעדכנים גם אצלנו וגם בליונוויל. הוכחת מסירה (חתימה + שם חותם) נשמרת אוטומטית.
- שידור אוטומטי בעת שיוך נהג SNL — סטטוס עובר להעברה (IN_TRANSFER)
- Webhook endpoint /api/webhooks/snl/[tenantId] עם אימות HMAC-SHA256
- מיפוי מלא: imported → בהעברה, received_in_warehouse → נקלט במחסן, assigned_to_driver → יצא להפצה, in_transit → יצא לחלוקה (ACTIVE), delivered → הושלם, failed_attempt → נכשל; returned/cancelled לא משנים סטטוס פנימי — נשמרים רק ב-snl_status לצורכי שירות לקוחות
- תיקון: אימות Webhook timestamp מ-Unix שניות ל-Unix מילישניות (בהתאם לאישור מצוות ש.נ.ל)
- הוכחת מסירה: signature_url נשמר כ-ShipmentImage (pod/snl), signer_name ב-additionalData
- סינק סטטוס חזרה לליונוויל אחרי כל עדכון מ-SNL
- שדה providerCode בנהג — לסימון נהגי SNL
- תיקון קריטי: שידור כולל עכשיו את סכום הגביינא (cod_amount) מ-CodTracking — בעבר נשלח תמיד 0
- תיקון: עמודת destination_phone2 חסרה מטבלת cod_tracking — גרמה לשגיאת 500 בכל טעינת נתוני גוביינא לפי ברקוד
- עדכון מדיניות פרטיות: מילוי פרטי החברה (Shipnest, סירקין 5 בני ברק, יוסי סודרי), הוספת סעיף ייעודי לאפליקציית השליחים (מיקום, מצלמה, הקלטה, התראות)
- שיוך שליח באצווה מדף המשלוחים — בחירת מרובה + כפתור 'שיוך שליח' עם בחירת סוג משימה (מסירה/איסוף); אם הנהג הוא קבלן SNL, השידור לש.נ.ל מתבצע אוטומטית
v01.74.001חדשאינטגרציות / פורטל לקוחותאינטגרציה עם nopCommerce — פורטל לקוחות
הוספת תמיכה בחנויות nopCommerce בפורטל הלקוחות.
פרטים נוספים ↓הסתר ↑
הוספת תמיכה בחנויות nopCommerce בפורטל הלקוחות. הזמנות חדשות נמשכות כל 5 דקות, סטטוס ההזמנה מתעדכן אוטומטית עם מסירה.
v01.74.000חדשAI / פנימיminorעוזר AI פנימי — צ'אט חכם + תרחישי ETA וכישלון מסירה
עוזר AI פנימי לעובדי החברה עם שאלות בשפה טבעית.
פרטים נוספים ↓הסתר ↑
עוזר AI פנימי לעובדי החברה עם שאלות בשפה טבעית. תרחיש 1: AI שולח WhatsApp לשליח כשמשלוח מעוכב. תרחיש 2: שליח מדווח על כישלון → הודעה ללקוח העסקי + טיימר 30 דקות לסימון FAILED אוטומטי. תרחיש 3: שליחת בקשת אישור מסירה לנמען — תשובת 'כן' מסמנת DELIVERED אוטומטית.
- צ'אט SSE streaming בממשק היסטורי עם sidebar לניהול שיחות
- Shipment Agent עם 6 כלים: חיפוש, פרטים, טיימליין, ימי הפצה, פרטי לקוח, רשימת עיכובים
- היסטוריית שיחה מועברת ל-AI בכל הודעה — AI זוכר את ההקשר
- שמירת היסטוריית שיחות ב-DB (ai_chat_sessions / ai_chat_messages)
- הרשאות AI_CHAT_USE ו-AI_INSIGHTS_VIEW — OWNER/ADMIN/CS בלבד
- תרחיש 3: כפתור ממשק לבקשת אישור מסירה + AiDeliveryConfirmation + סיווג Haiku → DELIVERED אוטומטי
- שדות whatsappGroupChatId/Name בטופס עריכת שליח — Green API קבוצות נפרד מאינבוקס לקוחות
- תרחיש 4: כלי updateShipmentAddress — עדכון כתובת/טלפון מהצ'אט + סנכרון ליונוויל + הודעה לשליח
- כלל אבטחה: לעולם לא מזכיר 'קבלן' — תמיד 'שליח'
- עוזר AI פנימי הוסב לווידג'ט צף (FAB) בפינה שמאל-תחתית — נגיש מכל דף ללא ניווט נפרד
- הגדרות ספק AI: טוגל לכיבוי/הפעלת עוזר AI פנימי (settings.aiChat.enabled) — חוסם API + מציג מצב בממשק
- תיקון: כניסה עם Google נכשלה בניסיון ראשון עקב AdapterError — הסרת יצירת Account ידנית כפולה
- פורטל לקוח: הסרת מגבלת 10 מדבקות — הדפסת כמות בלתי מוגבלת (עד 250) כ-PDF אחד
- תיקון e-shop: הודעת שגיאה 401/403 הציגה HTML גולמי מה-API — כעת מוצגת הודעה נקייה ומובנת
- סוכן AI לקוחות עסקיים (Agent 3): ווידג'ט צף (FAB) בפורטל — שאילתות משלוחים בעברית טבעית
- Green API webhook: זיהוי הודעות נכנסות מלקוחות עסקיים — קבוצה (@g.us) לפי whatsappGroupChatId, פרטי (@c.us) לפי טלפון מנורמל
- Session שיחה מתמשך: session חי עד 24 שעות ממסרון אחרון, אחרת session חדש אוטומטית
- שדות whatsappGroupChatId/Name נוספו לטופס עריכת לקוח — קישור לקוח לקבוצת WhatsApp שלו
v01.73.000חדשWhatsApp / Inboxminorמענה אוטומטי WhatsApp — סוכן AI מטפל בהודעות נכנסות
הוספת מנוע סיווג AI שמטפל אוטומטית בכל הודעת WhatsApp נכנסת מלקוח קצה.
פרטים נוספים ↓הסתר ↑
הוספת מנוע סיווג AI שמטפל אוטומטית בכל הודעת WhatsApp נכנסת מלקוח קצה. הסוכן מסווג כל הודעה לאחת מ-4 קטגוריות ומחליט אם לענות אוטומטית, לעדכן שדות משלוח, או להעביר לטיפול אנושי.
- 4 קטגוריות סיווג: אישור/טריוויאלי, AI פותר, פנייה לשולח, הסלמה לאדם
- עדכון שדות משלוח אוטומטי: קומה, דירה, קוד כניסה, הוראות
- תגובה עם עיכוב אנושי (2-4 שניות) בתוך חלון 24 שעות
- טבלת WhatsappConversation חדשה לניהול סטטוס שיחות
- Inbox: החלפת tabs ל'לא טופל' / 'טופל' עם מדדי AI בזמן אמת
- תווית 🤖 על שיחות שטופלו, ובאנר הערה פנימית בקטגוריה 4
- שיחות שטופלו ע"י AI מסומנות אוטומטית כנקראות — רק הסלמות נשארות כלא נקרא
- תיקון קונפליקט ניתובים ב-/contracts שגרם למסך לבן לכלל המשתמשים — שינוי שם פרמטר הנתיב הציבורי מ-[token] ל-[id]
- אפשרות ידנית לסמן שיחה כ'טופל' דרך תפריט ימני-קליק, גם ללא מעורבות AI
- תיקון classifier: תגובות אוטומטיות/בוט של עסקים → קטגוריה 1 (לא הסלמה), הערות AI כעת בעברית
- classifier מכיר כעת את כל סטטוסי המשלוח ומשיב בהתאם — בוטל → פנייה לשולח, נמסר אך לא התקבל → הסלמה דחופה
- הגדרות ספק AI חדשות: בחירת Anthropic / Google Gemini / כלי תואם-OpenAI, הזנת מפתח API מוצפן, בחירת מודל
- תיקון: AI כעת תומך גם בעדכון רחוב (update_street) — נמנע ממצב שבו ה-AI הודיע על עדכון כתובת אך השינוי לא בוצע בפועל
- תיקון: תגובות אימוג'י (❤️, 👍 וכו') מעובדות כעת על ידי ה-AI — לפני כן נשארו כ'לא טופל' לנצח
- הסכמים: עמוד חתימה ציבורי (/contracts/[token]) — לקוח קצה קורא את ההסכם ב-HTML נקי וחותם דיגיטלית ללא צורך בהתחברות
- הסכמים: שדה 'איש קשר מטעם הלקוח' (contact person) — מופיע בסעיף 'לבין:' בהסכם ובקובץ PDF
- הסכמים: תבנית ברירת מחדל עם 30 סעיפי החוזה המלאים ונוסח 'הואיל ו...' — מאכלס את הטופס מיד בפתיחה
- מעקב משלוח: צפי מסירה מחושב רק לאחר האיסוף — לפני האיסוף מוצגת הודעה שהצפי יופיע מיד לאחר שהחבילה תאסף מהשולח
- תיקון קריטי AI: סוכן WhatsApp קיבל סטטוס אופרטיבי במקום סטטוס לוגיסטי — תוקן, כעת מועבר הסטטוס האמיתי (UNASSIGNED/ACTIVE וכו') שממנו הסוכן מבין באיזה שלב המשלוח
- תיקון AI: כשלקוח שולח כמה הודעות ברצף מהיר — כעת מעובד רק ה-session האחרון (במקום כל session בנפרד, שגרם לתגובה כפולה); פרומפט עודכן: שאלת 'יגיע היום?' כשטרם נאסף → תשובה ישירה ומפורשת
- שיפור מהימנות AI: בקריאות ל-Gemini שנכשלות עם 503 (עומס יתר) — retry עם 3 ניסיונות נוספים ו-exponential backoff (3s / 9s / 27s) במקום ניסיון יחיד
- הגדרת שעות פעילות בדף הגדרות AI: כשה-AI נכשל, נשלחת ללקוח הודעת fallback — בשעות פעילות: 'שיחתך הועברה לנציג'; מחוץ לשעות: 'נחזור אליך בתחילת יום העסקים הקרוב + שעות הפעילות'
- תיקון Inbox: פתיחת שיחה עכשיו גוללת לסמן 'הודעות חדשות' (100px מעל) כדי שנציגים יראו את ההודעה היוצאת האחרונה כהקשר — לפני כן גלל תמיד לתחתית ורקע השיחה נעלם מהתצוגה
- Inbox: ברקוד המשלוח מופיע בכותרת הצ'אט כלינק לחיץ — נציגים מזהים מיד במה לטפל גם כשהודעת ההתחלה אינה גלויה
v01.72.000חדשcrm/contractsminorשליחת הסכם — Send Dialog חדש עם התאמת מייל, CC, מעקב צפייה, תזכורות אוטומטיות, נעילה ו-WhatsApp
במקום 'אישור > שלח' של שורה אחת, הכפתור 'שלח לחתימה' פותח דיאלוג מלא בן 2 עמודות: בצד אחד תצוגת PDF חיה של ההסכם (endpoint חדש /api/contracts/[id]/preview-pdf), ובצד השני 4 סקציות הגדרה — הודעת המייל עם תחליפים ({name}, …
פרטים נוספים ↓הסתר ↑
במקום 'אישור > שלח' של שורה אחת, הכפתור 'שלח לחתימה' פותח דיאלוג מלא בן 2 עמודות: בצד אחד תצוגת PDF חיה של ההסכם (endpoint חדש /api/contracts/[id]/preview-pdf), ובצד השני 4 סקציות הגדרה — הודעת המייל עם תחליפים ({name}, {tenantName}, {contractNumber}) ל-subject ול-body, רשימת CC לעותק PDF החתום (מיילים נוספים שיקבלו את ההסכם החתום ברגע שייחתם), מעקב צפייה (מייל אוטומטי לסוכן ברגע שהלקוח פותח את הקישור — פעם אחת בלבד), ותזכורת אוטומטית + נעילה (cron יומי /api/cron/contract-reminders ששולח מייל חוזר אם לא נחתם תוך X ימים, ו-publicAccessExpiresAt שמחושב לפי autoLockDays). כל הגדרה נשמרת על ההסכם (Contract.customEmailSubject/Body/ccEmails/notifyOnView/notifyEmail/reminderEnabled/reminderDays/autoLockEnabled/autoLockDays) ונטענת מחדש בעת עריכה. כפתור 'פתח צ'אט WhatsApp' מוצג כשיש לליד טלפון — בונה wa.me link עם הודעה מוכנה, יפתח WhatsApp Web/App ויחסוך התקשרות. כל הזרימה נשמרת על-גבי כל מה שכבר עשינו (מותג-טננט, סעיפים ממוספרים, נספחים).
- Send Dialog 2-column עם תצוגת PDF חיה בצד אחד והגדרות בצד השני
- Subject + body עם תחליפים ({name}/{tenantName}/{contractNumber}) ניתנים לעריכה לפני שליחה
- CC לעותק של ה-PDF החתום — נוסף אוטומטית כ-BCC על מייל האישור
- התראת צפייה — מייל לסוכן ברגע שהלקוח פותח את הקישור (פעם אחת)
- תזכורת אוטומטית + נעילה — cron יומי, מייל ממותג עם hero 🔔, ו-publicAccessExpiresAt לפי autoLockDays
- כפתור פתיחת צ'אט WhatsApp עם הלקוח (wa.me + מספר ישראלי מומר לפורמט בינלאומי)
v01.71.000חדשcrm/leadsminorלידים — שדות הסמכה (כמות / משקלים / גדלים) כ-Selects עם bucket קנוני בכל המערכת
שלושת השדות 'כמות חודשית', 'טווח משקלים', 'טווח גדלים' עברו מ-input חופשי ל-Select עם רשימת ערכים סגורה — בכל המערכת: LeadForm הפנימי, ImportLeadsDialog, וטופס embed לאתר.
פרטים נוספים ↓הסתר ↑
שלושת השדות 'כמות חודשית', 'טווח משקלים', 'טווח גדלים' עברו מ-input חופשי ל-Select עם רשימת ערכים סגורה — בכל המערכת: LeadForm הפנימי, ImportLeadsDialog, וטופס embed לאתר. הערכים מוגדרים בקובץ משותף lead-options.ts: כמות חודשית (פחות מ-50 / 50-100 / 100-200 / 200-500 / יותר מ-500), משקלים (עד 5/5-10/10-20/יותר מ-20 ק״ג), גדלים (מעטפות / שקיות / קרטון עד 20×30×30 / קרטון 40×40×60). שינוי schema: monthlyExpectedQuantity עבר מ-Int? ל-String? (VARCHAR(100)) — הערך 'משוערת' זה לא מספר מדויק. POST /api/public/leads קיבל את שלושת השדות החדשים, ה-HTML snippet כולל אותם כ-selects עם ה-options מולאים, פרומט ה-AI מציין את הרשימות המדויקות (כולל הוראה לא לשנות גרשיים/רווחים), ודוגמת cURL מציגה ערכים אמיתיים. הסיבה: אמינות הנתונים — bucket תמיד יותר אמין ממספר חופשי שהמשתמש משער. גם משפר conversion על דפי נחיתה (לחיצה אחת במקום הקלדה).
- שלוש קבוצות bucket קנוניות, משותפות לפנים ולחוץ
- monthlyExpectedQuantity: Int → String (כי 'משוערת' זה לא מספר)
- POST /api/public/leads קיבל monthlyExpectedQuantity / weightRange / sizeRange
- HTML snippet בטופס embed כולל את שלושת ה-selects מולאים
- פרומט ה-AI מציג את הערכים בדיוק (גרשיים, רווחים, מקפים) ומבקש מה-AI לא לשנות
v01.70.002שיפורcrm/contractsעמוד חתימה — חזרה ללינק אחרי חתימה מציגה כעת מסך מקצועי עם הורדת PDF
כשלקוח לחץ שובה על קישור החתימה אחרי שכבר חתם, הוא ראה אותו מסך הצלחה גנרי בלי כפתור הורדה (ה-API לא החזיר את ה-URL של ה-PDF החתום על revisit).
פרטים נוספים ↓הסתר ↑
כשלקוח לחץ שובה על קישור החתימה אחרי שכבר חתם, הוא ראה אותו מסך הצלחה גנרי בלי כפתור הורדה (ה-API לא החזיר את ה-URL של ה-PDF החתום על revisit). עכשיו GET /api/public/contracts/[token] מחזיר signedPdfUrl, signedAt, signedByName ופרטי קשר של הטננט גם כשההסכם כבר נחתם, וה-/sign/[token] מציג מסך מעוצב חדש עם: Hero בצבע המותג, נתוני ההסכם (מספר, חותם, תאריך), כפתור הורדת PDF גדול, ושורת אמון עם פרטי הקשר של הטננט. הכותרת מתאימה עצמה — 'ההסכם נחתם בהצלחה' כשזה הרגע שאחרי חתימה, 'ההסכם כבר נחתם' כשזה revisit. שיפור על-פני חתימה ירוקה שמציגים מסך מינימלי בלי הורדת PDF.
v01.70.001שיפורcrm/emailsמיילים ללקוחות — עיצוב מותג-טננט (הצעה, שליחת הסכם, אישור חתימה)
שכתוב מלא של 3 המיילים שנשלחים ללקוחות חיצוניים: הצעת מחיר, שליחת הסכם לחתימה, ואישור חתימה.
פרטים נוספים ↓הסתר ↑
שכתוב מלא של 3 המיילים שנשלחים ללקוחות חיצוניים: הצעת מחיר, שליחת הסכם לחתימה, ואישור חתימה. במקום HTML פלפול כללי ש-'From' שלו 'Shipnest', המייל יוצא עכשיו בשם הטננט עצמו ('שיפינג ש.י.פ.' במקום 'Shipnest') והעיצוב מותאם פר-טננט: לוגו הטננט בכותרת (אם קיים), צבע המותג של הטננט ב-Hero panel, ופרטי הקשר של הטננט (טלפון, מייל, כתובת) כשורת אמון לפני קרדיט Shipnest קטן. כל מייל מציג Hero ייעודי (🧾 להצעה, 📝 להסכם, ✓ לאישור), כותרת ברורה, ברכה אישית עם שם הנמען, פרטי המסמך כ-facts grid, CTA גדול בצבע המותג, הסבר קצר על האקשן, והערה משפטית. תשתית משותפת renderBrandedEmail() מאחדת את כל ה-template. תאימות מלאה ל-Outlook + Gmail + Apple Mail (table-based, inline styles).
- 'From' header מציג את שם הטננט בולט במקום 'Shipnest' (גם בפרסום ב-inbox)
- צבע המותג של הטננט עובר ב-Hero ובכפתור CTA
- לוגו הטננט בכותרת (fallback: שם בצבע מותג)
- פרטי קשר של הטננט (טלפון/מייל/כתובת) כשורת אמון — חסר ב-2sign
- Hero panel ייעודי לכל סוג מייל עם icon רלוונטי
- תשתית renderBrandedEmail() משותפת — נוחה להוסיף עליה מיילים עתידיים
v01.70.000חדשcrm/contractsminorPDF הסכם — עיצוב משפטי-מקצועי + נספחים: ערבות אישית וביטוח
שכתוב מלא של ה-PDF של ההסכם כדי שייראה כמסמך משפטי רשמי.
פרטים נוספים ↓הסתר ↑
שכתוב מלא של ה-PDF של ההסכם כדי שייראה כמסמך משפטי רשמי. הדר נקי עם לוגו ממורכז + שם עסק + ע.מ. בכל עמוד, פתיח 'בין:/לבין:' עם פרטים מלאים של המוביל (משאבי הטננט) והלקוח, פסקת 'הואיל ו...' אופציונלית, וסעיפים ממוספרים אוטומטית (השורה הראשונה של כל פסקה ב-bold ככותרת). פוטר עם פרטי קשר ומספור דפים בכל עמוד. הוספת 3 נספחים: א' תעריפים מוסכמים בעמוד נפרד עם חתימה; ב' ערבות אישית (אם הוספו ערבים) עם נוסח קבוע + שדות מודבקים לכל ערב + שורת חתימה; ג' ביטוח חבילות (אם הופעל) עם סכומי כיסוי וחתימה. שדות חדשים בהסכם: preambleText, guaranteeText, insuranceText, insuranceEnabled, insuranceMonthlyAmount, insuranceCoverageAmount. מודל חדש ContractGuarantor (רבים פר-הסכם). ContractTemplate הורחב ב-preamble/guarantee/insurance כשדות תבנית. טופס יצירת/עריכת הסכם קיבל סקציות חדשות: 'הואיל ו...', רשימת ערבים עם הוסף/הסר, וטוגל ביטוח עם 2 שדות סכום.
- הדר נקי בכל עמוד עם לוגו + שם + ע.מ. ופוטר עם פרטי קשר ומספור
- פתיח 'בין:/לבין:' עם פרטים מלאים של המוביל והלקוח + ביטויי '(להלן: "...")'
- מספור אוטומטי של סעיפי תנאים — כל פסקה הופכת לסעיף עם השורה הראשונה ב-bold
- נספח א' תעריפים נפרד עם חתימת לקוח
- נספח ב' ערבות אישית — מודל חדש שתומך בריבוי ערבים, עם נוסח קבוע ושדות מודבקים
- נספח ג' ביטוח חבילות — עלות חודשית + תקרת כיסוי + שורת חתימה (אופציונלי)
- כל הנוסחים ניתנים לעריכה ברמת ContractTemplate
v01.69.003שיפורcrm/leadsטופס לאתר — הסבר מובנה למשתמש + פרומט מוכן ל-AI מפתח אתרים
ה-LeadEmbedDialog קיבל שתי שכבות חדשות שמיועדות למשתמש (לא מפתח): (1) Collapsible 'איך הטופס הזה עובד?' בראש הדיאלוג שמסביר במונחים יומיומיים מה זה עושה, איך זה זורם, מהן הגנות ה-anti-spam, ולמה הטוקן בטוח לשים באתר ציבו…
פרטים נוספים ↓הסתר ↑
ה-LeadEmbedDialog קיבל שתי שכבות חדשות שמיועדות למשתמש (לא מפתח): (1) Collapsible 'איך הטופס הזה עובד?' בראש הדיאלוג שמסביר במונחים יומיומיים מה זה עושה, איך זה זורם, מהן הגנות ה-anti-spam, ולמה הטוקן בטוח לשים באתר ציבורי. (2) Tab חדש 'פרומט ל-AI' (ברירת מחדל) — טקסט מפורט עם הטוקן וה-API URL מולאים אוטומטית, שהמשתמש מעתיק ומדביק בצ׳אט AI שמפתח לו את האתר (v0/Cursor/Claude/ChatGPT/Lovable) כדי לקבל טופס שמשתלב חזותית באתר במקום HTML גנרי. הפרומט כולל מבנה שדות, לוגיקת שליחה, טיפול בתגובות, חוויית משתמש מצופה, ו-CORS. סדר הטאבים: AI (מומלץ) → HTML מוכן → cURL. כפתור 'הסבר תיבת הצהובה' הישן הוסר (החליף אותו ה-Collapsible הכחול בראש).
v01.69.002שיפורcrm/leadsלידים — 'טופס לאתר' ו'ייבוא מ-Excel' עברו למודלים במקום דפים נפרדים
שני הכפתורים בסרגל הכלים של /leads (טופס לאתר, ייבוא מ-Excel) פתחו עד עכשיו דפים נפרדים (/leads/embed, /leads/import) שדרשו ניווט וחזרה — חוויה כבדה לשני flows קצרים.
פרטים נוספים ↓הסתר ↑
שני הכפתורים בסרגל הכלים של /leads (טופס לאתר, ייבוא מ-Excel) פתחו עד עכשיו דפים נפרדים (/leads/embed, /leads/import) שדרשו ניווט וחזרה — חוויה כבדה לשני flows קצרים. הם הומרו ל-Dialogs (מודלים) שנפתחים על דף הלידים, בהתאם לקונבנציית ה-Dialog של המערכת (header + flex-1 min-h-0 overflow-y-auto + footer). בייבוא: בסיום ייבוא מוצלח הטבלה מתרעננת אוטומטית. רכיבים חדשים: LeadEmbedDialog, ImportLeadsDialog. הדפים הנפרדים (/leads/embed/, /leads/import/) נמחקו.
v01.69.001שיפורcrm/leadsלידים — KPI Cards דחוסות יותר + הסרת 'המרות החודש'
כרטיסי ה-KPI מעל טבלת הלידים הוקטנו לחצי בערך: layout אופקי (מספר+תווית מימין, אייקון משמאל) במקום אנכי, padding מצומצם, טקסט קטן יותר, וגובה כולל פוחת מ-~110px ל-~50px.
פרטים נוספים ↓הסתר ↑
כרטיסי ה-KPI מעל טבלת הלידים הוקטנו לחצי בערך: layout אופקי (מספר+תווית מימין, אייקון משמאל) במקום אנכי, padding מצומצם, טקסט קטן יותר, וגובה כולל פוחת מ-~110px ל-~50px. הכרטיסיה 'המרות החודש' הוסרה (פידבק מהמשתמש — מיותרת). נשארו 4 כרטיסיות במקום 5: לידים פעילים, חדשים השבוע, מעקבים היום, באיחור.
v01.69.000חדשcrm/leadsminorלידים — תצוגת Kanban (לוח Pipeline) עם גרירה
דף חדש /leads/board עם תצוגת Kanban: 8 עמודות (סטטוסים), כרטיס פר ליד עם שם עסק, איש קשר, עיר, עדיפות, תאריך מעקב הבא (אדום אם באיחור), עד 3 תגיות, וכפתורי חיוג/WhatsApp/מייל.
פרטים נוספים ↓הסתר ↑
דף חדש /leads/board עם תצוגת Kanban: 8 עמודות (סטטוסים), כרטיס פר ליד עם שם עסק, איש קשר, עיר, עדיפות, תאריך מעקב הבא (אדום אם באיחור), עד 3 תגיות, וכפתורי חיוג/WhatsApp/מייל. גרירה ושחרור מעבירה ליד בין סטטוסים ומבצעת PATCH אוטומטי + יוצרת LeadActivity STATUS_CHANGE. עדכון אופטימי + rollback אם ה-API נכשל. כפתור 'תצוגת לוח' נוסף לסרגל הכלים של /leads ובחזרה כפתור 'תצוגת טבלה' ב-/board. מבוסס על רכיב ה-Kanban הקיים (dnd-kit) של המערכת. שלב 6 הושלם — Roadmap CRM-מלא-ללידים הושלם במלואו!
- Pipeline view ויזואלי לכל ה-funnel: 8 עמודות סטטוסים
- Drag-and-drop בין עמודות → עדכון סטטוס מיידי + activity log
- כרטיס לוח מציג עדיפות, תגיות, מעקב באיחור (אדום), כפתורי קשר
- Toggle דו-כיווני בין תצוגת טבלה ל-Pipeline
- מסיים את ה-Roadmap בן 6 השלבים שהתחיל היום — Shipnest = CRM מלא ללידים
v01.68.001חדשcrm/leadsלידים — צרופות (כרטיסי ביקור, הצעות מחיר ידניות, וכו')
בכרטיס פרטי ליד (LeadDetails) נוספה סקציית 'קבצים מצורפים' לפני היסטוריית הפעילויות.
פרטים נוספים ↓הסתר ↑
בכרטיס פרטי ליד (LeadDetails) נוספה סקציית 'קבצים מצורפים' לפני היסטוריית הפעילויות. ניתן להעלות עד 20MB פר קובץ, להוריד, ולמחוק. הקבצים נשמרים ב-Supabase Storage תחת leads/tenants/{tenantId}/{leadId}/. בעת העלאה נוצרת LeadActivity מסוג NOTE עם הסימן 📎 ושם הקובץ, כך שגם הציר הזמן מתעד מה צורף. נוסף model חדש LeadAttachment עם foreign keys ל-Lead ו-Tenant (CASCADE delete). 3 endpoints חדשים: GET /api/leads/[id]/attachments (LEADS_VIEW), POST /api/leads/[id]/attachments (LEADS_EDIT, multipart/form-data), DELETE /api/leads/[id]/attachments/[attachmentId] (LEADS_EDIT). Tenant scoping מלא + הגנת agent (רואה רק שלו). שלב 5.3 הושלם — שלב 5 (Growth) הושלם.
v01.68.000חדשcrm/leadsminorלידים — מחולל טופס embed לאתרי לקוחות
דף חדש /leads/embed שמספק טוקן פר-טננט וסניפט HTML מוכן להדבקה בכל אתר.
פרטים נוספים ↓הסתר ↑
דף חדש /leads/embed שמספק טוקן פר-טננט וסניפט HTML מוכן להדבקה בכל אתר. כל ליד שיישלח דרך הטופס נכנס ל-/leads עם status=NEW ומקור 'טופס באתר' או הדומיין הפונה. הזיהוי משתמש בטוקן ייעודי (לא ב-API keys הכלליים) — קל לסבב אם דלף. נוסף POST /api/public/leads (ללא auth, מוגדר עם CORS פתוח ו-rate limit 30/דקה), GET+POST /api/settings/lead-form-token (GET דורש LEADS_VIEW, POST דורש SETTINGS_MANAGE). זיהוי כפילויות פעיל כברירת מחדל + חלון 5 דקות אנטי-spam פר טלפון. מציג גם snippet cURL לחיבור Make/Zapier/n8n. כפתור 'טופס לאתר' נוסף לסרגל הכלים של /leads. שלב 5.2 הושלם.
- Snippet HTML מוכן להדבקה — JS וסטיילינג מוטמעים, ללא תלות בספרייה
- טוקן ייעודי פר-טננט הנשמר ב-Tenant.settings — סבב בלחיצה
- CORS פתוח על POST /api/public/leads — עובד מכל דומיין
- אנטי-spam: 5 דקות חלון פר טלפון + רשימת כפילויות מלאה (Phase 1.3)
- Tab נוסף עם cURL לחיבור אוטומציות (Make/Zapier/n8n)
v01.67.000חדשcrm/leadsminorלידים — ייבוא מ-Excel/CSV (עד 2000 שורות)
דף חדש /leads/import שמאפשר העלאת קובץ Excel (.xlsx/.xls) או CSV, זיהוי אוטומטי של עמודות לפי כותרות בעברית/אנגלית (שם, שם עסק, טלפון, מייל, עיר, סוג מוצר, טווח משקלים/גדלים, גוביינות, סוג הפצה, עדיפות, תגיות, מקור, הערו…
פרטים נוספים ↓הסתר ↑
דף חדש /leads/import שמאפשר העלאת קובץ Excel (.xlsx/.xls) או CSV, זיהוי אוטומטי של עמודות לפי כותרות בעברית/אנגלית (שם, שם עסק, טלפון, מייל, עיר, סוג מוצר, טווח משקלים/גדלים, גוביינות, סוג הפצה, עדיפות, תגיות, מקור, הערות, כמות חודשית), תצוגה מקדימה של 5 שורות עם בא׳ למיפוי כל עמודה, וצ׳קבוקס לאישור יצירת כפילויות. POST /api/leads/import מקבל עד 2000 לידים, בודק כפילויות לפי טלפון/מייל/שם עסק (אותם כללים כמו POST /api/leads), ומחזיר סיכום: נוצרו / דולגו (כפילויות) / שגיאות עם מספרי שורות. נורמליזציה אוטומטית של גוביינות (כן/לא/yes/no/1/0), סוג הפצה ועדיפות (לפי enum key או לייבל עברי), ותגיות (מופרדות בפסיק). כפתור 'ייבוא מ-Excel' נוסף לסרגל הכלים של /leads. שלב 5.1 הושלם.
- זיהוי אוטומטי של כותרות עברית/אנגלית — 15 שדות נתמכים
- תצוגה מקדימה לפני שליחה + עריכת מיפוי ידני
- שילוב מלא עם זיהוי הכפילויות (Phase 1.3) — בברירת מחדל מדלג
- סיכום מפורט בסוף: כמה נוצרו / דולגו / שגיאות עם מספרי שורות
- תקרה של 2000 שורות פר ייבוא + rate limit של 5 בקשות לדקה
v01.66.002שיפורportal / storesהוספת הסבר איתור URL לחיבור Shopify
בשלב הראשון של חיבור חנות Shopify נוסף הסבר קצר כיצד למצוא את כתובת ה-myshopify.com — מיועד למשתמשים לא טכנולוגיים שאינם מכירים את ה-URL הפנימי של החנות.
v01.66.001שיפורעריכת משלוח — חשיפת 3 שדות נוספים שמסתנכרנים לליונוויל
אחרי הבדיקה האמפירית של 82 שדות מול ליונוויל (ראה scripts/lionwheel-probe-results.json) זיהינו 3 שדות שעובדים בכתיבה בליונוויל אבל לא היו זמינים לעריכה אצלנו: מספר מסמך (document_number), אימייל נמען (destination_email),…
פרטים נוספים ↓הסתר ↑
אחרי הבדיקה האמפירית של 82 שדות מול ליונוויל (ראה scripts/lionwheel-probe-results.json) זיהינו 3 שדות שעובדים בכתיבה בליונוויל אבל לא היו זמינים לעריכה אצלנו: מספר מסמך (document_number), אימייל נמען (destination_email), וכפולה (is_roundtrip). שלושתם נוספו במלואם: (1) ל-Zod של PATCH /api/shipments/[id]; (2) ל-LIONWHEEL_TASK_FIELDS / LIONWHEEL_VISIT_FIELDS עם תוויות עבריות; (3) ל-Shipment TS type; (4) ל-UI: destinationEmail כשורת EditableField ב-DestinationCard ליד 'הערת יעד'; documentNumber כשורת EditableField בכרטיס פרטי המשלוח ליד 'הערה ארגונית'; isRoundtrip כ-Badge עם DropdownMenu (כן/לא) ליד 'השאר ליד הדלת'. בנוסף נוספה עמודה חדשה ל-DB: shipment.document_number VARCHAR(255) — לא הייתה קיימת קודם (השדה רק נשלח לליונוויל ביצירה ולא נשמר אצלנו).
v01.65.001חדשcrm/leadsלידים — תבניות WhatsApp מהשורה
כפתור ה-WhatsApp בעמודת הטלפון הפך ל-Dropdown: 'פתח צ׳אט ריק' + רשימה של כל תבניות ה-WhatsApp הפעילות מההגדרות.
פרטים נוספים ↓הסתר ↑
כפתור ה-WhatsApp בעמודת הטלפון הפך ל-Dropdown: 'פתח צ׳אט ריק' + רשימה של כל תבניות ה-WhatsApp הפעילות מההגדרות. בחירת תבנית פותחת wa.me?text=... עם הטקסט מולא אוטומטית והמשתנים {{name}}, {{businessName}}, {{contactName}}, {{city}}, {{agentName}}, {{phone}}, {{email}} מוחלפים בערכי הליד. נוסף endpoint חדש GET /api/leads/whatsapp-templates עם הרשאת LEADS_VIEW (להבדיל מ-/api/messages/templates שדורש SETTINGS_VIEW), מחזיר רק את גוף התבניות הפעילות בלי המטא-מידע של Meta Cloud API. אם אין תבניות מוגדרות — הכפתור פותח צ׳אט ריק כברירת מחדל (התנהגות זהה לקודם). שלב 3.2 הושלם — שלב 3 (Power) הושלם.
v01.65.000חדשcrm/leadsminorלידים — Bulk Actions (שינוי סטטוס/עדיפות/סוכן/מחיקה לרב-בחירה)
טבלת /leads קיבלה שורת בחירה ו-4 פעולות המוניות: שינוי סטטוס, שינוי עדיפות, הקצאת סוכן (לא לסוכנים), ומחיקה.
פרטים נוספים ↓הסתר ↑
טבלת /leads קיבלה שורת בחירה ו-4 פעולות המוניות: שינוי סטטוס, שינוי עדיפות, הקצאת סוכן (לא לסוכנים), ומחיקה. בחירה של 1+ שורות מציגה Bottom Dock עם הפעולות; לחיצה פותחת LeadsBulkActionDialog עם Select מתאים. כל פעולה רצה POST /api/leads/bulk עם תקרה של 500 לידים פר-בקשה. בעת שינוי סטטוס המוני נוצרת LeadActivity של STATUS_CHANGE אוטומטית לכל ליד שסטטוסו השתנה. הרשאות: סוכן רואה ויכול לעדכן רק לידים שלו, מחיקה דורשת LEADS_DELETE, הקצאת סוכן זמינה רק למנהלים. אחרי כל פעולה הטבלה + KPI + filter-options מתרעננים. שלב 3.1 הושלם.
- 4 פעולות המוניות: שינוי סטטוס, עדיפות, סוכן, מחיקה
- Endpoint יחיד /api/leads/bulk עם action+ids+value
- STATUS_CHANGE activity נוצר אוטומטית גם בעדכון המוני
- סוכן יכול לעדכן רק לידים שלו, הקצאת סוכן זמינה רק למנהלים
- תקרה של 500 לידים פר-בקשה
v01.64.001חדשcrm/leadsלידים — 5 כרטיסי KPI מעל הטבלה
נוספה שורת כרטיסים מעל טבלת /leads עם 5 מדדים: פעילים (סטטוסים שאינם CONVERTED/CLOSED_*), חדשים השבוע, מעקבים היום, באיחור (מעקב עבר + עדיין פעיל), והמרות החודש.
פרטים נוספים ↓הסתר ↑
נוספה שורת כרטיסים מעל טבלת /leads עם 5 מדדים: פעילים (סטטוסים שאינם CONVERTED/CLOSED_*), חדשים השבוע, מעקבים היום, באיחור (מעקב עבר + עדיין פעיל), והמרות החודש. 3 הכרטיסים האחרונים קליקיים — לחיצה על 'מעקבים היום' או 'באיחור' מחילה את פילטר 'מעקב הבא' המתאים; לחיצה על 'המרות החודש' מחילה statusFilter=CONVERTED. לחיצה שנייה מאפסת. הסטטיסטיקות נטענות מ-GET /api/leads/stats ומתרעננות אחרי יצירה/עריכה/מחיקת ליד. הסטטיסטיקות פר-טננט, וסוכן רואה רק את שלו. שלב 2.2 הושלם — שלב 2 (Visibility) הושלם. נדרש גם עדכון StatusFilter type שיכלול את כל 8 סטטוסי ה-enum (בעבר היו חסרים QUOTED/CONTRACT_*/CONVERTED).
v01.64.000חדשcrm/leadsminorלידים — סינון מתקדם (עדיפות, סוג הפצה, גוביינות, עיר, תגיות, מעקב הבא)
ה-FiltersPopover של דף /leads קיבל 6 קטגוריות סינון חדשות מעבר ל-status+agent הקיימים: עדיפות (HOT/WARM/COLD), סוג הפצה (4 הסוגים), גוביינות (כן/לא), עיר (multi-select מתוך הערים שיש בלידים בפועל), תגיות (multi-select מת…
פרטים נוספים ↓הסתר ↑
ה-FiltersPopover של דף /leads קיבל 6 קטגוריות סינון חדשות מעבר ל-status+agent הקיימים: עדיפות (HOT/WARM/COLD), סוג הפצה (4 הסוגים), גוביינות (כן/לא), עיר (multi-select מתוך הערים שיש בלידים בפועל), תגיות (multi-select מתוך כלל התגיות שיש), ו-'מעקב הבא' עם 4 קיצורים שימושיים: באיחור, היום, השבוע, ללא מעקב מוגדר. GET /api/leads תומך בפרמטרים החדשים: priority, distributionType, hasCod, city (חוזר), tag (חוזר), followUpStatus. נוסף endpoint חדש GET /api/leads/filter-options שמחזיר את רשימת הערים והתגיות הקיימות פר-טננט (כדי לאכלס את ה-Select). כל הסינונים פר-טננט וקובע אם מסנן לפי הרשאה (סוכן רואה רק שלו). שלב 2.1 מתוך roadmap CRM מלא ללידים.
- 6 קטגוריות סינון חדשות, חלקן multi-select
- סינון 'מעקב הבא' עם 4 קיצורים: באיחור, היום, השבוע, ללא
- Endpoint חדש /api/leads/filter-options שמאכלס דינמית עיר+תגיות
- סינון עיר ותגיות מתוך הערכים הקיימים בלידים — אין הצעות פנטום
- החיפוש החופשי הקיים (שם/עסק/עיר/טלפון/אימייל) משחק יחד עם הסינונים
v01.63.002חדשplatform/adminAdmin — בקשות שמות חלופיים: בחירה מרובה + אישור/דחייה bulk
בעמוד /admin/alias-requests נוספה עמודת checkbox (פעילה רק בטאב 'ממתינות') עם בחירת הכל בכותרת.
פרטים נוספים ↓הסתר ↑
בעמוד /admin/alias-requests נוספה עמודת checkbox (פעילה רק בטאב 'ממתינות') עם בחירת הכל בכותרת. כשמסומנת לפחות שורה אחת מופיע סרגל פעולות עם 'אשר את הנבחרים' / 'דחה את הנבחרים' / 'ביטול בחירה'. דיאלוג הסקירה נפתח במצב bulk עם שדה הערה אחד שמוחל על כל הנבחרים. ההפעלה רצה במקביל (Promise.allSettled), ה-toast מסכם הצליחו/נכשלו. הבחירה מתאפסת אוטומטית בהחלפת סטטוס. APPROVED/REJECTED נשארים read-only.
v01.63.001חדשcrm/leadsלידים — זיהוי כפילויות בעת יצירה
POST /api/leads בודק כפילויות פר-טננט לפי טלפון (התאמה מדויקת), אימייל ושם עסק (case-insensitive).
פרטים נוספים ↓הסתר ↑
POST /api/leads בודק כפילויות פר-טננט לפי טלפון (התאמה מדויקת), אימייל ושם עסק (case-insensitive). אם נמצאו עד 5 מועמדים — מחזיר 409 עם רשימת המועמדים (id/שם/עסק/טלפון/אימייל/עיר/סטטוס/תאריך יצירה/סוכן). הלקוח מציג דיאלוג DuplicateLeadDialog: 'נמצאו לידים דומים' עם כפתור 'פתח קיים' פר-מועמד שפותח את כרטיס הליד הקיים, ושני כפתורים תחתונים: 'צור ליד חדש בכל זאת' (שולח שוב עם confirmDuplicate=true) או 'ביטול' (חוזר לטופס). מונע יצירת לידים כפולים ביד או בייבוא עתידי. שלב 1.3 מתוך roadmap CRM מלא ללידים.
v01.62.002שיפורcrm/leadsלידים — עריכת סטטוס מהירה ישירות בשורה
ה-Badge של סטטוס בטבלת הלידים הפך לכפתור עם dropdown — לחיצה פותחת תפריט עם כל 8 הסטטוסים ובחירה מעדכנת את הליד בלי לפתוח את ה-form.
פרטים נוספים ↓הסתר ↑
ה-Badge של סטטוס בטבלת הלידים הפך לכפתור עם dropdown — לחיצה פותחת תפריט עם כל 8 הסטטוסים ובחירה מעדכנת את הליד בלי לפתוח את ה-form. עדכון אופטימי + rollback אם ה-PATCH נכשל + toast. כפתור ה-dropdown מוצג רק למשתמשים עם הרשאת LEADS_EDIT; לאחרים מוצג Badge רגיל. ה-PATCH endpoint כבר יוצר LeadActivity מסוג STATUS_CHANGE אוטומטית, כך שכל שינוי נשמר בטיימליין. רכיב חדש LeadStatusBadge מומלץ לשימוש חוזר. שלב 1.1 מתוך roadmap של 'CRM ללידים בלי מערכת חיצונית'.
v01.62.001שיפורcrm/pdfPDF הצעה / הסכם — תיקוני רינדור עברית ועיצוב סקציות
תיקון רינדור: react-pdf השמיט אותיות עברית סמוכות לרווח אסקי (תוספת ג…, חבילה נ…).
פרטים נוספים ↓הסתר ↑
תיקון רינדור: react-pdf השמיט אותיות עברית סמוכות לרווח אסקי (תוספת ג…, חבילה נ…). fixHe עודכן להחליף רווח בין שתי אותיות עבריות ב-NBSP — שומר את הרווח מפני re-ordering של מנוע הביידי בלי לפגוע במעבר השורות בטקסט מעורב. תווית 'משלוח כפול (החלפה)' שונתה ל'משלוח כפול והחלפה' (סוגריים בהקשר RTL גרמו ל-glyphs ליפול). עיצובית: כל סקציה (פרטי הלקוח / תעריפי בסיס / חבילות נוספות / הערות / תנאי שירות) קיבלה אותו טיפול של ה-info card — רקע SURFACE_50, פינות מעוגלות, ובורדר ימני בצבע מותג. שורת ה-info card עברה ל-RTL נכון (שם הנמען מימין, תוקף ההצעה משמאל). פונט עמודת הסכום במחירון עבר מ-700 ל-500 כך שלא 'צועק' מול שאר הטקסט.
v01.62.000חדשcrm/pricingminorמחירון — טירים מאוחדים לחבילות נוספות (החליפו 2 שדות נפרדים)
השדות 'חבילה נוספת במסירה' ו'חבילה נוספת באיסוף' אוחדו למערכת טירים אחת שחלה הן על מסירה והן על איסוף.
פרטים נוספים ↓הסתר ↑
השדות 'חבילה נוספת במסירה' ו'חבילה נוספת באיסוף' אוחדו למערכת טירים אחת שחלה הן על מסירה והן על איסוף. החבילה הראשונה תמיד בתעריף הבסיסי של האופרציה; מהשניה והלאה ניתן להגדיר טירים — כל טיר חל מ-fromIndex (2, 3, 4...) ואילך, עם בחירה בין 'כמו חבילה ראשונה' או 'מחיר אחר'. כך מתאפשרים שני דפוסים נפוצים שלא ניתן היה לבטא קודם: הנחה רק לחבילה השניה (חבילה 3 חוזרת לבסיס), או הנחה רציפה מהשניה והלאה. הטירים מסתנכרנים בין הצעת מחיר → הסכם → פרופיל מחירון של הלקוח ב-conversion ובעריכה ידנית, וגם ב-PDF, בעמוד ההצעה הציבורי, ובדיאלוג עריכת מחירון לקוח. השדות הישנים נשמרים ב-DB ל-backward compat אבל לא מוצגים בטפסים חדשים.
- מודל אחד לתעריפי חבילות נוספות במקום שני שדות נפרדים למסירה ולאיסוף
- טיר 'כמו חבילה ראשונה' או 'מחיר אחר' עם fromIndex (2, 3, 4...) — מאפשר 'הנחה רק על השניה' או 'הנחה רציפה'
- סינכרון מלא: הצעת מחיר → הסכם → פרופיל מחירון לקוח (יצירה אוטומטית ב-Convert + עריכה ידנית בדיאלוג)
- סקציית 'תעריפים נוספים' בדיאלוג מחירון לקוח: 'איסוף מבית העסק' ו'משלוח כפול / החלפה' זמינים גם לעריכה ידנית
- תצוגת טירים בעמודי הצעה / הסכם / עמוד ציבורי /q/[token] + ב-PDFs של ההצעה וההסכם
v01.61.000חדשcrm/leadsminorלידים — שדות פרופיל לקוח מורחב (עסק, עיר, סוג הפצה, מוצר, כמויות, גוביינות)
הרחבת ה-Lead model בשבעה שדות חדשים שמאפשרים לתעד את פרופיל המשלוחים של ליד מהרגע הראשון, ולא רק בשלב ההמרה ללקוח.
פרטים נוספים ↓הסתר ↑
הרחבת ה-Lead model בשבעה שדות חדשים שמאפשרים לתעד את פרופיל המשלוחים של ליד מהרגע הראשון, ולא רק בשלב ההמרה ללקוח. במקום השדה 'סכום צפוי' (expectedAmount) מופיע עכשיו 'כמות חודשית צפויה' (monthlyExpectedQuantity) — שינוי תפיסה ממדידת ערך כספי למדידת נפח. השדה הישן הוסר משכבת ה-app (העמודה expected_amount נשמרה ב-DB לתאימות לאחור). שדות חדשים: businessName (שם העסק), city (עיר), productType (סוג מוצר), weightRange (טווח משקלים), sizeRange (טווח גדלים), hasCod (האם יש גוביינות, boolean), distributionType (enum: ONGOING/ONE_TIME_PROJECT/OCCASIONAL_PROJECTS/SHABBAT_LEAFLETS). LeadForm קיבל סקציה חדשה 'פרופיל משלוחים' עם Switch ל-hasCod ו-Select ל-distributionType. LeadDetails מציג את כל השדות החדשים בסקציה נפרדת. טבלת /leads קיבלה 9 עמודות חדשות וסידור ברירת מחדל הגיוני: שם העסק → איש קשר → עיר → טלפון → אימייל → מקור → סוכן → סטטוס → תאריך קליטה → מעקב הבא → פעילויות → סוג הפצה → סוג מוצר → כמות חודשית → טווח משקלים → טווח גדלים → גוביינות. החיפוש הורחב לכלול businessName + city. ה-webhook /api/leads/webhook מקבל גם את השדות החדשים.
- שם העסק כעמודה ראשית (במקום שם איש קשר)
- כמות חודשית צפויה במקום סכום צפוי (משלוחים, לא ₪)
- סוג הפצה כ-enum: הפצה שוטפת / פרוייקט חד פעמי / פרוייקטים מזדמנים / עלוני שבת
- Boolean גוביינות (כן/לא) עם תצוגה כ-Badge בטבלה
- 9 עמודות חדשות בטבלה, סידור ברירת מחדל הגיוני, ניתן לשינוי על-ידי המשתמש
- חיפוש חופשי כולל גם שם העסק ועיר
v01.60.005שיפורcrm/leadsטבלת לידים — כפתורי חיוג / WhatsApp / מייל בכל שורה
האייקונים הדקורטיביים שהיו צמודים לטלפון ולמייל בטבלה הוחלפו בכפתורי פעולה אמיתיים.
פרטים נוספים ↓הסתר ↑
האייקונים הדקורטיביים שהיו צמודים לטלפון ולמייל בטבלה הוחלפו בכפתורי פעולה אמיתיים. בעמודת הטלפון: כפתור 'חיוג' (tel:{phone}) + כפתור WhatsApp (https://wa.me/{intl} בצבע emerald) שפותח שיחה רגילה בוואטסאפ של המשתמש מול הלקוח (לא צ'אט פנימי). מספרי טלפון ישראליים שמתחילים ב-0 מומרים אוטומטית ל-972. בעמודת המייל: כפתור 'שליחת מייל' (mailto:{email}) שפותח את לקוח המייל המוגדר. כל הכפתורים stopPropagation כדי לא לפתוח את כרטיס הליד בלחיצה. הכפתורים ממוקמים בצד הימני (start) של התא — כך הם מיושרים אנכית בין השורות ולא 'רוקדים' לפי אורך הטקסט.
v01.60.004תיקוןcrm/leadsלידים — תוויות עבריות לכל הסטטוסים
הסטטוסים QUOTED / CONTRACT_SENT / CONTRACT_SIGNED / CONVERTED (שנוספו עם CRM funnel) הופיעו באנגלית בטבלת הלידים, בפילטר הסטטוסים, בטופס עריכה, בכרטיס פרטי ליד וב-dashboard של סוכן — כי לא הוגדרו עבורם תוויות עבריות במפת…
פרטים נוספים ↓הסתר ↑
הסטטוסים QUOTED / CONTRACT_SENT / CONTRACT_SIGNED / CONVERTED (שנוספו עם CRM funnel) הופיעו באנגלית בטבלת הלידים, בפילטר הסטטוסים, בטופס עריכה, בכרטיס פרטי ליד וב-dashboard של סוכן — כי לא הוגדרו עבורם תוויות עבריות במפת LEAD_STATUS_LABELS. אוחדו 5 העתקים מקומיים של LEAD_STATUS_LABELS / LEAD_STATUS_COLORS למודול משותף יחיד (apps/web/app/(site)/leads/lead-status.ts) עם תוויות וצבעים לכל 8 סטטוסי ה-enum: 'הצעה נשלחה' / 'הסכם נשלח' / 'הסכם נחתם' / 'הומר ללקוח'.
v01.60.003תיקוןdelivery-times/settlement-name-alertsהתראות שמות לא מזוהים — שורה נעלמת מהטבלה אחרי שטננט הגיש בקשה
המשך מ-Phase G: כשטננט לחץ 'קישור לישוב' בטאב ההתראות, הבקשה הוגשה ל-/admin/alias-requests תקין, אבל ההתראה עצמה נשארה ב-status PENDING (כי רק admin יכול לסמן LINKED) — ולכן השורה לא נעלמה מהטבלה והטננט חשב שכלום לא קרה.
פרטים נוספים ↓הסתר ↑
המשך מ-Phase G: כשטננט לחץ 'קישור לישוב' בטאב ההתראות, הבקשה הוגשה ל-/admin/alias-requests תקין, אבל ההתראה עצמה נשארה ב-status PENDING (כי רק admin יכול לסמן LINKED) — ולכן השורה לא נעלמה מהטבלה והטננט חשב שכלום לא קרה. GET /api/delivery-times/settlement-name-alerts מסנן עכשיו החוצה כל alert שיש לו SettlementAliasRequest פעיל מאותו טננט. אם ה-admin ידחה את הבקשה, ההתראה תחזור להופיע. הסינון פר-טננט: טננט שיצר בקשה לא רואה את ה-alert, אבל טננטים אחרים כן.
v01.60.002שיפורcrm/leadsליצוב לידים — עמודת 'תאריך קליטה'
נוספה עמודה 'תאריך קליטה' לטבלת הלידים ב-/leads, ממופה לשדה createdAt שכבר היה מוחזר מה-API.
פרטים נוספים ↓הסתר ↑
נוספה עמודה 'תאריך קליטה' לטבלת הלידים ב-/leads, ממופה לשדה createdAt שכבר היה מוחזר מה-API. ממוקמת לפני 'מעקב הבא' כך ששני שדות התאריך מופיעים זה לצד זה. ניתן למיין לפי העמודה.
v01.60.001שיפורshipments/detailדף משלוח — כפתור קישורים להעתקה + טולטיפ על כפתור ההדפסה
בכרטיסיית 'זיהוי וסטטוס' (תצוגת desktop) נוסף כפתור חדש עם אייקון של קישור שפותח רשימה דומה לכפתור ההדפסה: 'לינק מעקב ללקוח' (/tracking/{public_id}) ו'לינק לעדכון פרטים' (/validate/{public_id}).
פרטים נוספים ↓הסתר ↑
בכרטיסיית 'זיהוי וסטטוס' (תצוגת desktop) נוסף כפתור חדש עם אייקון של קישור שפותח רשימה דומה לכפתור ההדפסה: 'לינק מעקב ללקוח' (/tracking/{public_id}) ו'לינק לעדכון פרטים' (/validate/{public_id}). לחיצה על כל פריט מעתיקה את ה-URL המלא ללוח עם toast. בנוסף, נוסף טולטיפ לכפתור ההדפסה ('הדפסה ושיתוף') — עד עכשיו היה היחיד באזור ללא טולטיפ בניגוד לשאר הכפתורים. שני הפריטים disabled כש-shipment.public_id חסר. נוסף שדה public_id ל-Shipment type ב-shipment-detail-types.ts.
v01.60.000חדשcrm/quotes,crm/contracts,crm/pricingminorהצעות מחיר: שליחה חוזרת, תוקף ברירת מחדל 14 ימים, 2 תעריפים חדשים, וכותרת משפטית
אוסף שינויים תוצרים ממשוב משתמש על דף הצעת מחיר ו-PDF: **(1) Resend tracking** — POST /api/quotes/[id]/send תומך עכשיו ב-resend מ-status SENT/VIEWED (לא רק DRAFT).
פרטים נוספים ↓הסתר ↑
אוסף שינויים תוצרים ממשוב משתמש על דף הצעת מחיר ו-PDF: **(1) Resend tracking** — POST /api/quotes/[id]/send תומך עכשיו ב-resend מ-status SENT/VIEWED (לא רק DRAFT). שדות חדשים ב-Quote: lastSentAt + sendCount. ב-resend ה-PDF והטוקן הקיימים נשמרים — רק המייל נשלח שוב. סטטוס לא משתנה (SENT נשאר SENT). באתר /quotes/[id]: כפתור 'שליחה חוזרת' מופיע ב-status=SENT/VIEWED עם confirm מעוצב; ב-timeline 'נשלחה' מציג 'X שליחות, אחרונה בתאריך Y' כש-sendCount>1. **(2) הצג כלקוח** — 'פתח כלקוח' → 'הצג כלקוח' (Eye icon במקום ExternalLink) ב-/quotes/[id] וב-/contracts/[id]. **(3) הסרת סיכום מיותר** — השורה 'סך X שירותים · סכום סה״כ' הוסרה מ-Rates card. **(4) תוקף ברירת מחדל** — QuoteForm.defaultValidUntil() מחזיר היום+14 ימים. **(5) Required rate fields** — כל שדות התעריפים חובה (גם 0 תקף, refine עם regex). QuoteForm + ContractForm קיבלו ולידציה חדשה. **(6) Legal disclaimer** — 'הצעה זו אינה מהווה התחייבות חוזית מצד הצדדים. הסכם מחייב טעון חתימה נפרדת.' מוצג בדף /quotes/[id] (כרטיס amber), בדף הציבורי /q/[token] (פס amber לפני footer), וב-PDF (View עם background amber-100 + border-right). **(7) שדות תעריף חדשים + 'החזרה' הוסר** — נוספו businessPickupRate ('איסוף מבית העסק') ו-roundtripRate ('משלוח כפול — החלפה'). הוסר returnRate מהטפסים החדשים (נשאר בסכמה לתאימות לאחור). מיגרציה הוסיפה business_pickup_rate + roundtrip_rate ל-customer_pricing_profile. RATE_LABELS עודכן ב-7 מקומות: QuoteForm, ContractForm, /quotes/[id], /contracts/[id], /q/[token] QuoteClient, render-quote-pdf, render-contract-pdf. Convert API מעדכן את שני הרייטים החדשים ב-profile. backfill: רשומות sent קיימות קיבלו sendCount=1, lastSentAt=sentAt.
- Resend מ-SENT/VIEWED עם sendCount + lastSentAt + תצוגה ב-timeline
- 'פתח כלקוח' → 'הצג כלקוח' (Eye icon)
- כל שדות התעריף בטופס = חובה; ברירת מחדל 0
- תוקף ברירת מחדל = היום + 14 ימים
- Legal disclaimer מופיע בדף, ב-/q/[token] וב-PDF
- 2 שדות תעריף חדשים: איסוף מבית העסק + משלוח כפול (החלפה); 'החזרה' הוסר מהטפסים
- הסרת סיכום 'X שירותים · סכום סה״כ' מהדף
v01.59.018שיפורsorting-errorsהתראת טעות מיון — שמות שדות ברורים יותר
בהתראת טעות מיון (SortingErrorAlertListener) שונו שני לייבלים כך שיהיה ברור שמדובר באזורי הפצה ולא באזורים גנריים: 'אזור שובץ' → 'אזור הפצה מאומת', ו'אזורים מורשים' → 'אזורי הפצה מורשים לשליח'.
v01.59.017תיקוןcrm/quotes,crm/contractsPDF הצעת מחיר/הסכם — 7 תיקוני עיצוב
תיקוני עיצוב מקבילים ב-render-quote-pdf ו-render-contract-pdf לפי משוב משתמש על ה-PDF הקודם.
פרטים נוספים ↓הסתר ↑
תיקוני עיצוב מקבילים ב-render-quote-pdf ו-render-contract-pdf לפי משוב משתמש על ה-PDF הקודם. **(1) Info card RTL נשבר** — האקסנט (border) היה בשמאל ובלוקי התוכן אובסטר alignItems=flex-start, מה שייצר 'תוקף ההצעה' בצד שמאל ו'מיועדת ל' בצד ימין הפוך מהציפייה. הוחלף ל-borderRightWidth + alignItems=flex-end → ה-accent בצד ימין (תחילת קריאה ב-RTL) ובלוקי המידע מיושרים ימינה. **(2) 'מיועדת ל-' → 'עבור'** — שמא ברורה ומקובלת יותר. **(3) NBSP נטוש לטובת RLM helper** — ה-NBSP הציר ב-'תוספת גוביינא' לקדם רחב מדי ודחף את הטקסט. הוחלף ב-fixHe(s) שמכניס U+200F (RLM mark) אחרי כל ASCII space — בלתי-נראה, רוחב 0, אבל גורם ל-bidi engine של react-pdf להתחיל RTL run חדש כך שהרווח לא נדחס. הוחל על כל ה-RATE_LABELS, KIND_LABELS, שמות נמענים, הערות, ותנאי שירות שמסופקים על-ידי המשתמש — כך גם 'כל מיני תנאים' שהיה מתרנדר כ'כלמיני תנאים' עכשיו נשמר. **(4) טיפוגרפיה דקה יותר** — title 22→19, brand sender 16→15, sectionTitle 12→11, table 10→9.5, number מ-700 ל-400, infoValue מ-700 ל-400. **(5) Footer border 3px brand → 0.5px BORDER_200** — היה דומיננטי מדי. הרקע השתנה ל-#fafafa עדין. **(6) Footer overlapping content** — הוסר ה-hack של Text מוסתר ב-position:absolute left:-9999 שהיה להחזיק את משתנה onBrand. במקום זאת onBrand נמחק מ-QuoteDocument (נכון רק ב-buildStyles closure). הוסף flexShrink ל-footerLeft/Right למניעת התנגשות. **(7) page numbers footer text קוצר** מ-'עמוד X מתוך Y' ל-'X / Y' — חוסך מקום. הוחל באופן זהה על PDF ההסכם.
- info card: accent עבר מצד שמאל לצד ימין (RTL)
- fixHe helper מתקן את ה-bidi collapse של רווחים ב-RTL — גם בלייבלים וגם בטקסט משתמש
- 'מיועדת ל' → 'עבור'
- טיפוגרפיה דקה יותר (כותרות וטבלאות)
- Footer: border עדין + מניעת התנגשויות
v01.59.016שיפורcrm/quotes,crm/contracts,customersהחלפת window.confirm() המכוער ב-ConfirmDialog המעוצב של המערכת
השתמשתי בטעות ב-native window.confirm() ב-9 מקומות ב-CRM לפעולות הרגישות (שליחת הצעה, שליחת הסכם לחתימה, מחיקת טיוטות, ביטול השעיה).
פרטים נוספים ↓הסתר ↑
השתמשתי בטעות ב-native window.confirm() ב-9 מקומות ב-CRM לפעולות הרגישות (שליחת הצעה, שליחת הסכם לחתימה, מחיקת טיוטות, ביטול השעיה). הוחלף ב-useConfirm hook מ-@/components/ui/confirm-dialog (כבר בשימוש ב-leads, customers, ועוד) — Dialog מעוצב עם icon variant + iconBgClass לפי סוג הפעולה, כותרת ארוכה יותר עם הסבר השלכות, ושמות אישור ספציפיים ('שלח', 'מחק' וכו'). וריאנטים שנקבעו: info (כחול) ל-שליחה/ביטול השעיה; danger (אדום) למחיקות.
- 9 confirm() native → ConfirmDialog מעוצב
- מקומות: /quotes/[id]+page, /contracts/[id]+page, /customers/[id] (handleUnsuspend)
- icons + variants לפי סוג הפעולה (Send/Trash2/CheckCircle2)
v01.59.015שיפורניסיון לסנכרון סטטוס גוביינא חזרה לליונוויל — בוטל
ניסיתי להוסיף סנכרון של מעבר ל-IN_SAFE/RETURNED בגוביינא חזרה לליונוויל.
פרטים נוספים ↓הסתר ↑
ניסיתי להוסיף סנכרון של מעבר ל-IN_SAFE/RETURNED בגוביינא חזרה לליונוויל. לאחר מימוש ובדיקה אמפירית מקיפה (כ-15 גרסאות body על PUT /tasks/{id}/update, ניסיון endpoints דדיקטיביים /cods/*, /tasks/{id}/cod/*, /money_collects/*, ועדכון ברמת /visits/{id}) — הוכח שה-API הציבורי של ליונוויל פשוט לא מקבל כתיבת סטטוס COD בשום צורה. ליונוויל מחזירה 'Saved Successfully' לכל body שולחים לה אבל מתעלמת בשקט מכל שדה COD שלא היא תיעדה (מה שהתבטא ב-cod.status נשאר 'unreturned' לאחר כל ניסיון, מאומת מול היומן בליונוויל). התיעוד הציבורי שלהם (github.com/lionwheel/api) חושף 14 endpoints בלבד ואף אחד לא קשור לכתיבת COD. בוטל מימוש הקריאה — אבל הגילוי מתועד למקרה שבעתיד תקבל ליונוויל תמיכת API ל-COD writes.
v01.59.014חדשcrm/quotes,crm/contractsעריכת טיוטות הצעת מחיר/הסכם — כפתור 'ערוך' בדף הפרטים
אחרי יצירת טיוטה לא הייתה דרך מ-UI לערוך אותה — אפשר היה רק לשלוח או למחוק.
פרטים נוספים ↓הסתר ↑
אחרי יצירת טיוטה לא הייתה דרך מ-UI לערוך אותה — אפשר היה רק לשלוח או למחוק. נוסף כפתור 'ערוך' (outline + Pencil icon) בדף /quotes/[id] ו-/contracts/[id] שמופיע כש-status=DRAFT (וקיימת הרשאת QUOTES_EDIT / CONTRACTS_EDIT). הכפתור פותח את אותו QuoteForm / ContractForm במצב עריכה — עם title='עריכת ...', submitLabel='שמירת שינויים', וערכי כל השדות pre-filled. המקור (ליד/לקוח/הצעה) ננעל ומוצג כ-Badge בלי X — שינוי מקור דורש מחיקת הטיוטה ויצירה חדשה, להגנה על integrity. שדות שניתן לערוך: בהצעה — תוקף, תעריפי בסיס, הערות, תנאי שירות snapshot. בהסכם — תקופה (effectiveFrom/To), autoRenew, תעריפי בסיס, תנאי שירות. Submit קורא ל-PATCH /api/quotes/[id] או PATCH /api/contracts/[id] בהתאמה (ה-endpoints כבר היו קיימים מפאזה 1/2), לא ל-POST. אחרי שמירה — load() מרענן את הדף, toast 'השינויים נשמרו'.
- כפתור 'ערוך' ב-/quotes/[id] ו-/contracts/[id] כשהסטטוס DRAFT
- QuoteForm + ContractForm תומכים ב-edit mode עם pre-fill מלא
- מקור (ליד/לקוח/הצעה) ננעל בעריכה ומוצג כ-Badge
- Submit מפנה ל-PATCH במקום POST
v01.59.013תיקוןcrm/contractsתיקון: יצירת הסכם נכשלה ב-Prisma — חסר @map בשדה actorType
POST /api/contracts נכשל ב-500 עם 'Invalid prisma.contractEvent.create() invocation: The column actorType does not exist in the current database.'.
פרטים נוספים ↓הסתר ↑
POST /api/contracts נכשל ב-500 עם 'Invalid prisma.contractEvent.create() invocation: The column actorType does not exist in the current database.'. בטבלת contract_events הטור actor_type כן קיים (לפי SQL ה-migration), אבל ב-schema.prisma שכחתי להוסיף @map("actor_type") לשדה actorType — אז Prisma ניסה לכתוב לטור בשם actorType מילולי שאינו קיים. הוחל ה-@map. שאר 3 הטבלאות (quotes, contracts, contract_templates) נבדקו ידנית מול ה-DB — הכל תקין שם.
- schema.prisma ContractEvent.actorType: הוספת @map("actor_type")
- אומת ש-actor_type כן קיים ב-DB; הבאג היה רק ב-ORM mapping
v01.59.012תיקוןshipments/messages,messaging/triggersאקורדיון מסרונים פר-משלוח: שליחות אוטומטיות מופיעות נכון + פלטפורמה אמיתית
באג שהתגלה במשלוח 25089988: הלקוחה קיבלה 3 הודעות (Meta task_created, Green-API delivery_failed, וגם שליחה ידנית), אך טבלת המסרונים בדף המשלוח הציגה שורה אחת בלבד עם timestamp שגוי ופלטפורמה Meta כשהשליחה האחרונה הייתה G…
פרטים נוספים ↓הסתר ↑
באג שהתגלה במשלוח 25089988: הלקוחה קיבלה 3 הודעות (Meta task_created, Green-API delivery_failed, וגם שליחה ידנית), אך טבלת המסרונים בדף המשלוח הציגה שורה אחת בלבד עם timestamp שגוי ופלטפורמה Meta כשהשליחה האחרונה הייתה Green-API. שלוש סיבות נמצאו: (1) sendTriggerMessage כתב את ה-id שחזר מ-Green-API (hex format כמו 3EB0...) לעמודה meta_message_id ב-whatsapp_message — מאכלס אותה גם בערוצים שאינם Meta. (2) ה-update על שורת ה-Shipment קבע metaMessageId רק כשהשליחה הייתה Meta, אך לא ניקה אותו כשהשליחה החדשה הייתה Green-API — לכן הערך הישן מה-task_created נשאר ו-UI חשב שזה Meta. (3) הטריגרים האוטומטיים לא כתבו כלל ל-AuditLog (entityType=shipment) שזה המקור שהאקורדיון קורא — לכן רק השליחה האחרונה הופיעה (מהיחס היחיד על שורת ה-Shipment, שנדרס בכל ירייה). תיקון: metaMessageId נכתב רק לערוצי Meta; ל-Green-API נשמר null. כל שליחה אוטומטית כותבת עכשיו audit log משלה עם autoTrigger=true בנתונים — האקורדיון מזהה ומציג עם triggerType ופלטפורמה אמיתיים, ומדלג על שורת ה-Shipment fallback כשיש כבר audit log אוטומטי.
v01.59.011תיקוןpublic/layoutsתיקון: עמודים ציבוריים /validate, /tracking, /t הוצגו עם header של 'מועדי הפצה'
שלושה עמודים ציבוריים שלא קשורים ל-/delivery-check ישבו תחת אותו route group (public) שה-layout שלו מציג header 'מועדי הפצה / בדיקת זמני משלוח' ו-footer 'שיפינג אנד שופינג'.
פרטים נוספים ↓הסתר ↑
שלושה עמודים ציבוריים שלא קשורים ל-/delivery-check ישבו תחת אותו route group (public) שה-layout שלו מציג header 'מועדי הפצה / בדיקת זמני משלוח' ו-footer 'שיפינג אנד שופינג'. ה-layout הזה נוצר במקור עבור /delivery-check בלבד, אבל ירש לעמוד עדכון פרטי מסירה (/validate/[id]), עמוד מעקב משלוח (/tracking/[id]) ועמוד משימת שליח (/t/[token]) — כל אחד מהם יש לו shell עצמאי משלו (min-h-screen, dir=rtl, header card משלו). הועברו ל-route group חדש (shipment-public) עם layout מינימלי שמחזיר children בלבד. נשמר הניתוב הציבורי דרך middleware (publicRoutes ב-middleware.ts כבר רושם את ה-URLs לפי prefix — route groups בסוגריים לא משפיעים על URL). תיקון בעקבות אותו דפוס שתוקן ל-/q ו-/sign ב-01.59.005.
- /validate/[id], /tracking/[id], /t/[token] יוצאים מ-(public) ל-(shipment-public)
- /delivery-check נשאר ב-(public) עם header 'מועדי הפצה' — שם זה רלוונטי
- metadata title נקי: 'עדכון פרטי מסירה | Shipnest' במקום '... | בדיקת זמני משלוח'
v01.59.010שיפורui/terminologyטרמינולוגיה: "מספר משלוח" → "מזהה משלוח"
אחידות בטרמינולוגיה — בכל מקום בממשק שבו הוצג שדה הברקוד של משלוח עם הלייבל "מספר משלוח" / "מס׳ משלוח" הוחלף ל"מזהה משלוח".
פרטים נוספים ↓הסתר ↑
אחידות בטרמינולוגיה — בכל מקום בממשק שבו הוצג שדה הברקוד של משלוח עם הלייבל "מספר משלוח" / "מס׳ משלוח" הוחלף ל"מזהה משלוח". כולל: כותרות בעמוד פרטי משלוח (admin ו-portal), label בטופס פתיחת tickets, placeholder בחיפוש משלוחים (QuickAssign, ShipmentBarcodeInput, OffsetDetails), label של משתנה {{barcode}} בעורך טמפלייטים, הגדרת מדבקת godex-50x50, ו-8 תבניות ברירת המחדל של הודעות WhatsApp ב-CUSTOM_TEMPLATES. מופעים שמשמעותם "כמות משלוחים" (לדוגמה {{shipment_count}}) לא שונו. הערה: tenants שכבר שמרו טמפלייט WhatsApp מותאם אישית ב-DB לא מושפעים — רק tenants חדשים שטרם הגדירו יקבלו את הניסוח החדש.
v01.59.009תיקוןcrm/contractsContractForm: בורר הצעת מחיר לא מצא הצעות SENT/VIEWED
בורר הצעות המחיר בטופס יצירת הסכם סינן ב-fetch לפי status=ACCEPTED בלבד, אבל ה-status הזה דורש פעולת אישור מפורשת שלא קיימת היום ב-UX (אין כפתור 'אשר' בעמוד ההצעה — היא נשארת SENT אחרי שליחה, ועוברת ל-VIEWED אוטומטית כשה…
פרטים נוספים ↓הסתר ↑
בורר הצעות המחיר בטופס יצירת הסכם סינן ב-fetch לפי status=ACCEPTED בלבד, אבל ה-status הזה דורש פעולת אישור מפורשת שלא קיימת היום ב-UX (אין כפתור 'אשר' בעמוד ההצעה — היא נשארת SENT אחרי שליחה, ועוברת ל-VIEWED אוטומטית כשהלקוח פותח את הקישור). התוצאה: כל ההצעות נסתרו, גם בחיפוש לפי מספר הצעה. הוסר ה-status filter מה-fetch; הקליינט מסנן עכשיו לכל הצעה שאינה DRAFT — מאפשר ליצור הסכם מהצעות ב-SENT, VIEWED, או ACCEPTED. ACCEPTED עדיין יוצג כשהוא קיים, אבל לא נדרש.
- בורר הצעת מחיר ב-ContractForm מציג עכשיו הצעות SENT/VIEWED/ACCEPTED (לא רק ACCEPTED)
v01.59.008תיקוןshared/SearchComboboxתיקון: SearchCombobox לא נסגר בלחיצה על הלייבל מעל האינפוט
ב-QuoteForm ו-ContractForm ה-SearchCombobox עטוף ב-FormControl, שמעביר id לאינפוט הפנימי, וה-FormLabel מקושר אליו דרך htmlFor.
פרטים נוספים ↓הסתר ↑
ב-QuoteForm ו-ContractForm ה-SearchCombobox עטוף ב-FormControl, שמעביר id לאינפוט הפנימי, וה-FormLabel מקושר אליו דרך htmlFor. כשלוחצים על הלייבל הדפדפן מפוקס אוטומטית את האינפוט (התנהגות סטנדרטית של label), וה-onFocus של SearchCombobox היה פותח שוב את הדרופדאון מיד אחרי שה-mousedown סגר אותו. הדרופדאון נשאר פתוח מנקודת המבט של המשתמש. ב-/credits לא הייתה הבעיה כי שם SearchCombobox משמש בלי FormControl ולא היה htmlFor. הוסף ref-flag justClosedByOutsideRef שמסומן ל-true כשהדרופדאון נסגר מ-mousedown בחוץ, ב-onFocus בודקים את הדגל ומדלגים על setOpen(true) למשך 200ms. אחרי החלון הזה ההתנהגות חוזרת לרגילה (לחיצה ישירה על האינפוט פותחת כרגיל).
- לחיצה על FormLabel/FieldLabel מעל SearchCombobox סוגרת את הדרופדאון נכון
- fallback של 200ms — לא משפיע על שימושים קיימים ב-/credits
v01.59.007תיקוןintegrations/meta-cloud-api,whatsapp/templatesתבניות Meta: שם ייחודי בכל הגשה — עוקף צינון מחיקה של 30 יום
סאבמיט של תבנית עברית טריה לאישור Meta נכשל ב-502 עם 'אי אפשר להוסיף תוכן חדש בעברית בזמן מחיקת התוכן הקיים — נסה שוב בעוד 3 שבועות'.
פרטים נוספים ↓הסתר ↑
סאבמיט של תבנית עברית טריה לאישור Meta נכשל ב-502 עם 'אי אפשר להוסיף תוכן חדש בעברית בזמן מחיקת התוכן הקיים — נסה שוב בעוד 3 שבועות'. הסיבה: slugifyToMetaName ייצר עבור שם עברי טהור hash דטרמיניסטי (template_<hash>) — כל ריצה חוזרת לאחר מחיקה הוציאה בדיוק אותו שם, ו-Meta אוכפת צינון של 30 יום על שם של תבנית שנמחקה. הוסף uniqueSuffix אופציונלי ל-slugifyToMetaName; הדיאלוג מייצר ערך טרי בכל פתיחה (Date.now().toString(36)) ושולח אותו ל-server מפורש כ-metaName; ה-route מוסיף defense-in-depth — אם metaName לא נשלח, מצרף סיומת זמן משלו. תוצאה: מחיקה של תבנית כדי לשפר ניסוח והגשתה מיד מחדש פשוט עובדת.
v01.59.006שיפורcrm/quotes,crm/contractsQuoteForm + ContractForm: בוררי ליד/לקוח/הצעת מחיר עם חיפוש (SearchCombobox)
טופס יצירת הצעת מחיר וטופס יצירת הסכם השתמשו ב-native Select dropdown לבחירת מקור (ליד / לקוח / הצעת מחיר ב-ContractForm) — בלי חיפוש, סקרול ארוך, חוויה גרועה כשיש עשרות לקוחות.
פרטים נוספים ↓הסתר ↑
טופס יצירת הצעת מחיר וטופס יצירת הסכם השתמשו ב-native Select dropdown לבחירת מקור (ליד / לקוח / הצעת מחיר ב-ContractForm) — בלי חיפוש, סקרול ארוך, חוויה גרועה כשיש עשרות לקוחות. הוחלף ב-SearchCombobox המשותף מ-@/components/shared/SearchCombobox (אותו רכיב ש-CreditNoteDialog משתמש בו ב-/credits): input חיפוש עם השלמה אוטומטית בזמן הקלדה, ניווט בחיצים, Enter לבחירה, Esc לסגירה, הצגת אייקון ותווית משני (אימייל/טלפון/סטטוס). כשפריט נבחר — הוא מוצג כ-Badge עם X לניקוי הבחירה. הוחל על: QuoteForm (לידים + לקוחות), ContractForm (הצעות מחיר + לידים + לקוחות). אייקונים צבועים פר-סוג: לידים violet, לקוחות blue, הצעות amber.
- QuoteForm: בורר ליד/לקוח עם חיפוש בזמן הקלדה (במקום dropdown סטטי)
- ContractForm: בורר הצעת מחיר/ליד/לקוח עם חיפוש
- בחירה מוצגת כ-Badge עם כפתור X לניקוי
- navigation עם חיצים + Enter + Esc (פונקציונליות SearchCombobox קיים)
v01.59.005שיפורcrm/quotes,crm/contracts,publicCRM: עיצוב PDF, דף הצעת מחיר ועמודים ציבוריים — 4 תיקונים + שיפורים
**(1) באג: עמודים ציבוריים /q ו-/sign הוצגו עם header של 'מועדי הפצה'** — שני הנתיבים היו תחת route group (public) שהלייאאוט שלו ייעודי ל-/delivery-check עם header 'מועדי הפצה' ו-footer של שיפינג אנד שופינג.
פרטים נוספים ↓הסתר ↑
**(1) באג: עמודים ציבוריים /q ו-/sign הוצגו עם header של 'מועדי הפצה'** — שני הנתיבים היו תחת route group (public) שהלייאאוט שלו ייעודי ל-/delivery-check עם header 'מועדי הפצה' ו-footer של שיפינג אנד שופינג. הועברו ל-route group חדש (brand) ללא chrome משותף, מה שמאפשר לעמוד ה-/q לרנדר את העיצוב הממותג שלו עם לוגו הטננט במלוא הרוחב. ה-(brand)/layout.tsx מינימלי + robots: noindex (לא רוצים שגוגל יקטלג קישורי הצעה ספציפיים). **(2) באג: 'תוספתגוביינא' בלי רווח ב-PDF** — בקומבינציית RTL 'ת' אחרי 'ת' אחרי רווח לפני 'ג', אלגוריתם bidi של react-pdf דחס את המילים. הוחלף ASCII space ב-NBSP (\u00A0) — מרכז את הרווח ממאפסי-bidi. הוחל בשני קבצי PDF (quote + contract). **(3) שיפור: עיצוב PDF הצעת מחיר** — נכתב מחדש מבסיס. header band בצבע מותג עם לוגו (data URI) או ראשי תיבות, כותרת גדולה עם אקסנט תחתון, info card עם תוקף, טבלת תעריפים עם header צבעוני וזברה, מקטעים עם border-right בצבע מותג, footer bar קבוע עם מספור עמודים. ה-send endpoint מביא את tenant.logoUrl + brandColor, מוריד את הלוגו ל-data URI (כשל בשקט אם לא נגיש). **(4) שיפור: דף /quotes/[id]** — header sticky עם פעולות, 2-column responsive grid (מובייל=1), כרטיסי נמען + ציר זמן עם חיוויי סטטוס (icons + colors), טבלת תעריפים hover-able עם סיכום של מספר שירותים + סה״כ, skeleton state אמיתי עם המבנה של הדף (לא טקסט 'טוען...'), empty state עם כפתור חזרה לרשימה.
- /q ו-/sign יוצאים מ-(public) ל-(brand) — נפטרים מ-header 'מועדי הפצה'
- 'תוספת גוביינא' עם NBSP — לא נדחס יותר ב-PDF (גם quote וגם contract)
- PDF הצעת מחיר עם header band בצבע מותג + לוגו + טבלת תעריפים זברה + footer bar
- /quotes/[id] redesign: sticky header, 2-col grid responsive, timeline visual, skeleton אמיתי
v01.59.004תיקוןcrm/quotes,crm/contractsתיקון: 'Cannot read properties of undefined (reading slice)' בשליחת הצעת מחיר/הסכם
@react-pdf/renderer.toBuffer() למרות שמו מחזיר NodeJS.ReadableStream ולא Buffer ב-version 4.5.x.
פרטים נוספים ↓הסתר ↑
@react-pdf/renderer.toBuffer() למרות שמו מחזיר NodeJS.ReadableStream ולא Buffer ב-version 4.5.x. ב-render-quote-pdf.tsx ו-render-contract-pdf.tsx החזרנו את ה-stream casted כ-Buffer, ואחרי כן ב-send endpoints ניסינו לקרוא ל-pdfBuffer.buffer.slice(...) — מה שזרק 500 (stream אין שדה .buffer). הקוד של רינדור label PDF הקיים כבר טיפל בזה דרך streamToBuffer helper. הוסף את אותו helper לשני קבצי ה-CRM PDF, ושני הרינדורים מחזירים עכשיו Buffer אמיתי. השליחה של quotes ו-contracts לחתימה אמורה לעבוד שוב.
- streamToBuffer helper מוסף ל-render-quote-pdf + render-contract-pdf
- POST /api/quotes/[id]/send חוזר לעבוד (יצירת PDF + העלאה ל-Supabase + מייל)
v01.59.003שיפורadmin/tenantsטופס עריכת חברה — 4 טאבים + header/footer קבועים בקונבנציה של המערכת
הטופס ב-/admin/tenants התרחב משמעותית עם הזמן (warehouse, crm_quotes, crm_contracts, signature provider, brand, billing, external) וגלש למעלה ממסך אחד.
פרטים נוספים ↓הסתר ↑
הטופס ב-/admin/tenants התרחב משמעותית עם הזמן (warehouse, crm_quotes, crm_contracts, signature provider, brand, billing, external) וגלש למעלה ממסך אחד. סודר לפי הקונבנציה של דיאלוגים ארוכים ב-CLAUDE.md: DialogContent עם max-w-2xl + flex flex-col max-h-[90vh] + overflow-hidden; DialogHeader עם shrink-0 (קבוע למעלה); הטופס נכנס לתוך div עם flex-1 min-h-0 overflow-y-auto (גולל באמצע); DialogFooter שיצאה החוצה מ-form עם shrink-0 (קבוע למטה), והכפתור 'שמור' עם form='tenant-form' מקושר ל-id של הטופס בפנים. נוספו 4 טאבים: 'כללי' (שם, slug, תוכנית, סטטוס, טלפון, ח.פ.), 'חיוב ומיתוג' (לוגו, אימייל חיוב, כתובת חיוב, צבע מותג — לוגו עבר לכאן מתחת ל-header), 'מודולים' (מחסן, הצעות מחיר, הסכמים, ספק חתימה — disabled עד שמירה ראשונה כדי שלא יבלבל בחברה חדשה), ו-'אינטגרציה' (מערכת חיצונית, API URL). כל TabsContent עם forceMount + data-[state=inactive]:hidden כדי שערכי השדות יישמרו בכל הטאבים גם כשטאב אחר פעיל (חשוב ל-react-hook-form כדי לא לאבד values בעת מעבר טאבים).
- header/footer קבועים + אמצע גולל לפי קונבנציית CLAUDE.md לדיאלוגים ארוכים
- 4 טאבים: כללי / חיוב ומיתוג / מודולים / אינטגרציה
- טאב 'מודולים' disabled בחברה חדשה — יתאפשר אחרי השמירה הראשונה
- forceMount על TabsContent — ערכי שדות נשמרים בעת מעבר בין טאבים
v01.59.002תיקוןadmin/tenantsתיקון: toggles המודולים ב-/admin/tenants נראו 'כבויים' אחרי שמירה
GET /api/tenants (רשימה) לא כלל את שדה settings ב-select, ולכן בפתיחת דיאלוג העריכה ה-tenant.settings היה undefined, וה-toggles (warehouse, crm_quotes, crm_contracts) ו-בוחר ספק החתימה התאתחלו אוטומטית ל-false/'internal'.
פרטים נוספים ↓הסתר ↑
GET /api/tenants (רשימה) לא כלל את שדה settings ב-select, ולכן בפתיחת דיאלוג העריכה ה-tenant.settings היה undefined, וה-toggles (warehouse, crm_quotes, crm_contracts) ו-בוחר ספק החתימה התאתחלו אוטומטית ל-false/'internal'. השמירה כן עבדה — ה-PUT נכנס לבסיס הנתונים — אבל בכל פתיחה הבאה הטופס דרס את הערך כי הוא התחיל מטעות. הוסף settings: true ל-select של GET /api/tenants/route.ts, וכעת ה-toggles נטענים נכון בפתיחה והשמירה משתמרת בין רענונים.
- settings נכלל ב-GET /api/tenants list — toggles של מודולים מסונכרנים נכון בפתיחת דיאלוג עריכה
v01.59.001שיפורcrm/docsתיעוד ציבורי ב-/docs/crm — הזרימה המלאה של ה-CRM מליד עד לקוח פעיל
פאזה 6 של CRM Funnel — Hardening: דף תיעוד ציבורי מלא ב-/docs/crm שמסביר את כל הזרימה לטננטים ולקוחותיהם.
פרטים נוספים ↓הסתר ↑
פאזה 6 של CRM Funnel — Hardening: דף תיעוד ציבורי מלא ב-/docs/crm שמסביר את כל הזרימה לטננטים ולקוחותיהם. **תוכן הדף:** סקירה כללית עם diagram טקסטואלי של המשפך, הוראות הפעלת המודולים מ-/admin/tenants, תיאור 4 השלבים (ליד → הצעת מחיר → הסכם → לקוח פעיל) עם סטטוסים וזרימות חיים, פירוט מה הלקוח רואה בעמודי /q/[token] ו-/sign/[token], הסבר משפטי על תוקף החתימה האלקטרונית הרגילה לפי חוק תשס״א-2001 והגדרת רמת ההתאמה (סטנדרטית מסחרית; לא מאושרת), זרימת המרה ללקוח עם פירוט הטרנזקציה האטומית (Customer + Pricing + Lead.CONVERTED + portal invite), זרימת השעיה (status=SUSPENDED + isActive=false + חסימה ב-3 מסלולי יצירה), הסבר על audit log (ContractEvent immutable), ותכניות עתידיות (Green Invoice adapter, ContractTemplate CRUD, per-contract provider override, addendums). **Navigation:** הדף נוסף לסיידבר ב-apps/web/app/docs/_components/nav-data.ts תחת קבוצת 'ניהול תפעולי' (אחרי 'לקוחות'), עם blurb תיאורי. **טכני:** ה-page משתמש בכל ה-primitives הסטנדרטיים של docs — DocsArticle, Prose, H2/H3 עם anchors, Callout (info), Bullets/Steps, ו-C ל-inline code (כולל יישור LTR אוטומטי). updated label: '1 ביוני 2026'.
- דף תיעוד מלא ב-/docs/crm — סקירה, הפעלה, 4 שלבים, חתימה, השעיה, audit
- הסבר משפטי על תוקף חתימה אלקטרונית רגילה לפי חוק תשס״א-2001
- פירוט הזרימה הטכנית של ההמרה האטומית (Customer + Pricing + portal invite)
- נוסף לסיידבר של /docs תחת 'ניהול תפעולי' עם blurb תיאורי
v01.59.000חדשdelivery-times/alias-requestsminorשמות חלופיים — מסלול בקשה לאישור אדמין + עמוד בקרה /admin/alias-requests
טננטים לא יוצרים יותר ישירות שמות חלופיים גלובליים — במקום זה הבקשה שלהם נכנסת לתור אישור ב-/admin/alias-requests.
פרטים נוספים ↓הסתר ↑
טננטים לא יוצרים יותר ישירות שמות חלופיים גלובליים — במקום זה הבקשה שלהם נכנסת לתור אישור ב-/admin/alias-requests. רק PLATFORM_ADMIN / SYSTEM_DEVELOPER יכולים לאשר/לדחות. אדמינים שמשתמשים באותה ה-UI של הטננט מקבלים אישור אוטומטי בלי לעבור דרך תור (זיהוי role בצד שרת).
- טבלה חדשה SettlementAliasRequest עם status (PENDING/APPROVED/REJECTED), tenantId, sourceName, targetSettlementId, unknownAlertId, requestedBy/At, reviewedBy/At/Notes, resultingAliasId/resultingMergeId
- POST /api/delivery-times/alias-requests — מבצע אוטומטית אם המבצע admin (יוצר alias + audit + מעדכן alert); אחרת PENDING
- GET /api/delivery-times/alias-requests — טננט רואה רק את הבקשות שלו
- GET /api/admin/alias-requests — אדמין רואה את כל הבקשות מכל הטננטים
- POST /api/admin/alias-requests/[id]/approve — יוצר alias + audit + מעדכן alert + מסמן APPROVED, בטרנזקציה אחת
- POST /api/admin/alias-requests/[id]/reject — REJECTED עם reviewNotes
- עמוד חדש /admin/alias-requests עם פילטרי סטטוס, חיפוש, דיאלוגי אישור/דחיה
- /delivery-times/settlement-name-alerts (handleLinkConfirm / handleCreateAndLink / handleBulkLink) עבר ל-/alias-requests — toast מבדיל בין 'קושר' (admin) ל'בקשה הוגשה לאישור' (tenant)
v01.58.003שיפורdelivery-times/settlement-name-alertsמיזוגי שמות חלופיים — תיעוד מי ביצע + הצגת השם בטאב המיזוגים
POST /api/delivery-times/settlement-merges מושך עכשיו את userId מ-session ושומר אותו ב-mergedById של רשומת ה-audit (היה null עד עכשיו).
פרטים נוספים ↓הסתר ↑
POST /api/delivery-times/settlement-merges מושך עכשיו את userId מ-session ושומר אותו ב-mergedById של רשומת ה-audit (היה null עד עכשיו). GET ה-merges מצרף בנוסף את firstName/lastName/email של המשתמש דרך db.user.findMany; הטאב 'מיזוגים אחרונים' מציג ע״י [שם המשתמש] מתחת לתאריך. מיזוגים היסטוריים (לפני התיקון) ימשיכו להציג רק את התאריך — אין דרך לשחזר מי עשה אותם.
v01.58.002חדשdrivers/linkedשליחים מקושרים — drill-down תשלום פר סאב-שליח
בדוח התשלום החודשי של מנהל, ליד הפירוט פר סאב-שליח (לביקורת), כעת ניתן ללחוץ על שורת סאב כדי לפתוח מודל עם הפירוט המלא של מה שהמנהל חייב לסאב הזה — לפי מחירון הקישור (לא מחירון המנהל).
פרטים נוספים ↓הסתר ↑
בדוח התשלום החודשי של מנהל, ליד הפירוט פר סאב-שליח (לביקורת), כעת ניתן ללחוץ על שורת סאב כדי לפתוח מודל עם הפירוט המלא של מה שהמנהל חייב לסאב הזה — לפי מחירון הקישור (לא מחירון המנהל). זה הכלי שהמנהל צריך להתחשבן עם הסאב פיזית: רואה כמה משלוחים מכל סוג (מסירה / איסוף / איסוף עסקי / החזרה / חבילות נוספות), טבלת ביקורים מלאה (תאריך, ברקוד, לקוח, יעד, חבילות, בסיס+תוספת, סה״כ), וסכום סופי לתשלום. המודל משתמש ב-computeManagerSubPayout הקיים (פאזה 1 של פיצ'ר השליחים המקושרים) דרך endpoint חדש /api/drivers/[id]/sub-drivers/[linkId]/payout.
- Endpoint חדש GET /api/drivers/[id]/sub-drivers/[linkId]/payout?from&to — tenant-scoped, מחזיר lines+totals באותה צורה כמו ה-earnings הראשי.
- SubPayoutDialog חדש — strip של 5 סיכומים (מסירות/איסופים/עסקי/החזרות/חבילות נוספות) + grand total סגול 'סה״כ לתשלום לסאב' + טבלה גוללת של כל הביקורים.
- EarningsCard: שורות הסאב ב-'פירוט פר סאב-שליח' הופכות כפתורים שלחיצה עליהם פותחת את המודל. שורת המנהל-עצמו נשארת לא-לחיצה (לא רלוונטי — אין לו linkId).
- טוען subLinks פעם אחת פר view של מנהל; lookup מ-subDriverId ל-linkId נעשה ב-client, בלי שינוי לתגובת ה-earnings הראשי.
- 924/924 בדיקות עוברות. typecheck + lint נקיים.
v01.58.001שיפורcrm/contracts/providersSignatureProvider abstraction — תשתית לספקי חתימה מרובים + stub ל-חשבונית ירוקה
פאזה 5 של CRM Funnel — abstraction של ספקי חתימה דיגיטלית כדי לאפשר adapters עתידיים מבלי לשנות את ה-flow הקיים.
פרטים נוספים ↓הסתר ↑
פאזה 5 של CRM Funnel — abstraction של ספקי חתימה דיגיטלית כדי לאפשר adapters עתידיים מבלי לשנות את ה-flow הקיים. **תשתית חדשה:** lib/integrations/signature/types.ts (interface SignatureProvider עם code/label/ready/description/sendForSignature; SendForSignatureInput/Result types), lib/integrations/signature/internal/index.ts (InternalSignatureProvider — עוטף את הלוגיקה הקיימת: randomBytes token, /sign/[token] URL, sendContractSignatureRequestEmail; ready=true), lib/integrations/signature/green-invoice/index.ts (STUB — ready=false, sendForSignature זורק שגיאה עם הודעה ברורה; כולל תיעוד הצעדים הנדרשים להפעלה: בירור מול Green Invoice support האם יש POST endpoint ל-Proposals Plus עם דורש-חתימה, מימוש sendForSignature, webhook ב-/api/webhooks/green-invoice/[tenantId], ו-fetchSignedDocument), lib/integrations/signature/registry.ts (getSignatureProvider() עם fallback ל-internal אם code לא קיים או ready=false; listSignatureProviders() ל-UI). **Helper:** lib/crm/signature-provider.ts — getSignatureProviderForTenant(tenantId) קורא מ-Tenant.settings.crm.signatureProvider; extractSignatureProviderCode() כעטיפה defensive. **Refactor:** POST /api/contracts/[id]/send לא יוצר token+מייל ישירות יותר — אלא קורא ל-getSignatureProviderForTenant(tenantId) ומאציל ל-provider.sendForSignature() את היצירה. ה-Contract.publicAccessToken מאוכלס מ-result.externalId (ל-internal — token; ל-external — provider's ID). ה-Contract.signatureProviderCode נשמר עם הקוד שבחר הספק; חוזר ל-internal אוטומטית אם בחירת ספק לא תקפה. **UI:** dropdown 'ספק חתימה דיגיטלית' ב-/admin/tenants tenant-form (מתחת ל-toggles של crm). מציע 'חתימה פנימית (Shipnest)' ו-'חשבונית ירוקה (בקרוב)' — האחרון disabled. הבחירה נשמרת ב-tenant.settings.crm.signatureProvider, ננעל כש-crm_contracts כבוי. **Behavior preserved:** המשתמש לא מבחין בשינוי — הזרימה זהה בדיוק לפאזה 2 (internal עוטף את אותה הלוגיקה). הבדל היחיד — Contract.signatureProviderCode עכשיו מאוכלס מתוך הספק שבחר במקום קבוע 'internal'.
- interface SignatureProvider + 2 adapters (internal ready, green-invoice stub)
- registry עם fallback בטוח ל-internal אם code לא תקף או provider לא ready
- Tenant settings.crm.signatureProvider + UI dropdown ב-/admin/tenants
- POST /api/contracts/[id]/send refactor — מאציל ל-provider במקום inline
- Green Invoice adapter מתועד עם הצעדים הנדרשים להפעלה (API + webhook + fetch signed)
v01.58.000חדשcrm/customers/suspensionminorהשעיית לקוחות — חסימת יצירת משלוחים, באנר אדום בכרטיס הלקוח ומייל אוטומטי
פאזה 4 של CRM Funnel — מעבר מ-isActive בוליאני לסטטוס מלא.
פרטים נוספים ↓הסתר ↑
פאזה 4 של CRM Funnel — מעבר מ-isActive בוליאני לסטטוס מלא. **API חדש:** POST /api/customers/[id]/suspend (דורש body.reason ≥5 תווים, מעדכן status=SUSPENDED + isActive=false + suspendedAt + suspendedById + suspendReason, שולח מייל ללקוח עם הסיבה — fire-and-forget) ו-POST /api/customers/[id]/unsuspend (משחזר ל-ACTIVE/isActive=true, מנקה שדות ההשעיה). שני ה-endpoints דורשים CUSTOMERS_EDIT. **חסימת יצירת משלוחים:** lib/shipments/create-shipment.ts (שגיאת 403 ברורה: 'הלקוח X מושעה כעת — לא ניתן ליצור משלוחים חדשים'), apps/web/app/api/v1/shipments/route.ts (Public API מחזיר 403 על customer SUSPENDED/ARCHIVED). שני המסלולים מוגנים — admin /create + portal /create (משתמשים ב-createShipmentForTenant) ו-v1 הציבורי. /api/customers/for-shipment-form כבר מסנן isActive=true, אז דרופדאון בחירת לקוח לא יציג מושעים. **Email:** lib/email.ts sendCustomerSuspendedEmail — מייל אדום עם הסיבה בתיבה הילייטד + הסבר שמשלוחים קיימים ימשיכו להיות מטופלים. **UI:** SuspendCustomerDialog (Dialog פשוט עם textarea לסיבה + אופציה לדלג על המייל). באנר אדום בולט בראש /customers/[id] כש-status=SUSPENDED — Ban icon, הסיבה ב-whitespace-pre-wrap, מתי הושעה, וכפתור 'בטל השעיה'. בסרגל הפעולות של כרטיס הלקוח — כפתור 'השעה' (אדום) כש-ACTIVE, או 'בטל השעיה' (ירוק) כש-SUSPENDED. הbadge בכותרת הוחלף ב-3-state (מושעה אדום / בארכיון אפור / פעיל ירוק). העמודה 'סטטוס' ברשימת הלקוחות הוחלפה בלוגיקה דומה. **תזרים:** isSuspended/isArchived computed מ-customer.status; כש-isSuspended=true גם כפתור 'השעה' מוסתר וגם הבאנר מוצג. handleUnsuspend עם confirm + router.refresh. הסטטוס נוסף ל-Customer type ב-_types.ts (LEAD/ACTIVE/SUSPENDED/ARCHIVED + suspendedAt/suspendedById/suspendReason).
- POST /api/customers/[id]/suspend + /unsuspend — דורש reason ≥5 תווים + מייל אוטומטי
- חסימת יצירת משלוחים ב-3 מסלולים: admin /api/shipments/create, portal, וגם v1 הציבורי
- באנר אדום בולט בראש כרטיס לקוח מושעה — Ban icon + הסיבה + תאריך + כפתור ביטול השעיה
- מייל ללקוח עם הסיבה והסבר שמשלוחים קיימים ימשיכו (אופציה לדלג ב-checkbox)
- Badge ב-3 מצבים (פעיל/מושעה/בארכיון) בכותרת + ברשימת הלקוחות
- סינון for-shipment-form (isActive=true) מסיר אוטומטית לקוחות מושעים מהדרופדאון
v01.57.000חדשdelivery-times/settlement-name-alertsminorעמוד שמות לא מזוהים — איחוד ל-4 טאבים: התראות / שמות חלופיים / מיזוגים / דאשבורד
ה-/delivery-times/settlement-name-alerts הקיים מוחלף בעמוד מאוחד עם 4 טאבים שמתאחדים מקודם בכמה דיאלוגים ועמודים נפרדים.
פרטים נוספים ↓הסתר ↑
ה-/delivery-times/settlement-name-alerts הקיים מוחלף בעמוד מאוחד עם 4 טאבים שמתאחדים מקודם בכמה דיאלוגים ועמודים נפרדים. (1) טאב 'התראות' — תוכן ה-page הקיים עם search/bulk/link/ignore, חוץ ממסלול ה-link שעבר ל-/api/delivery-times/settlement-merges (מבוצע באטומיות במקום ב-2 קריאות, כותב audit ל-undo). (2) טאב חדש 'שמות חלופיים' — רשימה של כל ה-aliases עם חיפוש, עריכה inline (PATCH), מחיקה, badge לפי מקור. (3) טאב חדש 'מיזוגים אחרונים' — audit log של כל המיזוגים (handleMergeSettlement, performBulkLink, ו-link-from-alert) עם כפתור 'ביטול' לכל אחד. checkbox 'הצג גם מיזוגים שבוטלו'. (4) טאב חדש 'דאשבורד' — סטטיסטיקות: ישובים פעילים, סה״כ aliases, התראות ממתינות, מיזוגים השבוע, פילוח aliases לפי מקור עם bars יחסיים, ועוד.
- טבלה חדשה SettlementMergeAudit (settlement_merge_audit) ל-3 שדות מסלול-מיזוג: sourceName, sourceSettlementId, targetSettlementId, אנדקס ל-undoneAt
- API חדש: POST /api/delivery-times/settlement-merges שמבצע alias-create + soft-delete + audit-log בטרנזקציה אחת
- API חדש: POST /api/delivery-times/settlement-merges/[id]/undo שמשחזר את הישוב, מוחק את ה-alias, וב-PENDING את alert אם היה
- API חדש: GET /api/delivery-times/settlement-stats לפיד הדאשבורד
- כל ה-flows הקיימים של merge/link עברו ל-endpoint החדש — עוקבים אחרי כל פעולה ב-DB ומאפשרים ביטול
v01.56.000חדשcrm/conversionminorהמרה ללקוח פעיל — סגירת המשפך: הסכם חתום ⇒ Customer + מחירון + פורטל
פאזה 3 של CRM Funnel — endpoint יחיד שסוגר את כל המשפך: הסכם חתום ⇒ לקוח פעיל עם מחירון מוטמע, עם אפשרות לפתוח גם משתמש פורטל באותה פעולה.
פרטים נוספים ↓הסתר ↑
פאזה 3 של CRM Funnel — endpoint יחיד שסוגר את כל המשפך: הסכם חתום ⇒ לקוח פעיל עם מחירון מוטמע, עם אפשרות לפתוח גם משתמש פורטל באותה פעולה. **API חדש:** POST /api/contracts/[id]/convert — מקבל body עם name/email/phone/address/parentCustomerId/createPortalUser/portalFirstName/portalLastName. דורש שני permissions (CONTRACTS_EDIT + CUSTOMERS_CREATE) ו-feature flag crm_contracts. רץ ב-db.$transaction אטומית: (1) Customer.create אם לא קיים, או update עם status=ACTIVE אם קיים; (2) CustomerPricingProfile.upsert עם 7 שדות התעריפים מ-contract.baseRates באגורות (מקביל מלא ל-schema הקיים); (3) CustomerPricingRule.create לכל customRule מההסכם (אם יש), עם kind/mode/amount/label/validFrom/validTo/createdById; (4) Contract.update → ACTIVE + customerId, ContractEvent.create({type: ACTIVATED, actor, metadata: createdNewCustomer flag}); (5) Lead.status → CONVERTED + convertedCustomerId + LeadActivity של STATUS_CHANGE עם תיאור 'הליד הומר ללקוח X בעקבות חתימת הסכם Y'. **CustomerUser invite:** אם createPortalUser=true והאימייל תקף — מחוץ לטרנזקציה (כדי לא להכשיל את ה-conversion על שגיאת מייל): createCustomerUserInvite (asOwner) עם permissions מלאות, sendInviteEmail עם portal/accept-invite/[token] link, וההזמנה מוחזרת ב-response. שגיאה במייל לא מבטלת את ה-conversion (try/catch + console.error). **UI:** [ConvertToCustomerDialog.tsx](apps/web/app/(site)/contracts/components/ConvertToCustomerDialog.tsx) — דיאלוג בן שתי סקציות: 'פרטי הלקוח' (שם/אימייל/טלפון/כתובת/parent customer dropdown) עם pre-fill אוטומטי מ-signedByName/signedByEmail של ההסכם, ו-'גישה לפורטל הלקוח' (checkbox + שם פרטי/משפחה כש-checkbox מסומן). validation: שם חובה (Zod min 2), אימייל חובה אם portal user. בדף /contracts/[id]: כפתור 'המר ללקוח פעיל' מוצג רק כש-status=SIGNED ו-canConvert (שני permissions). כשהסטטוס ACTIVE — כפתור 'לכרטיס הלקוח' שמנווט ל-/customers/[customerId]. **Status flow מלא:** ליד NEW → IN_TREATMENT → QUOTED (פאזה 1) → CONTRACT_SENT → CONTRACT_SIGNED (פאזה 2) → **CONVERTED** (פאזה 3, עם convertedCustomerId). הסכם DRAFT → SENT_FOR_SIGNATURE → VIEWED → SIGNED → **ACTIVE** (פאזה 3).
- Endpoint יחיד POST /api/contracts/[id]/convert סוגר את כל המשפך באטומית
- יצירת Customer + CustomerPricingProfile + CustomerPricingRules עם נתוני ההסכם
- אופציה לפתוח CustomerUser ראשון (owner) עם invite לפורטל בלחיצה אחת
- Lead מקבל CONVERTED + convertedCustomerId + LeadActivity של ההמרה
- Contract → ACTIVE + ContractEvent ACTIVATED עם metadata (קיים/חדש)
- טרנזקציה אטומית — הכל נשמר ביחד או כלום; שגיאת מייל לא חוסמת את ההמרה
- Dialog ב-/contracts/[id] עם pre-fill מ-signedByName/Email + parent customer dropdown
- כפתור 'לכרטיס הלקוח' מופיע ב-status=ACTIVE לניווט מהיר
v01.55.000חדשcrm/contractsminorהסכמים וחתימה דיגיטלית — מודול חדש: יצירה מהצעת מחיר, שליחה לחתימה, signature pad, ת״ז חובה ואודיט משפטי
פאזה 2 של CRM Funnel — מודול הסכמים end-to-end עם חתימה אלקטרונית רגילה תקפה משפטית בישראל (חוק חתימה אלקטרונית, תשס״א-2001).
פרטים נוספים ↓הסתר ↑
פאזה 2 של CRM Funnel — מודול הסכמים end-to-end עם חתימה אלקטרונית רגילה תקפה משפטית בישראל (חוק חתימה אלקטרונית, תשס״א-2001). **API:** GET/POST /api/contracts (רשימה+יצירה — מקבל quoteId/leadId/customerId, יוצר ContractEvent של CREATED), GET/PATCH/DELETE /api/contracts/[id] (עריכה ומחיקה רק ב-DRAFT), POST /api/contracts/[id]/send (מפיק PDF טיוטה, מעלה ל-Supabase, שולח מייל עם signing link, מסמן SENT_FOR_SIGNATURE, מקדם ליד מקושר ל-CONTRACT_SENT, ContractEvent SENT), GET /api/public/contracts/[token] (public, מסמן VIEWED), POST /api/public/contracts/[token]/sign (public — חתימה: מאמת ת״ז ישראלית עם ספרת ביקורת, לוכד IP + UA + signature image, מפיק PDF חתום עם תמונת חתימה משובצת ו-audit footer, מעדכן הסכם ל-SIGNED, מקדם ליד ל-CONTRACT_SIGNED, שולח מייל אישור עם PDF חתום ללקוח). **תשתית:** lib/crm/contract-number.ts (CON-YYYY-NNNN), lib/crm/israeli-id.ts (ולידציה לפי אלגוריתם 9 ספרות + ספרת ביקורת — תקף ל-ת״ז וח.פ.), lib/crm/render-contract-pdf.tsx (react-pdf עם דף חתימה כולל תמונת חתימה, פרטי החותם, IP/UA וטקסט אזהרה משפטי), 2 email helpers חדשים: sendContractSignatureRequestEmail + sendContractSignedConfirmationEmail. **הרשאות:** 6 חדשות CONTRACTS_VIEW/CREATE/EDIT/DELETE/SEND/TEMPLATES_MANAGE — לרולים מנהליים בלבד (לא AGENT). **UI:** /contracts — עמוד רשימה עם פילטר/חיפוש, ContractForm dialog שתומך ב-3 מקורות יצירה: מהצעת מחיר (מעתיק baseRates+terms אוטומטית), מליד, או מלקוח קיים. /contracts/[id] — עמוד פירוט עם כרטיסי לקוח+תקופה, כרטיס חתימה (מוצג רק אחרי חתימה — עם IP/ת״ז/שעה לאודיט), טבלת תעריפים, תנאי שירות, ויומן אירועים מלא (CREATED/SENT/VIEWED/SIGNED עם actor_type ו-IP). /sign/[token] (public, ללא login) — דף חתימה ממותג עם תוכן ההסכם, signature pad של react-signature-canvas (תומך עכבר+מסך מגע), שדות חובה: שם/אימייל/ת״ז (validation client-side + server-side)/טלפון (אופציונלי), checkbox קריאה ואישור, וטקסט הסבר על תוקף החתימה האלקטרונית. אחרי חתימה — מסך success עם הורדת PDF החתום. **אינטגרציות:** בעמוד הצעת מחיר (status≠DRAFT) — כפתור 'צור הסכם' מנווט ל-/contracts?quoteId=… ופותח דיאלוג עם pre-fill מההצעה (תעריפים + תנאי שירות snapshot). Sidebar: 'הסכמים' תחת לקוחות, gated ע״י crm_contracts flag (תלוי ב-crm_quotes). Middleware: /sign ו-/api/public/contracts/[token]/sign ללא auth. **Audit/Legal:** lib/crm/israeli-id.ts מאמת לפי אלגוריתם רשמי; שדה signedByIdNumber חובה (לא optional); IP נלכד מ-x-forwarded-for/x-real-ip/cf-connecting-ip; UA נשמר חתוך ל-1000 תווים; PDF החתום כולל את כל פרטי החותם + IP + UA + הצהרה משפטית על חוק חתימה אלקטרונית. ContractEvent מהווה immutable audit trail.
- מודול הסכמים מלא: יצירה מהצעת מחיר → שליחה לחתימה → חתימה דיגיטלית → PDF חתום
- Signature pad ב-/sign/[token] (react-signature-canvas) — עכבר ומסך מגע, ת״ז חובה עם validation
- ולידציית ת״ז ישראלית (9 ספרות + ספרת ביקורת) — client-side ו-server-side
- PDF חתום כולל תמונת חתימה משובצת + פרטי החותם + IP + UA + הצהרה משפטית
- Audit trail מלא: ContractEvent immutable + actor_type + IP + timestamp לכל פעולה
- ליד מתקדם אוטומטית CONTRACT_SENT → CONTRACT_SIGNED בעת השליחה והחתימה
- מייל אישור עם PDF חתום נשלח אוטומטית ללקוח אחרי חתימה
- כפתור 'צור הסכם' בהצעת מחיר (status≠DRAFT) → ContractForm עם pre-fill מההצעה
v01.54.003תיקוןdelivery-times/settlement-aliasesעריכת שם חלופי: PATCH אמיתי במקום DELETE+POST שדרס id/createdAt/source
ב-AliasesDialog (פתיחה מ-/delivery-times/settlements) הפעולה 'ערוך' עשתה DELETE+POST: מחקה את ה-alias ויצרה חדש.
פרטים נוספים ↓הסתר ↑
ב-AliasesDialog (פתיחה מ-/delivery-times/settlements) הפעולה 'ערוך' עשתה DELETE+POST: מחקה את ה-alias ויצרה חדש. תופעות הלוואי: id חדש (מאבד הפניות אם היו), createdAt חדש, source נדרס ל-'manual' גם אם המקור היה auto-quotes/merge/bulk-merge/canonical-cleanup, ובמקרה ש-POST נכשל אחרי DELETE — ה-alias נמחק לעולמים. נוסף route חדש PATCH /api/delivery-times/settlement-aliases/[id] שמעדכן alias וב-originalName באטומיות תוך שמירה על id/createdAt/source. במקביל נוסף invalidateSettlementCache() אחרי כל POST/PATCH/DELETE כדי שהפונקציה המאוחדת תראה את השינוי ב-lookup הבא במקום לחכות 5 דקות. הוחלפה הפונקציה המקומית normalizeSettlementName ב-API route בייבוא של normalize מ-lib/settlements/normalize כדי שהמפתח שנשמר במסד יהיה עקבי עם מה שהפונקציה מחפשת.
v01.54.002שיפורdelivery-times/settlement-name-alertsטבלת התראות שמות לא מזוהים — אוטומציה: 41 רשומות שהפונקציה החדשה כן יודעת לפתור סומנו כ-LINKED
סקריפט חדש resolve-pending-alerts.ts עובר על כל הרשומות ב-status PENDING ב-UnknownSettlementAlert ומריץ עליהן resolveSettlement.
פרטים נוספים ↓הסתר ↑
סקריפט חדש resolve-pending-alerts.ts עובר על כל הרשומות ב-status PENDING ב-UnknownSettlementAlert ומריץ עליהן resolveSettlement. אם הפונקציה החדשה פותרת את ה-originalName דטרמיניסטית (exact/light/medium/alias/stripped), הרשומה מסומנת כ-LINKED עם linkedSettlementId/Name, reviewedAt עכשיו, ו-reviewNotes שמציין 'Auto-resolved by resolveSettlement (via X)'. לא נוצר alias חדש — הפונקציה ממשיכה לפתור גם ללא רשומה במסד. substring match לא נכלל באוטו-resolve (יותר מדי סיכון לזיהוי שגוי, נשאר ידני). מתוך 370 התראות PENDING, 41 קיבלו טיפול אוטומטי — כל אלה שנוצרו לפני הרפורמה כשהקוד הישן לא ידע לקלף קידומות (מושב X, קיבוץ X, ישוב X), לנרמל מקפים (תל אביב – יפו, רמת- השרון), או יי/וו (גניי תקווה, נורדייה, בירייה). יתר 326 ההתראות נשארו ידניות.
v01.54.001תיקוןdelivery-times/settlementsתיקון באג בניקוי שמות חלופיים: שחזור 34 רשומות שנמחקו במקרה (mutual-cover)
בסקריפט cleanup-redundant-aliases.ts מ-Phase 2.D היה באג: כששני aliases מצביעים לאותו ישוב ושותפים אותו key מנורמל (למשל 'קרית ספר' ו'קריית ספר' שניהם מנורמלים ל'קרית ספר'), הניתוח של כל אחד מהם מצא ש'השני מכסה אותי' — א…
פרטים נוספים ↓הסתר ↑
בסקריפט cleanup-redundant-aliases.ts מ-Phase 2.D היה באג: כששני aliases מצביעים לאותו ישוב ושותפים אותו key מנורמל (למשל 'קרית ספר' ו'קריית ספר' שניהם מנורמלים ל'קרית ספר'), הניתוח של כל אחד מהם מצא ש'השני מכסה אותי' — אז שניהם נמחקו ונוצר חור. נכתב סקריפט restore-mutually-covered-aliases.ts שעובר על קובץ הגיבוי, בודק לכל רשומה האם הפונקציה החדשה במצב ה-DB הנוכחי עדיין פותרת את ה-originalName אל אותו ישוב, ואם לא — משחזרת את ה-alias. 34 aliases שוחזרו (כולל קרית ספר → מודיעין עילית, תל אביב - יפו → תל אביב יפו, ועוד וריאציות יידוע של ירושלים/חיפה/מודיעין עילית). הוסף הערה לסקריפט ה-cleanup על המגבלה.
v01.54.000חדשcrm/quotesminorהצעות מחיר — מודול חדש: יצירה, PDF בעברית, שליחה במייל ועמוד צפייה ציבורי
פאזה 1 של CRM Funnel — מודול הצעות מחיר מלא end-to-end.
פרטים נוספים ↓הסתר ↑
פאזה 1 של CRM Funnel — מודול הצעות מחיר מלא end-to-end. **API:** GET/POST /api/quotes (רשימה + יצירה כטיוטה), GET/PATCH/DELETE /api/quotes/[id] (עריכה ומחיקה רק ב-DRAFT), POST /api/quotes/[id]/send (יוצר PDF, מעלה ל-Supabase Storage, שולח מייל ללקוח, מסמן SENT, מקדם ליד מקושר לסטטוס QUOTED אוטומטית + LeadActivity), GET /api/public/quotes/[token] (Public, no auth — לדף הצפייה של הלקוח). **תשתית:** lib/crm/quote-number.ts (מספור QUO-YYYY-NNNN פר טננט), lib/crm/render-quote-pdf.tsx (react-pdf עם פונט Rubik לעברית RTL, תעריפים בש״ח, תנאי שירות, footer ממוספר), sendQuoteEmail ב-lib/email.ts. **הרשאות:** 5 הרשאות חדשות QUOTES_VIEW/CREATE/EDIT/DELETE/SEND, חולקו ל-3 רולים עם הרשאות leads מלאות + ל-AGENT (ללא DELETE). **UI:** /quotes — עמוד רשימה מלא עם פילטר סטטוס, חיפוש, pagination, row actions (פתח / שלח / העתק קישור ציבורי / פתח כלקוח / מחק טיוטה). /quotes/[id] — עמוד פירוט עם header פעולות, כרטיסי נמען+פרטי שליחה, טבלת תעריפים, הערות ותנאים. /q/[token] (public, ללא login) — דף ממותג RTL עם לוגו טננט, מספר הצעה, סטטוס, תעריפים, הערות, תנאים, וכפתור הורדת PDF. **אינטגרציות:** כפתור 'צור הצעת מחיר' בפעולות שורת ליד מנווט ל-/quotes?leadId=… ופותח דיאלוג עם הליד pre-selected; הסיידבר כולל קישור 'הצעות מחיר' תחת קבוצת לקוחות, מותנה בפיצ'ר flag crm_quotes; middleware מאפשר /q ו-/api/public/quotes ללא auth, ומוסיף /quotes ו-/api/quotes ל-AGENT allowed prefixes. **Status flow:** DRAFT → SENT (אחרי /send + PDF + email) → VIEWED (פעם ראשונה שהלקוח פותח). publicAccessToken (32 בייטים crypto.randomBytes) נוצר בשליחה.
- מודול הצעות מחיר מלא: API + UI + PDF + מייל + public link
- PDF עברית RTL עם react-pdf + Rubik (תעריפים, הערות, תנאים, מספור עמודים)
- /q/[token] — דף צפייה ציבורי ממותג עם לוגו טננט, ללא login
- כפתור 'צור הצעת מחיר' בפעולות ליד → דיאלוג עם pre-fill אוטומטי
- ליד שמקבל הצעה מקבל אוטומטית סטטוס QUOTED + LeadActivity של שליחה
- Feature flag crm_quotes מסתיר את המודול בטננטים שאינם פעילים
- טוגלי הפעלת מודולים ב-/admin/tenants — הצעות מחיר + הסכמים (הסכמים תלויים בהפעלת הצעות)
v01.53.016חדשcrmCRM Funnel — תשתית סכמה לפאזה 0 (ליד→הצעת מחיר→הסכם→לקוח)
פאזה 0 של תוכנית ה-CRM הכוללת שאושרה היום: נוצרה התשתית המלאה ב-DB schema עבור משפך הלידים שייבנה מעל.
פרטים נוספים ↓הסתר ↑
פאזה 0 של תוכנית ה-CRM הכוללת שאושרה היום: נוצרה התשתית המלאה ב-DB schema עבור משפך הלידים שייבנה מעל. אין שינוי נראה למשתמש כרגע — רק יסודות לפיתוח הבא. נוספו 4 מודלים חדשים ב-Prisma schema: Quote (הצעת מחיר עם snapshot של תעריפים, סטטוס DRAFT→SENT→VIEWED→ACCEPTED, PDF storage, communication tracking), Contract (הסכם הנגזר מהצעה, תוכן מלא, חתימה דיגיטלית עם signedByIdNumber/IP/UA לאודיט, draft+signed PDFs), ContractEvent (immutable audit log פר הסכם), ContractTemplate (תבניות פר-טננט עם placeholders). הוסף enum CustomerStatus (LEAD/ACTIVE/SUSPENDED/ARCHIVED) ושדות status/suspended_at/suspended_by_id/suspend_reason ל-customers, עם backfill: לקוחות עם is_active=false → ARCHIVED. הורחב enum LeadStatus עם QUOTED/CONTRACT_SENT/CONTRACT_SIGNED/CONVERTED, נוסף converted_customer_id ל-leads כדי לקשר ליד שהומר ללקוח. נוצרו 2 enums חדשים נוספים: QuoteStatus, ContractStatus. נוסף apps/web/lib/crm/feature-access.ts עם isCrmQuotesEnabled + isCrmContractsEnabled (פטרן זהה ל-warehouse/feature-access). 0 שגיאות חדשות ב-typecheck. השלב הבא: פאזה 1 (UI להצעות מחיר + PDF generation עם react-pdf).
- 4 מודלים חדשים: Quote, Contract, ContractEvent, ContractTemplate
- Customer.status enum מחליף הדרגתית את isActive עם backfill
- Lead.convertedCustomerId + הרחבת LeadStatus ב-4 ערכים חדשים
- feature flags: crm_quotes + crm_contracts (gated של פאזות הבאות)
v01.53.015שיפורdelivery-times/settlementsתשתית: פונקציית resolveSettlement מאוחדת + harness לאי-רגרסיה
התשתית הראשונה לרפורמת שמות חלופיים: מודול חדש apps/web/lib/settlements/ עם normalize.ts (פונקציות נרמול טהורות, client-safe) ו-resolve.ts (פונקציה אחת resolveSettlement עם cache בזיכרון, 5+1 שלבים: exact → light → mediu…
פרטים נוספים ↓הסתר ↑
התשתית הראשונה לרפורמת שמות חלופיים: מודול חדש apps/web/lib/settlements/ עם normalize.ts (פונקציות נרמול טהורות, client-safe) ו-resolve.ts (פונקציה אחת resolveSettlement עם cache בזיכרון, 5+1 שלבים: exact → light → medium → alias → stripped → substring fallback). שמירת גרש אחרי ג'/ז'/צ'/ת'/ד' (תעתיק ערבי) — תיקון באג שמיזג ג'ת עם גת. נוסף scripts/capture-resolution-baseline.ts ו-scripts/verify-resolution-parity.ts שמריצים את כל 4 ה-callsites הקיימים על שמות עיר אמיתיים מ-30 הימים האחרונים ומשווים מול הפונקציה החדשה, לסיווג MATCH/IMPROVED/REGRESSION. 49 unit tests עוברים. בעקבות הסקירה הוטמעה הפונקציה ב-4 ה-callsites הצד-שרת: customer-pricing.isExceptionalZone, public/tracking resolveDeliveryType, sorting-error.findZoneCodeByCity, settlement-service.findSettlement. שמות עם מקפים שלא היו מזוהים קודם (מעלות-תרשיחא, פרדס חנה-כרכור, בנימינה-גבעת עדה וכו') מזוהים עכשיו נכון. שמות עם קידומת מושב/קיבוץ/כפר/ישוב מתקלפים אוטומטית. ImportShipmentsClient autocomplete עדיין לא הומר (Phase 1.B.5 — דורש endpoint להעברת הרשימה ללקוח). [Phase 2] ניקוי נתונים: 3 כפילויות בקנוני אוחדו ל-aliases — קריית ארבע → קרית ארבע, מרכז חבר → חבר, הר-חלוץ → הר חלוץ. נמחקו 447 aliases מיותרים (34.4%) שהפונקציה החדשה מכסה דטרמיניסטית (גרשיים, יי/וו, קידומות מושב/קיבוץ/כפר/ישוב). נמחק generateQuoteAliases ו-route generate-quotes שכבר לא נחוצים. נמחק alias שגוי 'ישוב חבר' → 'מעלה חבר' (החדש מחזיר נכון 'חבר').
v01.53.014תיקוןdrivers/earningsדו״ח תשלום חודשי — שם קובץ בעברית עובד בפועל + עמודת 'מזהה יוצא' (לא externalOrderId)
תיקון שני באגים שעלו אחרי משוב משתמש: (1) שם הקובץ בעברית שהוגדר ב-Content-Disposition של השרת לא הופיע בפועל כי הלקוח (EarningsCard) דרס אותו עם a.download שכתוב בקשיחות.
פרטים נוספים ↓הסתר ↑
תיקון שני באגים שעלו אחרי משוב משתמש: (1) שם הקובץ בעברית שהוגדר ב-Content-Disposition של השרת לא הופיע בפועל כי הלקוח (EarningsCard) דרס אותו עם a.download שכתוב בקשיחות. ה-blob URL לא קורא Content-Disposition אוטומטית, ולכן ה-a.download חייב להכיל את השם בעצמו. הוסף helper filenameFromContentDisposition שמפרסר את filename*=UTF-8'' מתוך header התגובה ומזין אותו ל-a.download, עם fallback לשם ה-ASCII הקודם אם משהו במידע השרת חסר. (2) העמודה שנקראה בטעות 'מזהה חיצוני' השתמשה ב-Shipment.externalOrderId (זה מזהה הזמנה חיצוני שהמשתמש סיפק ביצירת המשלוח — דבר אחר לגמרי). השדה שהמשתמש מתכוון אליו הוא 'מזהה יוצא' שמופיע בדף המשלוח — Shipment.targetPartnerTaskId (מזהה משלוח אצל הספק שאליו הועבר, מליונוויל). העמודה ב-EarningsLine שונתה ל-targetPartnerTaskId ושם העמודה בגיליון Excel שונה ל'מזהה יוצא'.
v01.53.013שיפורdrivers/earningsדו״ח תשלום חודשי לנהג — מע״מ לקבלנים, עמודות כתובת/מזהה חיצוני, מירכוז גורף
סדרת שיפורים לאחר משוב על הקובץ שיורד: (1) גיליון 'סיכום' — שורת 'ת.ז./מזהה' הוסרה לחלוטין, עמודה B הורחבה פי 2 (28 wch) כדי לאכלס שמות שליחים ארוכים יותר; אצל שליחים מסוג EXTERNAL (קבלן חיצוני) נוסף בלוק VAT: 'סה״כ לפני…
פרטים נוספים ↓הסתר ↑
סדרת שיפורים לאחר משוב על הקובץ שיורד: (1) גיליון 'סיכום' — שורת 'ת.ז./מזהה' הוסרה לחלוטין, עמודה B הורחבה פי 2 (28 wch) כדי לאכלס שמות שליחים ארוכים יותר; אצל שליחים מסוג EXTERNAL (קבלן חיצוני) נוסף בלוק VAT: 'סה״כ לפני מע״מ', 'מע״מ 18%', והבאנר הסופי משתנה ל'סה״כ לתשלום (כולל מע״מ)' עם הסכום המגולם. שלא לקבלנים, הבאנר נותר 'סה״כ תשלום נטו'. (2) גיליון 'משלוחים' — נוספה עמודה 'כתובת' המאחדת destinationStreet + destinationNumber לטקסט אחד ('הרצל 12'); אצל EXTERNAL בלבד, נוספה עמודה 'מזהה חיצוני' (Shipment.external_order_id) צמודה לעמודת הברקוד. (3) שם הקובץ — מ-'driver-42-2026-06.xlsx' ל-'דוח תשלום - יוסי כהן - יוני 2026.xlsx' (RFC 5987 UTF-8 encoding ב-Content-Disposition עם fallback ל-ASCII; טווח שאינו חודש קלנדרי שלם יקבל 'DD.MM.YY – DD.MM.YY' במקום שם חודש). (4) עיצוב — כל תוכן התאים בכל הגיליונות (סיכום, משלוחים, איסופים עסקיים, התאמות) מוצג ממורכז אופקית וורטיקלית; helper חדש centerEverything שמופעל לאחר שאר ה-styling כדי לא לדרוס borders/colors. (5) הרחבה ב-driver-earnings.ts: שדות destinationStreet, destinationNumber ו-externalOrderId נוספו ל-VISIT_SHIPMENT_SELECT וזולגים ל-EarningsLine — שאר ה-callers (UI card, mobile API) ממשיכים לעבוד כי הם פשוט מתעלמים מהשדות החדשים.
v01.53.012חדשmiddleware/hostדומיינים מוגבלים לכניסה בלבד (maslul.space, alonim.store) — ללא landing וללא /docs
הוספת host-gate ב-middleware: בקשות לדומיינים שלנו שאינם shipnest.io — נכון לעכשיו maslul.space ו-alonim.store (כולל וריאנטי www) — שמכוונות ל-/landing או ל-/docs (כולל תתי-נתיבים) מופנות אוטומטית ל-/login באותו host.
פרטים נוספים ↓הסתר ↑
הוספת host-gate ב-middleware: בקשות לדומיינים שלנו שאינם shipnest.io — נכון לעכשיו maslul.space ו-alonim.store (כולל וריאנטי www) — שמכוונות ל-/landing או ל-/docs (כולל תתי-נתיבים) מופנות אוטומטית ל-/login באותו host. שאר הנתיבים — /login עצמו, /portal/login, /employee/login, ו-routes מאומתים — ממשיכים לעבוד רגיל. / עצמו לא נוגעים בו: page.tsx ממילא מפנה משתמשים לא מחוברים ל-/landing, וה-gate החדש תופס את ההפניה הזאת והופך אותה ל-/login. shipnest.io לא מושפע — הבדיקה מבוססת על host header, לא env. הרשימה מוגדרת כקבוע LOGIN_ONLY_HOSTS בראש middleware.ts כדי שיהיה קל להוסיף דומיינים נוספים בעתיד.
v01.53.011תיקוןmiddleware/agentסוכנים — שחרור /api/settlements ב-middleware (סיבת השגיאות הרבות ביבוא)
השורש האמיתי של 'אצל הסוכן יש יותר שגיאות יבוא מאשר אצל האדמין' (62 מול 22 בהתחלה, 143 מול 22 בהתחזות) נמצא ב-middleware: ה-allowedPrefixes של תפקיד AGENT לא כלל את /api/settlements.
פרטים נוספים ↓הסתר ↑
השורש האמיתי של 'אצל הסוכן יש יותר שגיאות יבוא מאשר אצל האדמין' (62 מול 22 בהתחלה, 143 מול 22 בהתחזות) נמצא ב-middleware: ה-allowedPrefixes של תפקיד AGENT לא כלל את /api/settlements. כל בקשה של אשף היבוא ל-GET /api/settlements/bulk חזרה 403 לפני שהגיעה בכלל ל-route handler. בצד הלקוח ה-fetch הצליח (קיבל תגובה), אבל Array.isArray(data?.settlements) נכשל, ומערך היישובים נשאר ריק — splitTrailingCity לא יכול היה לקלף עיר מסוף הכתובת, וכל שורה ללא עמודת 'עיר' מפורשת נכשלה בולידציה של 'עיר חובה'. אצל אדמין (OWNER/PLATFORM_ADMIN) ה-middleware לא חוסם, וה-fetch מצליח. תיקון: הוספת /api/settlements לרשימת ה-allowedPrefixes של AGENT (היישובים הם dictionary גלובלי לא רגיש — שמות יישובים בלבד, אותה הרשאה שכבר ניתנת לקריאה ב-route handler עצמו דרך SHIPMENTS_VIEW). שני התיקונים הקודמים שלי על race-condition בטעינת היישובים (settlementsReadyRef + poll) נשארים כ-safety net אבל לא היו הסיבה האמיתית.
v01.53.010שיפורdrivers/earningsדו״ח תשלום חודשי לנהג — עיצוב גיליון הסיכום + פירוט איסופים עסקיים
המעבר מ-xlsx ל-xlsx-js-style מאפשר כתיבת עיצוב ברמת התא.
פרטים נוספים ↓הסתר ↑
המעבר מ-xlsx ל-xlsx-js-style מאפשר כתיבת עיצוב ברמת התא. גיליון 'סיכום' מקבל כעת כותרת בולטת על רקע primary, שורת כותרת לטבלת הפירוט עם רקע אפור ו-borders, פורמט מטבע ילידי (#,##0.00 ₪) על כל הסכומים, ובאנר 'סה״כ תשלום נטו' עם רקע primary וטקסט לבן בגדול. נוסף גיליון חדש 'איסופים עסקיים' שמוצג רק כאשר יש לפחות איסוף עסקי אחד בתקופה — מציג שורה לכל ברקוד ששייך לקבוצת איסוף עסקי, עם קוד קבוצה (BP-1, BP-2, …), תאריך, לקוח, ברקוד, חבילות, סכום למשלוח, כמות בקבוצה וסה״כ קבוצה. הקבוצות מקבלות רקע אלטרנטיבי לזיהוי ויזואלי של גבולות הקבוצה. בנוסף נוספה עמודה 'קבוצת איסוף' בגיליון 'משלוחים' שמכילה את אותו קוד BP-N — כך אפשר לעקוב מכל שורה לאיזו קבוצת איסוף היא שייכת. כל הגיליונות ממשיכים להיפתח ב-RTL. עדכון נוסף: גיליון 'התאמות' מוסתר לחלוטין כשאין התאמות ידניות בתקופה (אותה מדיניות כמו 'איסופים עסקיים') — גיליון ריק רק מבלבל קוראים שחושבים שמשהו חסר. תיקון נוסף: דגל ה-RTL הוזז מ-sheet['!views'] (שנבלע בשקט ע״י xlsx-js-style) ל-workbook.Workbook.Views[0].RTL — כך הקובץ באמת נפתח באקסל בכיוון ימין-לשמאל בכל הגיליונות; הניסיון הקודם לא עבד.
v01.53.009שיפורdrivers/listרשימת שליחים — עמודת מחירון + פילטרים + סטטוס אינליין + נוכחות חיה
נוספה עמודה 'מחירון' לרשימת השליחים: כאשר הוגדר מחירון מופיע כפתור 'ערוך מחירון' שפותח את אותו דיאלוג עריכת מחירון של דף השליח; כאשר לא הוגדר — טקסט מעומעם 'לא הוגדר מחירון' שלחיצה עליו פותחת את הדיאלוג במצב הקמה ראשונה.
פרטים נוספים ↓הסתר ↑
נוספה עמודה 'מחירון' לרשימת השליחים: כאשר הוגדר מחירון מופיע כפתור 'ערוך מחירון' שפותח את אותו דיאלוג עריכת מחירון של דף השליח; כאשר לא הוגדר — טקסט מעומעם 'לא הוגדר מחירון' שלחיצה עליו פותחת את הדיאלוג במצב הקמה ראשונה. בנוסף, נוסף ל-toolbar כפתור 'פילטרים' (FiltersPopover משותף) עם שתי קטגוריות: 'מחירון' (הוגדר / לא הוגדר — בחירה יחידה) ו'אזורי חלוקה' (multi-select לפי zoneCode, נגזר מ-allowedZones של השליחים בטאב הנוכחי). עמודת הסטטוס (פעיל/לא פעיל) הפכה לעריכה אינליין דרך dropdown — באותה תבנית של עריכת סטטוס משלוח בדף המשלוחים. נוסף PATCH /api/drivers/[id] שמעדכן רק את isActive וגם מסנכרן את ה-employee המקושר (אם קיים). הוסר ניווט-בלחיצה-על-השורה כדי שלא יפתח דף שליח בטעות בעת תפעול אינליין; ניווט לדף השליח מתבצע עכשיו רק דרך אייקון ה-ExternalLink שמופיע משמאל לשם השליח בריחוף (DriverNameDisplay). נוספו פעולות קבוצתיות לסרגל הבחירה: 'סמן כפעיל', 'סמן כלא פעיל' (עם דיאלוג אישור — מסנכרן גם employees מקושרים), ו-'הגדר מחירון' שפותח דיאלוג קצר עם 6 שדות תעריף בסיס (₪) ומחיל אותם על כל השליחים שנבחרו דרך POST /api/drivers/batch/pricing (יוצר profile חדש לשליחים בלי מחירון, מעדכן רק שדות שהוזנו לשליחים עם profile קיים). הוסר כפתור 'ייצוא' מסרגל הבחירה — הייצוא לאקסל נשאר רק כפעולת טבלה ראשית. נוספה עמודת 'נוכחות' (אינדיקציה חיה): נקודה ירוקה מהבהבת = השליח בתוך משמרת פעילה כעת, כתומה = סיים משמרת בשעות האחרונות, אדומה = משמרת פתוחה > 12 שעות (כנראה שכח לסיים), אפורה = ידוע אך לא במשמרת, אפורה דקה = ללא נתוני נוכחות (שליח בלי Employee). הנוכחות נגזרת מה-Shift האחרון של ה-Employee המקושר; ה-API מחזיר אותה דרך single batched query (DISTINCT ON על shifts) כדי לא לפגוע בביצועים. הקטגוריה 'נוכחות' נוספה גם ל-FiltersPopover עם מונים לכל דלי, ועמודת הנוכחות ניתנת למיון לפי סדר עדיפות (פעיל → פיגור → לאחרונה → לא פעיל → ללא).
v01.53.008שיפורdrivers/earningsדו״ח תשלום חודשי לנהג — אקסל נפתח מימין-לשמאל
ייצוא ה-Excel של דו״ח התשלום החודשי (סיכום + משלוחים + התאמות) מקבל עכשיו את דגל ה-RTL של ה-sheet view ב-SheetJS.
פרטים נוספים ↓הסתר ↑
ייצוא ה-Excel של דו״ח התשלום החודשי (סיכום + משלוחים + התאמות) מקבל עכשיו את דגל ה-RTL של ה-sheet view ב-SheetJS. כתוצאה מכך הקובץ נפתח באקסל בפריסה ישראלית — עמודה A בקצה הימני, הזרימה ימין-לשמאל — בלי שהמשתמש צריך להחליף את כיוון הגיליון ידנית בכל פתיחה.
v01.53.007תיקוןauth/impersonationהתחזות לסוכן — מילוי agentId על-בסיס effective role במקום User.role
באג ב-JWT callback של ההתחזות: הבדיקה אם לטעון את ה-Agent record (כדי לאכלס token.agentId) הסתעפה על targetUser.role === 'AGENT'.
פרטים נוספים ↓הסתר ↑
באג ב-JWT callback של ההתחזות: הבדיקה אם לטעון את ה-Agent record (כדי לאכלס token.agentId) הסתעפה על targetUser.role === 'AGENT'. אצל רוב הסוכנים תפקיד ה-AGENT מאוחסן ב-TenantUser.role ולא ב-User.role (זה הפיצ'ר של תפקידים פר-טננט), ולכן הבלוק לא רץ בכלל. כתוצאה מכך, אדמין שעשה 'התחבר כסוכן' קיבל session עם role='AGENT' (נכון, דרך resolveEffectiveRole) אבל agentId=null — וכל ה-endpoints שמסננים ל-AGENT לפי הלקוחות המשויכים (api/customers, api/shipments, api/customers/for-shipment-form) החזירו רשימות ריקות. נראה כאילו לסוכן אין לקוחות ולא משלוחים, בעוד שכשהסוכן עצמו התחבר ישירות הכל עבד תקין (זרימת הלוגין הרגילה כבר בוחנת effectiveRole). תיקון: ב-auth.ts JWT callback (impersonation block) קוראים את ה-Agent record בלי תנאי מקדים — השאילתה ממילא מסננת לפי users.some.userId — ומאכלסים את agentId אך ורק אם targetEffectiveRole === 'AGENT' (כדי שמשתמש עם קישור AgentUser שאיננו עוד סוכן בפועל לא יקבל scope שגוי). ה-tenantId נבחר עדיין על-בסיס TenantUser תחילה (admin עם קישור AgentUser ישן לא ייכנס בטעות לטננט של הסוכן), עם fallback ל-agent.tenantId אם אין TenantUser בכלל. תוקנה גם בדיקת ה-gate המקדימה ב-/api/users/impersonate שהשתמשה באותו דפוס מוטעה.
v01.53.006חדשstores, integrationsסקפולד אינטגרציה e-shop.co.il
הונח הבסיס לאינטגרציה עם e-shop.co.il: client, mapper, delivery-sync, cron job (כל 5 דקות), ו-UI בדף החנויות.
פרטים נוספים ↓הסתר ↑
הונח הבסיס לאינטגרציה עם e-shop.co.il: client, mapper, delivery-sync, cron job (כל 5 דקות), ו-UI בדף החנויות. הקוד מסומן ב-TODO עד שיתקבלו פרטי ה-API הרשמיים מ-e-shop.
v01.53.005תיקוןshipments/importייבוא משלוחים — race condition: ניתוח הקובץ ממתין למילון היישובים
תיקון באג שגרם לאותו קובץ לתת מספר שונה של שגיאות תלוי במהירות המשתמש: handleFile קרא את settlementsRef.current באופן סינכרוני, אבל הוא מתאכלס רק אחרי ש-/api/settlements/bulk חזר.
פרטים נוספים ↓הסתר ↑
תיקון באג שגרם לאותו קובץ לתת מספר שונה של שגיאות תלוי במהירות המשתמש: handleFile קרא את settlementsRef.current באופן סינכרוני, אבל הוא מתאכלס רק אחרי ש-/api/settlements/bulk חזר. מי שהעלה קובץ לפני שהמילון הגיע פירס בלי dictionary, ו-splitTrailingCity לא הצליח לקלף עיר מסוף הכתובת ('השקד 7 מודיעין' → עיר ריקה). normalizeCities שרץ אחרי שהיישובים הגיעו לא ניסה שוב לפצל כתובות — רק נירמל שמות עיר שכבר נקלטו. הניסיון הראשון השתמש ב-Promise/resolver מתוך useState lazy initializer; זה נכשל ב-React StrictMode (lazy initializer רץ פעמיים, ה-ref דרס למצביע על Promise שני אבל ה-state שמר את ה-resolver של הראשון, וה-Promise השני אף פעם לא התפזר) ובמקרה של הסוכן גרם לכל השורות להיכשל. ה-fix הסופי משתמש בדפוס poll פשוט שעמיד ל-StrictMode/HMR: counter של 'כמה fetches סיימו' שמתעדכן בכל סיום (success או failure), ו-handleFile עושה poll עד שהמילון מאוכלס או שהבדיקה הסתיימה, עם timeout של 5 שניות שלא יחסום את ה-UI אם ה-endpoint שבור.
v01.53.003תיקוןdrivers/linkedשליחים מקושרים — תיקון: הפיכת שליח רגיל למנהל אפסה את הדוח החודשי
באג שהתגלה בייצור — כשאדמין הפך שליח קיים לקבלן-מנהל, הדוח החודשי שלו ירד מ-16,000₪ ל-0.
פרטים נוספים ↓הסתר ↑
באג שהתגלה בייצור — כשאדמין הפך שליח קיים לקבלן-מנהל, הדוח החודשי שלו ירד מ-16,000₪ ל-0. הסיבה: computeManagerTenantEarnings סינן רק visits עם Visit.managedByDriverId מתויג מפורשות, אבל המשלוחים ההיסטוריים של המנהל (שבוצעו לפני שהוא הפך למנהל) היו עם managedByDriverId=null. תיקון: ה-query מסנן עכשיו OR — visits מתויגים מפורשות כ-managedBy=manager, OR visits שבהם driverId=manager AND managedByDriverId IS NULL. השני הוא fallback לוגי-בטוח (אם אדם X ביצע משלוח ואף אחד לא תבע אחריות כספית עליו, אז זה של X) — בלי סיכון של misattribution. ה-fallback לא חל על סאבים — visit ישן של סאב יכול להיות מתקופה לפני שהוא נכנס לצוות או של מנהל אחר; לזה צריך backfill מפורש (scripts/backfill-managed-by.ts). שום צורך ב-backfill ידני אחרי toggle של מנהל — המנוע מטפל בזה אוטומטית.
- Engine fix: computeManagerTenantEarnings.where = { OR: [{managedByDriverId: manager}, {driverId: manager, managedByDriverId: null}], ... }. השאר זהה.
- Sub work בטוח לא מושפע — fallback חל רק על visits שה-driverId שלהם הוא המנהל עצמו.
- Test חדש: 'fallback: includes manager own untagged visits' — מבטיח שהבאג הזה לא יחזור. Test ישן עודכן לבדוק את ה-OR החדש.
- 875/875 בדיקות עוברות. ה-fix נכנס לתוקף מיד — אדמינים שיהפכו שליח למנהל יראו את הדוח שלו ללא שינוי.
מאי 2026
v01.53.002תיקוןlandingתיקון build — הסרת דף landing כפול שנותר ב-(site)
אחרי ה-refactor של 7ad4643a שהעביר את ה-landing ל-/landing, הקובץ הישן apps/web/app/(site)/landing/page.tsx נותר במקומו וגרם ל-Turbopack לכשול בdeploy עם 'You cannot have two parallel pages that resolve to the same path'.
פרטים נוספים ↓הסתר ↑
אחרי ה-refactor של 7ad4643a שהעביר את ה-landing ל-/landing, הקובץ הישן apps/web/app/(site)/landing/page.tsx נותר במקומו וגרם ל-Turbopack לכשול בdeploy עם 'You cannot have two parallel pages that resolve to the same path'. נמחק.
v01.53.001תיקוןdrivers/linkedשליחים מקושרים — פאזה 7: ביקורת אבטחה + תיקון webhook ל-managedByDriverId
פאזה 7 (סיום) של פיצ'ר השליחים המקושרים.
פרטים נוספים ↓הסתר ↑
פאזה 7 (סיום) של פיצ'ר השליחים המקושרים. ביקורת אבטחה מקיפה על כל ה-API שנגעו ב-Person/cross-tenant — לא נמצאו דליפות אמיתיות, אבל פער פונקציונלי אחד התגלה ותוקן: ה-createVisits ב-data-service.ts (מסלול ה-webhook של Lionwheel ליצירת ביקורים אוטומטית) לא הציב את Visit.managedByDriverId, כך שמשלוחים שנוצרו דרך webhook אוטומטי למנהל/סאב חושבו כעצמאיים בדוח החודשי. נוסף buildManagedByMap שמשמש את כל 3 ה-callers של createVisits (data-service.ts + upsertShipment), כך שעכשיו ה-webhook מגיע לאותה התנהגות כמו השיבוץ הידני (resolveManagedByDriverId שנוסף ב-2A). הפיצ'ר השליחים-מקושרים מושלם — 7 פאזות, 8 commits, 874/874 בדיקות עוברות, version 01.46.000→01.53.001.
- Audit: 7 נקודות נבדקו (Person APIs, DriverManagerLink scoping, webhook flow, earnings tenant guard, mobile inbox, PersonalStop access, backfill safety). NO leaks found.
- fix: data-service.ts createVisits — שלושת ה-callers (POST /api/v1/webhook upsertShipment ושני create paths נוספים) משתמשים עכשיו ב-buildManagedByMap, אז Visit.managedByDriverId מציב נכון לפי הקשר השליח (manager/sub/standalone) גם כשה-visit נוצר ע"י webhook.
- תאימות לאחור: לטננטים בלי אף isManagerEnabled, ה-managedByMap ריק וההתנהגות זהה למה שהיה לפני הפאזה.
- סוף הפרויקט: כל 7 הפאזות שודרו ב-2026-05-31. מוכן לשימוש בייצור — admin יכול להפעיל toggle 'קבלן-מנהל' על כל שליח ולהתחיל להוסיף לו סאב-שליחים.
v01.53.000חדשdrivers/linkedminorשליחים מקושרים — פאזה 6: Unified Inbox API (תשתית לתצוגה מאוחדת)
פאזה 6 של פיצ'ר השליחים המקושרים.
פרטים נוספים ↓הסתר ↑
פאזה 6 של פיצ'ר השליחים המקושרים. נוסף endpoint חדש GET /api/v1/mobile/inbox שמחזיר feed מאוחד של כל העצירות של ה-Person המאומת — מכל הטננטים שבהם יש לו Driver פעיל + כל ה-PersonalStops שלו. זוהי ההרכבה של הרעיון של 'אפליקציה של השליח, לא של החברה': המובייל יכול עכשיו להציג מסך אחד עם כל המשלוחים מ-N טננטים + העצירות הפרטיות באותה רשימה ממוינת, כל עצירה מתוייגת במקור (טננט / personal). ה-endpoint הקיים פר-טננט (mobile JWT עם driverId/tenantId) נשמר בלי שינוי לתאימות לאחור. שילוב מלא עם ה-route planner (העברת PersonalStops דרך optimize/activate) דחוי לפאזה 6.5 — דורש שינוי משותף עם קוד המובייל. הפאזה הזו מספקת את ה-data foundation בלבד.
- GET /api/v1/mobile/inbox: מאמת ע"י mobile JWT, מתרגם driverId→personId, מוצא את כל ה-drivers הפעילים של ה-Person בכל הטננטים, ושולף את כל ה-visits שלהם + כל ה-PersonalStops של ה-Person.
- תגובה מאוחדת: stops[] פולימורפי עם type='VISIT'|'PERSONAL', tenantId+tenantName (null ל-personal), address מובנה, coordinates (משלוח first, fallback ל-visit lat/lng), recipientName/Phone, packages, hasCOD+codAmount (agorot), notes, POD URLs.
- ברירת מחדל סינון: ?status=PENDING (כברירת מחדל). אופציות: COMPLETED, FAILED, ALL.
- סדר: מיון לפי scheduledAt עולה (visitAt ל-visits, scheduledFor ל-personal); null בסוף; stable.
- Cross-tenant safety: ה-endpoint לא חושף את הרשימה לאף Person אחר. אם אין personId על ה-Driver של ה-JWT — 403.
- 8 בדיקות חדשות לעוזרי המיון/סטטוס; סה״כ 874/874 עוברות.
- Phase 7 הבא: ביקורת הרשאות חוצות-טננט על כל הנקודות הרגישות + cleanup.
v01.52.000שיפורlandingminorדף נחיתה ציבורי — שדרוג מקיף
שכתוב כולל של דף הנחיתה הראשי (/) — Hero חזק יותר, סקציות חדשות, ותוכן כן יותר במקום פלייסהולדרים מומצאים.
פרטים נוספים ↓הסתר ↑
שכתוב כולל של דף הנחיתה הראשי (/) — Hero חזק יותר, סקציות חדשות, ותוכן כן יותר במקום פלייסהולדרים מומצאים. ה-Hero מציג עכשיו סטטוס גרסה חי, headline ממוקד ('הלוגיסטיקה שלך, בלי קובץ Excel אחד'), ו-trust strip קצר (ללא כרטיס אשראי, הקמה תוך 10 דקות, ענן ישראלי + RTL). שורת הלוגואים המומצאים ('לוגיסטיקה מהירה', 'ג'אמפ שליחויות' וכו') הוחלפה ב-marquee גלילה של קטגוריות אינטגרציה גנריות (מערכות משלוחים, מערכות הנה״ח, WhatsApp Cloud API, Excel, Webhook REST, Google Sheets, ERP) — בלי הזכרת שמות מותג ספציפיים. נוספה סקציית 'איך זה עובד' עם 3 שלבים ויזואליים (ייבוא → אוטומציה → אנליטיקה), סקציית WhatsApp showcase עם דמו טלפון, סקציית use-cases (חברות שליחויות / 3PL / e-commerce) שמחליפה את ההמלצות הפיקטיביות, וסקציית FAQ עם 6 שאלות נפוצות באמצעות details/summary. סקציית הסטטיסטיקות הומרה לערכים שאפשר לעמוד מאחוריהם (זמינות, זמן טעינה, תאימות RTL, ניטור) במקום מספרי לקוחות מומצאים. ה-Footer הורחב ל-4 עמודות (מותג, מוצר, משאבים, צור קשר) עם קופירייט שמתעדכן אוטומטית לפי שנה. נוספו media queries מפורשים ל-768px ו-480px שמטפלים בpadding, גודל גופן, וכפתורים בפריסה אנכית במובייל. כל קישורי 'התחל עכשיו' עברו מ-/shipments ל-/login כדי שמשתמשים לא מזוהים יגיעו ל-flow ההתחברות בצורה תקינה.
- Hero חזק יותר: badge עם dot חי שמציג את גרסת המערכת, headline ממוקד שמדבר על הכאב האמיתי ('בלי קובץ Excel אחד'), ו-trust strip בלי הבטחות שווא.
- החלפת לוגואים מומצאים ב-integrations marquee גלילה עם קטגוריות גנריות (מערכות משלוחים, מערכות הנה״ח, WhatsApp Cloud API, Excel, REST, Sheets, ERP) — בלי שמות מותג ספציפיים.
- סקציה חדשה 'איך זה עובד' (#how) — 3 כרטיסי שלבים עם מספור 01/02/03 גדול ברקע, אייקונים צבעוניים ותיאורים מדויקים.
- סקציית WhatsApp showcase חדשה — mock של טלפון עם שיחת WhatsApp אמיתית (קליטה → יציאה → קרבה → מסירה), typing indicator מונפש, ו-bullets על האוטומציה משמאל.
- סקציית use-cases מחליפה את ההמלצות הפיקטיביות (אבי כהן/מירי לוי וכו') ב-3 פרסונות עם מבנה 'האתגר → עם Shipnest' (חברות שליחויות, מחסני 3PL, e-commerce).
- סקציית FAQ חדשה (#faq) עם 6 שאלות נפוצות באמצעות details/summary נייטיב — accessibility מובנית, ללא state ולא client component.
- סטטיסטיקות כנות: 99.9% זמינות, <2s טעינה, 100% RTL, 24/7 ניטור — במקום '500+ עסקים פעילים' ו-'2M+ משלוחים' שלא ניתן להוכחה.
- Footer הורחב ל-4 עמודות (מותג + תיאור / מוצר / משאבים / צור קשר) עם © שנה דינמית במקום '© 2025' hard-coded.
- Responsive: media queries מפורשים @768px (padding, marquee מהיר יותר, dash-metrics אנכי) ו-@480px (כפתורי CTA full-width אנכיים, גופן קטן יותר).
- כל CTAs 'התחל עכשיו' מצביעים על /login במקום /shipments — משתמשים לא מזוהים מגיעים ל-flow ההתחברות נכון.
- Routing: הדף עבר מ-/ ל-/landing כדי שגם משתמשים מחוברים יוכלו לצפות בו (פתיחה ישירה של /landing). ה-/ עכשיו ניתוב טהור: מחובר → /shipments, אנונימי → /landing. /landing נוסף ל-publicRoutes ב-middleware כדי שאנונימיים לא יישלחו ל-/login.
- Typography: כותרת ה-Hero ומספרי ה-stats עברו מ-Rubik 900 ל-Heebo 700 עם letter-spacing פתוח יותר (-0.01em ל-Hero, -0.005em ל-stats) ו-line-height מרווח — מרגיש עגול, אוורירי וקצת יותר דק. Heebo נוסף ל-globals.css (היה מוצהר ב-tailwind אבל לא נטען בפועל).
- Marquee fix: ה-integrations marquee נעלם מהמסך באמצע הלולאה כי ב-RTL הקונטיינר נצמד לימין-pa-parent ו-translateX(-50%) הזיז אותו ימינה→שמאלה אל מחוץ למסך בלי שום תוכן שמחליק פנימה. תוקן ע"י כפיית direction:ltr על המסילה (extends right from left edge) ו-direction:rtl על כל pill (האייקון נשאר מימין לטקסט).
v01.51.000חדשdrivers/linkedminorשליחים מקושרים — פאזה 5: עצירות אישיות (PersonalStop)
פאזה 5 של פיצ'ר השליחים המקושרים.
פרטים נוספים ↓הסתר ↑
פאזה 5 של פיצ'ר השליחים המקושרים. מודל PersonalStop חדש — עצירה אישית של שליח שאינה שייכת לאף טננט (Circuit-style). הבעלים היחיד היא ה-Person, לא הטננט. השליח מוסיף עצירות אלו ב-app שלו כדי לערב משלוחים חיצוניים (פרילנס/אישיים) במסלול הקיים. כל הסכמה: כתובת מובנית + שדה fullAddress חופשי, geocoding אופציונלי, נמען, מס׳ חבילות, COD אופציונלי, scheduledFor אופציונלי, סטטוס מחזור-חיים (PENDING/COMPLETED/FAILED/CANCELED) עם timestamps נפרדים, POD אופציונלי (תמונה + חתימה). API מובייל מלא תחת /api/v1/mobile/personal-stops עם CRUD מאובטח: ה-mobile JWT נושא driverId, השרת מתרגם ל-personId דרך Driver.personId, וכל שאילתא מסוננת ל-personId של המבקש. עצירה של Person אחר מחזירה 404 בלי לדלוף שהיא קיימת. ה-status transition idempotent — קריאה עם אותו סטטוס לא יוצרת timestamp חדש מיותר. הפאזה הבאה (6) תשלב את ה-PersonalStops עם ה-route planner הקיים במובייל כך שהם ישולבו במסלול עם Visits מטננטים.
- PersonalStop model + enum PersonalStopStatus (PENDING/COMPLETED/FAILED/CANCELED) + 2 indexes (personId,status / personId,scheduledFor).
- FK ל-Person עם CASCADE — מחיקת Person מוחקת את העצירות שלו (לעולם לא מוחקים drivers בעקבות זה, רק עצירות אישיות).
- API מובייל מלא: GET/POST /api/v1/mobile/personal-stops + GET/PATCH/DELETE /[id]. כל אחד מאובטח דרך requireMobileAuth ומסונן ל-Person של המבקש.
- Status transitions idempotent: COMPLETED → completedAt + clear failed/canceled; FAILED → failedAt + clear; CANCELED → canceledAt + clear; PENDING → clear everything (re-open). קריאה עם אותו סטטוס = no-op.
- 6 בדיקות חדשות לזרימת ה-status (סה״כ 867/867 עוברות). typecheck + lint נקיים.
- Phase 6 הבאה: שילוב ה-PersonalStops ב-route planner הקיים במובייל — inbox מאוחד של Visits מכל הטננטים של ה-Person + PersonalStops אישיות.
v01.50.000חדשdrivers/linkedminorשליחים מקושרים — פאזה 4: קישור שקט חוצה-טננטים לפי אימייל
פאזה 4 של פיצ'ר השליחים המקושרים.
פרטים נוספים ↓הסתר ↑
פאזה 4 של פיצ'ר השליחים המקושרים. כשטננט מקים שליח חדש עם אימייל שכבר קיים על Person כלשהו במערכת (כולל בטננט אחר), המערכת מקשרת את ה-Driver החדש לאותו Person במקום ליצור חדש — בלי שהאדמין יודע. זוהי התשתית להמשך: באפליקציית הנייד (Phase 6) הסאב יראה משלוחים מכל הטננטים בהם הוא מוקם, וב-PersonalStop (Phase 5) יוכל להוסיף עצירות אישיות חוצות-טננטים. הקישור הוא לפי canonical email (lowercase + trim, ללא קיבוץ של + או . בחלק המקומי) — בכוונה לא לפי טלפון, כי טלפון יותר רגיש לטעויות הקלדה ו-false-match יכול לפתוח גישה לזר. אימייל הוא identifier of trust סטנדרטי לכל SaaS. אדמין שטועה באימייל = טעות אדמיניסטרטיבית, לא באג מערכתי. שום שינוי UX חשוף — האדמין רואה רק שליח חדש שנוסף לטננט שלו.
- Person.email + canonical_email: שדות חדשים על Person, indexed ולא unique (פרגמטי לבקפיל). canonicalEmail = lowercase + trim בלבד — אין +/. collapse כי הם משמעותיים אצל חלק מהספקים.
- lib/person.ts → canonicalizeEmail() + createPersonForNewDriver() עם merge מובנה: אם canonicalEmail תואם Person קיים, מוחזר ה-id שלו; אחרת נוצר Person חדש. אין auto-merge לפי טלפון — בכוונה.
- POST /api/drivers בכל 3 ה-branches (EMPLOYEE קיים, EMPLOYEE חדש, CONTRACTOR/EXTERNAL) מעבירים body.email ל-createPersonForNewDriver. ה-CONTRACTOR/EXTERNAL branch סוף-סוף שומר את האימייל (קודם נזרק לפח).
- Backfill script scripts/backfill-person-emails.ts מעתיק Employee.email → Person.email לכל Person שעדיין null. הופעל בייצור — אין נתונים לבקפיל כרגע (תיקין צעיר), אבל הסקריפט מוכן.
- 7 בדיקות חדשות ל-Person helpers (canonicalizeEmail + auto-merge happy path + miss path + no-email skip + phone-only no-merge). סה״כ 861/861 עוברות.
- Privacy: log INFO רושם 'Silent cross-tenant Person link via canonicalEmail' רק לשרת — האדמין לא יודע, אבל המערכת רואה. ניתן יהיה לאתר merge-by-mistake מאוחר יותר.
- Phase 5 הבאה: PersonalStop — עצירות אישיות של שליח שאינן שייכות לאף טננט (Circuit-style).
v01.49.000חדשdrivers/linkedminorשליחים מקושרים — פאזה 3: שכבת Person גלובלית (תשתית)
פאזה 3 של פיצ'ר השליחים המקושרים — הוספת שכבת Person גלובלית מעל ל-Driver.
פרטים נוספים ↓הסתר ↑
פאזה 3 של פיצ'ר השליחים המקושרים — הוספת שכבת Person גלובלית מעל ל-Driver. Person הוא הזהות של אדם פיזי, חוצה-טננטים: באותו Person אפשר להחזיק כמה Driver records בטננטים שונים (אצל מספר חברות במקביל). זוהי תשתית — אין שינוי UX חשוף בפאזה זו. בפאזה זו כל Driver מקבל Person משלו (1:1), בלי קיבוץ אוטומטי לפי טלפון. הקישור המפורש (אותו Person בכמה טננטים) יקרה רק דרך invite flow ידני בפאזה 4 — אנו לא מרכזים drivers אוטומטית כי false-match יכול לדלוף נתונים בין טננטים. נוסף גם canonicalPhone (צורה מנורמלת ב-972 prefix) שמאוחר יותר ישמש לחיפוש Person קיים בעת invite. backfill לכל 354 ה-drivers בייצור הושלם, ולכל driver חדש (גם דרך POST API, גם דרך sync של Lionwheel, גם דרך flow של 'שליח מזדמן') נוצר Person אוטומטית. תאימות לאחור מלאה — שום API קיים לא מחזיר/דורש personId, פשוט קיים ברקע.
- Person model חדש: id, phone (raw), canonical_phone (לחיפוש), display_name, drivers (1:N). אין unique על טלפון כדי לא לדרוס backfill בכפילויות.
- Driver.personId nullable + FK ל-Person בלי CASCADE (לעולם לא מוחקים drivers בעקבות מחיקת Person).
- Backfill script scripts/backfill-persons.ts עם dry-run + --apply. הופעל בייצור על 354 drivers בכל הטננטים — לכל אחד נוצר Person חדש משלו עם canonicalPhone מנורמל.
- lib/person.ts עם canonicalizePhone (קוד משותף עם פורמט WhatsApp) + createPersonForNewDriver + ensurePersonForExistingDriver.
- כל מסלולי יצירת Driver מטמיעים אוטומטית Person: POST /api/drivers (3 branches: EMPLOYEE קיים, EMPLOYEE חדש, CONTRACTOR/EXTERNAL), POST /api/drivers/sync-all (sync מ-Lionwheel), lib/driver-sync.ts (webhook flow — 2 paths), lib/casual-courier.ts (provisioning שליח מזדמן).
- 11 בדיקות חדשות ל-Person helpers (canonicalizePhone, createPersonForNewDriver, ensurePersonForExistingDriver). סה״כ 854/854 עוברות.
- Phase 4 הבאה: invite flow — טננט מזמין שליח לפי טלפון → אם canonicalPhone תואם Person קיים, מציעים לקשר במקום ליצור חדש.
v01.48.000חדשdrivers/linkedminorשליחים מקושרים — פאזה 2: UI מנהל-טננט מלא
פאזה 2 של פיצ'ר השליחים המקושרים — UI מלא לטננט לניהול קבלן-מנהל ↔ סאב-שליחים, על-גבי תשתית הסכמה והמנוע שנבנו בפאזה 1.
פרטים נוספים ↓הסתר ↑
פאזה 2 של פיצ'ר השליחים המקושרים — UI מלא לטננט לניהול קבלן-מנהל ↔ סאב-שליחים, על-גבי תשתית הסכמה והמנוע שנבנו בפאזה 1. כולל 3 commits בנפרד (2A backend APIs, 2B manager-side UI, 2C list polish) שיחד נותנים cycle UX מלא: אדמין מפעיל toggle 'קבלן-מנהל' בעריכת השליח → קופצת בעמוד הפרטים סקציית 'סאב-שליחים' (גלויה רק למנהלים) שמאפשרת להוסיף סאב מתוך השליחים הקיימים, להגדיר תמחור נפרד פר-קישור, ולהסיר (soft-delete חסום ע"י משלוחים פעילים). שיבוץ משלוח לשליח רגיל / מנהל / סאב מציב אוטומטית את Visit.managedByDriverId הנכון. הדוח החודשי של המנהל עובר לחישוב המאוחד (כל הצוות) עם פירוט פר-סאב לביקורת. ברשימת השליחים — סמל כתר על מנהלים ו-badge 'תחת [שם]' על סאבים. לא נוגעים בהתנהגות של טננטים שלא הפעילו את ה-feature — שום שינוי בחישובי שכר קיימים, שום שינוי בעמודים שאינם של מנהלים.
- Backend APIs (פאזה 2A): GET/POST /api/drivers/[id]/sub-drivers, GET/DELETE /api/drivers/[id]/sub-drivers/[linkId], GET/PUT /api/drivers/[id]/sub-drivers/[linkId]/pricing. כולם tenant-scoped עם DRIVERS_VIEW/DRIVERS_EDIT permission.
- helper חדש lib/driver-assignment.ts → resolveManagedByDriverId(): קובע את Visit.managedByDriverId לפי הקשר השליח (מנהל / סאב יחיד / סאב מרובה / עצמאי). מוטמע גם ב-/api/shipments/bulk-assign-driver וגם ב-/api/v1/mobile/admin/visits/[id]/assign.
- DriverForm: switch סגול 'קבלן-מנהל' בעריכה (לא ביצירה — נדרש שהשליח כבר קיים כדי להוסיף לו סאבים).
- Driver detail: SubDriversSection חדש (מוסתר אם לא מנהל) עם הוספה רב-בחירה (AddSubDriverDialog), תמחור פר-קישור (SubDriverPricingDialog), הסרה עם AlertDialog ו-409 guard למשלוחים פעילים.
- EarningsCard: כשהשליח הוא מנהל, /api/drivers/[id]/earnings מחליף ל-computeManagerTenantEarnings עם includeSubBreakdown=true — וכרטיס חדש סגול בכרטיסיה מציג פירוט פר-סאב לביקורת.
- רשימת שליחים: כתר סגול על שליחים שהם מנהלים, badge 'תחת [שם]' על סאבים (עם +N אם תחת כמה מנהלים). /api/drivers/list מחזיר עכשיו גם subLinks.
- ההסרה של סאב היא soft-delete (isActive=false + removedAt) — היסטוריה נשמרת, ביקורים שכבר רצים נסגרים נורמלי. הסרה חסומה אם יש visit פתוח תחת המנהל הזה.
- תאימות לאחור מלאה — טננט שלא הפעיל אף toggle 'קבלן-מנהל' חווה אפס שינוי. resolveManagedByDriverId מחזיר null במקרה הזה ו-Visit.managedByDriverId נשאר NULL כמו שהיה.
- 843 בדיקות עוברות (כולל 7 חדשות ל-resolveManagedByDriverId), typecheck נקי, lint נקי.
v01.47.000חדשshipments/importminorאשף ייבוא משלוחים מאוחד — צוות, פורטל לקוחות וסוכנים
אשף ייבוא המשלוחים פועל כעת באופן זהה עבור כל סוגי המשתמשים: צוות הטננט (/shipments/import), לקוח בפורטל (/portal/shipments/import) וסוכן (/shipments/import).
פרטים נוספים ↓הסתר ↑
אשף ייבוא המשלוחים פועל כעת באופן זהה עבור כל סוגי המשתמשים: צוות הטננט (/shipments/import), לקוח בפורטל (/portal/shipments/import) וסוכן (/shipments/import). אותה לוגיקה של פירוק קובץ, מיפוי עמודות מבוסס AI, תיקון שורות בעייתיות באמצעות AI, זיהוי כפילויות, ולידציה, ייבוא בזרם NDJSON ועדכון היסטוריה — בלי שום סניף קוד לכל role. בורר הלקוחות בכל מסך שואב את הלקוחות הרלוונטיים ל-session: צוות רואה הכל, סוכן רואה רק לקוחות עם Customer.agentId שלו, ולקוח פורטל רואה רק את עצמו (או את החשבונות המקושרים שלו).
- הרשאת SHIPMENTS_CREATE נוספה לתפקיד AGENT (כדי שה-POST של הייבוא והאשף עצמו ירוצו). כל שאר ההרשאות לתפקיד נשארו כשהיו.
- פריט סיידבר חדש 'ייבוא משלוחים' מתחת למשלוחים, מוצג רק לסוכנים (כי הסיידבר שלהם flat).
- הגנה בצד השרת: POST /api/shipments/import מאמת ש-customer_id שייך לסוכן (Customer.agentId === session.agentId) ומחזיר 403 אם לא — גם אם הלקוח עצמו תקין בטננט. מונע יצירת ייבוא דרך בקשה מזויפת מחוץ לאשף.
- scoping של היסטוריית ייבוא: GET/PATCH /api/shipments/import/history[/id] ו-/download מסננים ל-customerId IN (לקוחות הסוכן). סוכן רואה ומוריד רק את הייבואים של הלקוחות שלו.
- Helper חדש lib/auth/agent-scope.ts המרכז את הלוגיקה של 'מי הלקוחות של הסוכן הנוכחי' — כדי שכל endpoint עתידי שצריך הגבלה דומה ישתמש באותו דפוס.
- AI map / AI fix עבור הפורטל: עד עכשיו ה-client היה צורב נתיבי /api/shipments/import/ai-{map,fix} בקוד, ולקוחות פורטל לא יכלו להגיע אליהם (middleware חוסם CUSTOMER session מ-routes שמחוץ ל-/api/portal). נוספו /api/portal/shipments/import/ai-map ו-ai-fix — wrappers דקים על אותם lib/ai/import-column-mapper ו-import-row-fixer, מאומתים דרך requireCustomerPermission(CREATE_SHIPMENTS) במקום RBAC של הצוות. הקיימים תחת /api/shipments/import/ai-{map,fix} נשארו כפי שהיו עבור הצוות והסוכנים.
- ImportShipmentsConfig מקבל כעת aiMapEndpoint ו-aiFixEndpoint כך שה-client יודע באיזה pair endpoints להשתמש לפי ה-config שמועבר אליו. כל הנתיבים הצרובים הוסרו מהאשף.
- ה-POST של ה-ייבוא עצמו (שורת הזרם, עבודת ה-workers, פתיחת ה-audit row, סגירת הסטטוס, האירוע 'done') חולץ ל-lib/shipments/run-bulk-import.ts. שני ה-routes (/api/shipments/import ו-/api/portal/shipments/import) הפכו ל-wrappers דקים של כ-90 שורות שעושים רק auth, אימות שהלקוח שייך ל-actor (AGENT.agentId / linked group של הפורטל) וקריאה ל-runBulkImport. שינוי עתידי ב'איך ייבוא רץ' (concurrency, מבנה האירועים, התנהגות duplicates) נופל בקובץ אחד ומשפיע על שלושת הקהלים יחד.
- בדומה, check-duplicates חולץ ל-lib/shipments/find-import-duplicates.ts (כולל normalizeExternalIds המשותף) ושני ה-routes הפכו ל-wrappers; ההבדל היחיד הוא ה-customerIdScope שעובר (null לצוות, רשימת לקוחות מקושרים לפורטל).
v01.46.001תיקוןshipments/importייבוא משלוחים — אות כניסה אחרי המספר + זיהוי עיר לפי תחילית
שני תיקונים לזיהוי כתובות בקבצים ללא עמודות מובנות: (1) אות עברית בודדת אחרי המספר (כניסה/אגף) כמו 'ראובן 12/6 ב'' או 'גוש עציון 2/9 א' שברה את זיהוי מספר הבית והדירה — parseAddress מזהה כעת מספר=12, דירה=6 ואת האות כ'כנ…
פרטים נוספים ↓הסתר ↑
שני תיקונים לזיהוי כתובות בקבצים ללא עמודות מובנות: (1) אות עברית בודדת אחרי המספר (כניסה/אגף) כמו 'ראובן 12/6 ב'' או 'גוש עציון 2/9 א' שברה את זיהוי מספר הבית והדירה — parseAddress מזהה כעת מספר=12, דירה=6 ואת האות כ'כניסה', בלי לפגוע במקרים קיימים. (2) שם יישוב מקוצר/עם מקף כמו 'מודיעין-מכבים' לא זוהה כי במילון השם המלא הוא 'מודיעין מכבים רעות' — findCityMatch מקבל כעת התאמת תחילית רב-מילתית, אך ורק כשיש התאמה יחידה וחד-משמעית (שם בן מילה אחת לא מפעיל זאת, ותחילית של חצי-מילה לא נחשבת). דוגמאות שתוקנו: 'עמק חרוד 28 מודיעין-מכבים', 'מגדל הלבנון 26/5 מודיעין-מכבים', 'גוש עציון 2/9 א גבעת שמואל'. נוספו 8 בדיקות יחידה (סה"כ 91).
v01.46.000חדשdrivers/linkedminorשליחים מקושרים — פאזה 1: סכמה ומנוע חישוב (תשתית)
פאזה ראשונה (תשתית בלבד; ללא UI חשוף) של פיצ'ר שליחים מקושרים — קבלן-מנהל שמנהל סאב-שליחים, עם תמחור נפרד פר-קישור (מה הטננט משלם למנהל מול מה המנהל משלם לסאב).
פרטים נוספים ↓הסתר ↑
פאזה ראשונה (תשתית בלבד; ללא UI חשוף) של פיצ'ר שליחים מקושרים — קבלן-מנהל שמנהל סאב-שליחים, עם תמחור נפרד פר-קישור (מה הטננט משלם למנהל מול מה המנהל משלם לסאב). נוספו 4 טבלאות חדשות (DriverManagerLink וטבלאות תמחור פר-קישור) ושדות isManagerEnabled על Driver, managedByDriverId על Visit וב-CodTracking — כולם nullable/ברירת-מחדל בטוחה כך ששום נתון קיים לא נוגע ושום חישוב משכורת קיים לא משתנה. מנוע החישוב driver-earnings.ts עבר refactor פנימי: הליבה (resolveRate, applyRules, group business pickup, rollup) חולצה ל-helpers משותפים; הפונקציה הקיימת computeDriverEarnings שומרת את החתימה וההתנהגות הקודמות בדיוק; נוספו שתי פונקציות חדשות — computeManagerTenantEarnings (טננט→מנהל, אגרגציה של כל ה-visits שתחת המנהל ע"י פילטר על managedByDriverId, עם אופציית per-sub breakdown לביקורת) ו-computeManagerSubPayout (מנהל→סאב, משתמש במחירון הפר-קישור). נכתבו 54 בדיקות חדשות (29 characterization שמלכדות את ההתנהגות הקיימת + 25 לפונקציות החדשות). כל 824 הבדיקות עוברות, typecheck נקי, lint נקי. סך הכל פאזה זו אחת מתוך 7 — הפאזות הבאות יוסיפו UI לטננט, שכבת Person גלובלית (לתמיכה בשליח חוצה-טננטים), invite flow ועוד.
- סכמת DB: DriverManagerLink (N:N) + DriverLinkPricingProfile + DriverLinkZoneRate + DriverLinkPricingRule. תאימות לאחור מלאה — אין שינוי בכמות הביקורים/חישובים הקיימים.
- Driver.isManagerEnabled — toggle של אדמין שמסמן שליח כקבלן-מנהל היכול לנהל סאבים. ברירת מחדל false.
- Visit.managedByDriverId + CodTracking.managedByDriverId — מי אחראי כספית מול הטננט, כך שאפשר לעבוד עם תרחישים שבהם הסאב מבצע אבל המנהל מקבל את התשלום.
- מנוע חישוב: חילוץ ליבה ל-computeEarningsLines/rollupTotals; computeDriverEarnings נשארת בדיוק כפי שהיא.
- computeManagerTenantEarnings — מחשב את התשלום שטננט חייב למנהל, מאגד את כל הביקורים תחת המנהל (גם של המנהל עצמו וגם של הסאבים שלו), משתמש בפרופיל המנהל. תומך ב-includeSubBreakdown לפירוט פר-סאב.
- computeManagerSubPayout — מחשב כמה המנהל חייב לסאב ספציפי לפי מחירון הקישור (לא מחירון הסאב!), עם guard חוצה-טננטים שמסרב לחשב אם הקישור בטננט אחר.
- Phase 2 הבאה: UI לטננט (תיוג סאבים, סינון שיבוץ, breakdown בדוח הסטטוס).
v01.45.003תיקוןshipments/importייבוא משלוחים — זיהוי עיר בפורמטים נוספים (פסיקים ותווית דירה)
הורחבה שליפת העיר מתוך הכתובת (בקבצים ללא עמודת עיר) כדי לכסות עוד דפוסים מהשטח שזוהו בקובץ רשימת המתנה: (1) פורמט 'רחוב , עיר, מספר' — כשהמקטע האחרון אחרי פסיק הוא מספר בלבד, העיר היא המקטע שלפניו ("איזנברג , רחובות, 26…
פרטים נוספים ↓הסתר ↑
הורחבה שליפת העיר מתוך הכתובת (בקבצים ללא עמודת עיר) כדי לכסות עוד דפוסים מהשטח שזוהו בקובץ רשימת המתנה: (1) פורמט 'רחוב , עיר, מספר' — כשהמקטע האחרון אחרי פסיק הוא מספר בלבד, העיר היא המקטע שלפניו ("איזנברג , רחובות, 26" → רחובות). (2) פורמט 'עיר , רחוב מספר' — עיר ראשונה ("רהט , אלג׳זאר 13" → רהט), עם הגנה שמונעת בלבול בין רחוב לעיר. (3) תווית 'דירה N' אחרי העיר — עוגן-המספר מתעלם כעת ממספרי דירה/קומה, כך ש"לבונטין 32 ראשון לציון דירה 5" מזהה ראשון לציון ושומר את דירה 5 בכתובת. כל מועמד עדיין מאומת מול מילון היישובים, ושם-עיר שמופיע ברחוב לא נשלף בטעות. נוספו 12 בדיקות יחידה (סה"כ 80), כולל בדיקות הגנה ("רחוב, קומה 2" לא מחלץ עיר).
v01.45.002תיקוןshipments/importייבוא משלוחים — זיהוי עיר מתוך הכתובת (תיקון closure + עיגון למספר)
שליפת העיר מתוך הכתובת (בקבצים ללא עמודת עיר) לא עבדה בפועל: הפונקציה handleFile היא useCallback שנוצר פעם אחת ב-mount, ולכן ה-closure שלה על רשימת היישובים נשאר [] לתמיד — והתנאי settlements.length>0 תמיד נכשל.
פרטים נוספים ↓הסתר ↑
שליפת העיר מתוך הכתובת (בקבצים ללא עמודת עיר) לא עבדה בפועל: הפונקציה handleFile היא useCallback שנוצר פעם אחת ב-mount, ולכן ה-closure שלה על רשימת היישובים נשאר [] לתמיד — והתנאי settlements.length>0 תמיד נכשל. תוקן באמצעות settlementsRef שמחזיק את הרשימה החיה. בנוסף, splitTrailingCity שודרגה לפי החוקיות שהעיר תמיד מופיעה אחרי מספרי הכתובת: נוסף עוגן-מספר שלוקח כמועמד-עיר את כל מה שמופיע אחרי הטוקן האחרון שמכיל ספרה (תוך דילוג על אות-דירה כמו "ב'"), עם וללא פסיק. כל מועמד עדיין מאומת מול מילון היישובים — לכן לא נשלף דבר שאינו עיר אמיתית, ושם-עיר שמופיע ברחוב (לפני המספר) לא נחשב בטעות לעיר. דוגמאות שנתמכות כעת: "הבנים 10/5 אשדוד", "ראובן 12/6 ב' , בית שמש", "נחל קטלב 15/5 בית שמש". נוספו 13 בדיקות יחידה (סה"כ 73).
v01.45.001תיקוןshipments/importייבוא משלוחים — חיפוש לקוח מדויק (במקום fuzzy)
החיפוש בבורר הלקוח (וגם בבורר כתובת שמורה) בזרימת ייבוא המשלוחים השתמש במנגנון ה-fuzzy הדיפולטי של cmdk, שמותאם לאנגלית ובעברית התנהג גרוע: הקלדת חלק ממילה ("הילו") החזירה שמות לא-קשורים שבהם האותיות פזורות לאורך הטקסט, …
פרטים נוספים ↓הסתר ↑
החיפוש בבורר הלקוח (וגם בבורר כתובת שמורה) בזרימת ייבוא המשלוחים השתמש במנגנון ה-fuzzy הדיפולטי של cmdk, שמותאם לאנגלית ובעברית התנהג גרוע: הקלדת חלק ממילה ("הילו") החזירה שמות לא-קשורים שבהם האותיות פזורות לאורך הטקסט, בעוד שההתאמה המדויקת ("הילולה") לא דורגה למעלה עד שהוקלדה המילה במלואה. הוחלף בפילטר substring שמדרג לפי רלוונטיות: התאמת תחילית מלאה > מילה שמתחילה במחרוזת > הכלה כלשהי > מוסתר. הפילטר אדיש לסוג הגרש/מירכאות (בע"מ / בע״מ) ולאותיות גדולות/קטנות. שינוי תוסף-בלבד — כל חיפוש של רצף תווים רציף שעבד קודם ממשיך לעבוד; רק רעש הרצף-המפוזר נעלם. נוספו 10 בדיקות יחידה.
v01.45.000שיפורshipments/importminorייבוא משלוחים — תמיכה בקבצי WooCommerce, רשימות מתנה וכתובות מורכבות
מנגנון ייבוא המשלוחים הורחב משמעותית כדי לקלוט קבצים אמיתיים מהשטח שעד היום נכשלו, מבלי לשנות את ההתנהגות עבור התבנית הרגילה.
פרטים נוספים ↓הסתר ↑
מנגנון ייבוא המשלוחים הורחב משמעותית כדי לקלוט קבצים אמיתיים מהשטח שעד היום נכשלו, מבלי לשנות את ההתנהגות עבור התבנית הרגילה. מזוהות אוטומטית כותרות של ייצוא WooCommerce ושל רשימות מתנה/קהילה, כתובת חופשית מפוצלת לרחוב/מספר/קומה/דירה/כניסה, שורת הכותרת מאותרת גם כשהיא לא בשורה הראשונה, עיר נשלפת מתוך הכתובת כשאין עמודת עיר, ועמודת מספר סידורי מזוהה ולא מוחלפת במספר הבית. כל ההיוריסטיקות החדשות מגודרות כך שהן פועלות רק כשאין עמודה ייעודית — תבנית רגילה עוברת ללא כל שינוי.
- זיהוי כותרות WooCommerce ((Billing)/(Shipping)) + Customer Note, וכותרות רשימת מתנה (פרטי / משפחה / נייד / כתובת מגורים / הערות / כמות).
- parseAddress — פיצול כתובת חופשית לרחוב/מספר/קומה/דירה/כניסה: מספר בעקבות רחוב, מספר/דירה (4/4), חלקים בפסיקים, סדר הפוך ("6 התחדשות"), אנגלית ("8 Shamgar Street, 44"), ותוויות עברית (קומה/דירה/בניין/כניסה). תאימות מלאה לפרסר הישן כולל סיומת לטינית ("10A").
- detectHeaderRowIndex — איתור שורת הכותרת גם כשקודמות לה שורות כותרת/ריקות (נפילה בטוחה לשורה 0 לתבנית רגילה).
- splitTrailingCity — שליפת יישוב מוכר מסוף הכתובת כשאין עמודת עיר ("השקד 7 מודיעין" → עיר מודיעין). פועל רק ללא עמודת עיר, ולעולם לא צורך את כל המחרוזת.
- isSerialCounterColumn — זיהוי עמודת מספר סידורי (1,2,3…) שלא תחליף את מספר הבית האמיתי. מגודר להרצה רק לצד עמודת כתובת ועל רצף אורדינלי כמעט-מושלם.
- השינוי תוסף-בלבד ומגודר: כל היוריסטיקה חדשה פועלת רק בהיעדר עמודה ייעודית. נוספו 49 בדיקות יחידה (כולל בדיקות אי-רגרסיה לפרסר הישן).
v01.44.004חדשmobile authהתחברות עם גוגל באפליקציית השליחים
כפתור 'המשך עם Google' בדף הכניסה של אפליקציית המובייל הופעל.
פרטים נוספים ↓הסתר ↑
כפתור 'המשך עם Google' בדף הכניסה של אפליקציית המובייל הופעל. ה-idToken מגוגל מאומת בצד השרת מול tokeninfo API, ולאחר מכן מונפקים JWT tokens רגילים — זרימת האימות זהה להתחברות ע"י אימייל/סיסמה.
v01.44.003חדשlanding page, marketingאתר תדמית — דף נחיתה ל-shipnest.io
דף הבית (/) הפך לאתר תדמית מקצועי במקום ריידיירקט ישיר לאפליקציה.
פרטים נוספים ↓הסתר ↑
דף הבית (/) הפך לאתר תדמית מקצועי במקום ריידיירקט ישיר לאפליקציה. הדף כולל: Hero עם דשבורד מדומה ואנימציות, סקציית פיצ'רים, סטטיסטיקות, תמחור (3 מסלולים), חוות דעת לקוחות, CTA ו-Footer. עיצוב Midnight Neon — כהה עם אקסנט סגול/ציאן.
v01.44.002תיקוןshipments/picking, warehouse/inbound, analytics, messaging, customers, webhooks, recycle-binתיקון: 'הסר מליקוט' מציג הודעת שגיאה כשפעולה לא בוצעה
תוקן: בכל נקודות הקוד שקוראות ל-/api/picking/remove — בדף פרטי משלוח (שני מקומות), בתפריט פעולות ליקוט ובסרגל הפעולות הקבוצתיות — הקוד בודק כעת את removedCount בתגובת ה-API.
פרטים נוספים ↓הסתר ↑
תוקן: בכל נקודות הקוד שקוראות ל-/api/picking/remove — בדף פרטי משלוח (שני מקומות), בתפריט פעולות ליקוט ובסרגל הפעולות הקבוצתיות — הקוד בודק כעת את removedCount בתגובת ה-API. אם removedCount=0 (המשלוח לא נמצא ב-pending_picking), מוצגת הודעת שגיאה במקום הודעת הצלחה. כמו כן: ה-Prisma client עודכן (pnpm generate) — endpoint /api/warehouse/inbound החזיר HTTP 500 בגלל enum WhInboundStatus שחסר מהקליינט הישן. שיפורי ביצועים: נוספו 5 אינדקסים חסרים ל-analytics (regionCode, destinationCity, sourceProvider, urgency ו-covering index לraw SQL). נוסף Redis cache ל-analytics routes (TTL 5 דקות). שליחת WhatsApp מהירה ×100 — credentials מבוצעים פעם אחת ל-5 דקות (ביטול PBKDF2 חוזר). חיפוש לקוח לפי טלפון עבר מ-O(N) ל-O(1) — עמודת phone_normalized עם index. dispatch-webhooks נוסף ל-cron schedule (*/2). הפחתת delay בין הודעות WhatsApp מ-2000ms ל-500ms. הגדלת batch שליחת הודעות מ-10 ל-50 לתמיכה בטנאנטים עם עומסי שליחה גבוהים. נוספה מדיניות שמירה של 6 חודשים לסל המיחזור — cron יומי מוחק לצמיתות משלוחים שנמחקו לפני יותר מ-6 חודשים (ב-batches של 200), ה-UI מציג הודעה מתאימה.
v01.44.001שיפורshipments/table, layout/header, shipments/pickingאישור לפני שכפול משלוח — יחיד ומרובה
נוסף דיאלוג אישור מעוצב לפני כל פעולת שכפול משלוח: גם בשכפול משלוח יחיד (תפריט שורה) וגם בשכפול מרובה (סרגל פעולות בחירה).
פרטים נוספים ↓הסתר ↑
נוסף דיאלוג אישור מעוצב לפני כל פעולת שכפול משלוח: גם בשכפול משלוח יחיד (תפריט שורה) וגם בשכפול מרובה (סרגל פעולות בחירה). הדיאלוג מציין כמה משלוחים יישכפלו ומבקש אישור מפורש לפני הביצוע. כמו כן, האייקונים בסרגל העליון צופפו במובייל: כפתור מסך-מלא מוסתר, גודל אייקונים h-8 במובייל, ורווח מצומצם — לאפשר לשורת החיפוש הגלובלי מספיק מקום. תוקן: האפשרות 'הסר מליקוט' בתפריט הסטטוס מוסתרת עבור משלוחים בסטטוס נלקט (API תומך רק ב-pending_picking).
v01.44.000חדשwarehouse/3pl, warehouse/billing, db/schemaminorמחסן 3PL — פאזה 5: חיוב חודשי (אחסון + ליקוט + קליטה)
פאזה 5 וגם הפאזה הסוגרת של תכנית ה-3PL: השכבה הכספית.
פרטים נוספים ↓הסתר ↑
פאזה 5 וגם הפאזה הסוגרת של תכנית ה-3PL: השכבה הכספית. הטננט מגדיר תעריפים ללקוח (אחסון ליחידה ליום, ליקוט ליחידה, קליטה ליחידה); המערכת רושמת אירוע חיוב לכל ליקוט וקליטה אוטומטית, ו-cron יומי כותב snapshot של כמות הסחורה במלאי × תעריף האחסון. דוח חודשי מציג סיכום וכלל אירועי החיוב פר-לקוח. כל אירוע מקובע ב-unitRate שהיה תקף ברגע הרישום, כך ששינוי תעריף בעתיד לא משנה אירועים היסטוריים.
- schema: שני מודלים חדשים — WhBillingRate (per-customer, effective_from/to, decimal(10,4) לכל תעריף) ו-WhBillingEvent (immutable: type/quantity/unitRate/amount, אינדקסים [tenantId, customerId, occurredAt] ו-[tenantId, customerId, type, occurredAt] לדוחות מהירים). enum חדש WhBillingEventType: STORAGE_DAILY / PICK / RECEIVE.
- helper מרכזי lib/warehouse/billing.ts עם findActiveRate (החזרת התעריף התקף בנקודת זמן), createPickEvent, createReceiveEvent, ו-createStorageDailySnapshot. כל פונקציה fire-and-forget: catch בלוקאל, log לשגיאה, וחזרה null במקום לזרוק — כך שכישלון חיוב לעולם לא ישבור פעולה תפעולית.
- endpoints: GET/POST /api/warehouse/billing/rates (יצירת תעריף חדש סוגרת אוטומטית תעריף קודם פעיל באותו תאריך התחלה), GET /api/warehouse/billing/report (סיכום by-type לטווח תאריכים + רשימת events). הרשאות: WAREHOUSE_BILLING_VIEW לקריאה, WAREHOUSE_BILLING_MANAGE לכתיבת תעריפים (שתיהן הוגדרו בפאזה 0).
- hooks: pick-tasks/[id] confirmPick מפעיל createPickEvent, ו-inbound/[id]/receive מפעיל createReceiveEvent לכל פריט שנקלט. שניהם רצים אחרי כל ה-validation והעדכונים — אם נכשל, האירוע התפעולי נשמר אבל אין חיוב (נראה בלוג).
- cron יומי /api/cron/warehouse-billing-storage-snapshot ב-02:00 — סורק את כל ה-rates הפעילים, ועבור כל לקוח: סוכם sum(WhInventory.quantity) במיקומים של הטננט (location.ownerCustomerId IS NULL) שבהם המוצרים שייכים ללקוח. idempotent: אם כבר נכתב event STORAGE_DAILY לאותו (tenant, customer, day) — מדלג.
- UI: /warehouse/billing — דשבורד עם בוררי לקוח + חודש, 4 summary cards (אחסון/ליקוט/קליטה/סך הכל), תעריף פעיל מוצג בכרטיס נפרד, וטבלת events מפורטת. הוסף קישור 'חיוב 3PL' לסיידבר (DollarSignIcon, גלוי למי שיש WAREHOUSE_BILLING_VIEW).
- BillingRateDialog — טופס יצירת תעריף עם בורר לקוח, 3 שדות תעריף (אחסון/ליקוט/קליטה) ב-decimal(10,4), ובורר תחילת תוקף.
- פורטל לקוח: הדוח (/api/warehouse/billing/report) נגיש גם למשתמשי פורטל — מוצמד אוטומטית ל-customerId שלהם. (UI בפורטל יבוא בעתיד אם יהיה צורך.)
- vercel.json: cron חדש הוסף לרשימה. הצבת השעה ב-02:00 IL בכוונה — מאוחר מספיק שכל activity של היום סוכם, וגם מוקדם מספיק לפני שעות העבודה.
- סך הכל פאזה 5 סוגרת את כל 7 הפאזות של תכנית ה-3PL. הזרם המלא מסחורה ועד חיוב פועל end-to-end: לקוח שולח מלאי → קליטה (RECEIVE event) → אחסון יומי (STORAGE_DAILY events) → הזמנה מ-Shopify → ליקוט (PICK event) → דוח חודשי מסכם הכל.
v01.43.001שיפורcustomers/portal-users, warehouse/3pl, shipments/3pl, db/schema, shared/alertsפורטל לקוחות — איפוס חשבון בעלים במקום מחיקה
במסך משתמשי פורטל הלקוח, כפתור המחיקה (🗑️) לבעלים הוחלף בכפתור 'אפס חשבון' (↺).
פרטים נוספים ↓הסתר ↑
במסך משתמשי פורטל הלקוח, כפתור המחיקה (🗑️) לבעלים הוחלף בכפתור 'אפס חשבון' (↺). הסיבה: בעלים לא ניתן באמת למחוק — ה-GET של /api/customers/[id]/users מפעיל auto-provision מחדש מאימייל הלקוח, ולכן מחיקה רק יוצרת אותו מחדש מאפס. עכשיו הפעולה מפורשת: היא מנקה passwordHash, googleId, lastLoginAt ו-inviteAcceptedAt, מחזירה ל-PENDING ויוצרת inviteToken חדש ושולחת מייל הזמנה — שורת ה-CustomerUser עצמה נשמרת (כולל createdAt ומי הזמין). עבור משתמשים שאינם בעלים — כפתור המחיקה נשאר כפי שהיה. נוסף endpoint POST /api/customers/[id]/users/[userId]/reset (CUSTOMERS_EDIT, fails-closed עם 400 אם המשתמש לא owner-grade). שלושה ניקויים בכרטיס היעד: (א) איקון קוד כניסה — היה אמבר/כתום כדי להבליט לשליחים, סודר לאפור נייטרלי בעקבות הסימטריה החדשה עם שאר השדות. (ב) הוסרו כפתורי "העתק מספר" שהיו ליד כל טלפון — כפילות מיותרת כי יש העתקה כללית של כל הכרטיס בכפתור העליון. (ג) כפתור "+ הוסף טלפון" שהיה תופס שורה נפרדת מתחת לרשימת הטלפונים, הועבר ל-IconButton קטן (+) בצד הימני של השורה ליד הטלפונים — לא תופס שורה נוספת. (2) מחסן 3PL — פאזה 4a (התשתית לקישור משלוח↔מלאי): נוספו שני שדות חדשים ל-schema שמגשרים בין מודול ה-3PL למודול המשלוחים. (א) Shipment.pickMode VARCHAR(20) — שדה אופציונלי שמסמן את מצב הליקוט של משלוח: 'TENANT' (הטננט מלקט מהמלאי שמאוחסן אצלו), 'SELF' (הלקוח מלקט בעצמו), או null (לא רלוונטי לזרם 3PL — ברירת המחדל). אינדקס חדש [tenantId, pickMode] לתמיכה ב"מה ממתין לליקוט אצלי" בעתיד. (ב) OrderItem.whProductId TEXT עם FK ל-WhProduct (onDelete: SetNull) — מקשר line item של משלוח למוצר מזוהה בקטלוג המחסן. אופציונלי כדי לא לשבור משלוחים שאינם 3PL; כאשר pickMode=TENANT, הקישור הזה הוא מה שמאפשר ל-picker לדעת איזה מוצר במלאי לקחת. ב-API: PATCH /api/shipments/[id] מקבל את pickMode (TENANT/SELF/null) ב-schema הקיים, ו-FIELD_LABELS עודכן לתיעוד activity log. ב-UI: בסקציית הליקוט בעמוד פרטי המשלוח נוסף dropdown 'מצב 3PL' עם 3 ערכים, ליד הבוררים הקיימים של pickingType ו-pickingCategory. הזרם הקיים תואם לאחור — משלוחים ללא pickMode פשוט מציגים 'לא רלוונטי'. מה שטרם הוטמע: מימוש adapter לסנכרון אוטומטי של pickMode מ-Shopify/Woo, ועריכה של OrderItem.whProductId דרך UI (כרגע ניתן רק דרך API). זה יבוא בפאזה 4b. נוסף סטטוס חדש לגוביינא: "בוטלה" (CANCELED). ההגיון הקיים שמ-PENDING אי אפשר לשנות סטטוס ידנית (כדי שלא יסמנו "בידי השליח" לפני שהמשלוח באמת נמסר) נשמר — אבל יש עכשיו חריג אחד: ניתן לשנות מ-PENDING ל-CANCELED. ב-UI: כשהסטטוס PENDING, ה-dropdown מציג רק "בוטלה" כאופציה; בשאר הסטטוסים — "בוטלה" נוסף לרשימה הרגילה. CANCELED הוא final + settled (לא ניתן להמשיך ממנו, ולא מופיע ברשימת ה-open). מקרי שימוש: משלוח שבוטל לפני שיצא — הגוביינא נסגרת ללא גבייה. (4) מחסן 3PL — פאזה 4b (סוגרת את הלולאה ייבוא→ליקוט): השלמה של פאזה 4a בכמה דרכים. (א) Adapter — lib/warehouse/order-import.ts: כל הזמנה שמיובאת מ-Shopify/Woo דרך חיבור פר-לקוח מסומנת אוטומטית pickMode=TENANT (הטננט הוא ה-picker בכל הזרמים האלה — תואם גישה B). בנוסף, ה-line items מיוצאים עם whProductId מאוכלס לפי המיפוי שב-WhStoreProductLink, כך שה-picker בעמדת הליקוט יודע בדיוק איזה מוצר מהמלאי לקחת. SKUs שלא מקושרים נרשמים ב-WhStoreSyncLog (התנהגות קיימת) — אז הזרם נמשך כרגיל גם בלי הקישור. (ב) API — PUT /api/shipments/[id]/order-items מקבל עכשיו whProductId לכל פריט; ב-validate נאכף שבעלות המוצר המקושר תואמת ל-customerId של המשלוח (invariant: בעלים של ה-product = בעלים של ה-shipment — לא לערבב מוצרי לקוח X במשלוח של לקוח Y). מענה 422 כש-mismatch, 404 כש-product לא נמצא. (ג) GET /api/shipments/[id] מצרף את שדות whProduct (id/sku/name) לכל orderItem כדי שה-UI יוכל להציג שם מוצר ידידותי בלי קריאה נוספת. (ד) OrderItemsCard — כש-pickMode=TENANT, נוסף עמודה 'מוצר במחסן' עם dropdown שטוען את מוצרי הלקוח של המשלוח (דרך /api/warehouse/products?ownerCustomerId=...) ומאפשר קישור/ביטול קישור פר-פריט. במצב קריאה (canEdit=false) מציג badge עם SKU + שם. כש-pickMode != TENANT, העמודה מוסתרת לחלוטין כדי לא לעמיס על משלוחים שאינם 3PL. הזרם נשלם: הזמנה מ-Shopify → Shipment(pickMode=TENANT) + OrderItem(whProductId) → המלקט רואה את הקישור → מלקט מהמלאי במחסן. 702 tests עוברים, 0 lint errors. (5) תיקון התראת טעות-מיון: כש-Dialog/Drawer של Radix או Vaul פתוח, הם מגדירים pointer-events:none על ה-body — וה-overlay של ההתראה (z-9999) יורש את זה ולכן הלחצן 'סגור' לא הגיב והמשתמש היה חייב לרענן את העמוד ולאבד טופס באמצע עריכה. נוסף pointer-events-auto ל-overlays של SortingErrorAlertListener ו-ShipmentAlertListener (בשני המצבים — fullscreen ו-banner). (6) עמוד המעקב הציבורי של הלקוח (/tracking/[id]) — תוקנה הצגה מטעה של 'צפי מסירה' עם תאריך ושעה מתוך visit.visitAt, שגרמה למצבים שבהם משלוח בסטטוס 'בהעברה' (IN_TRANSFER, בין מחסנים) הראה ללקוח שהמשלוח יסופק היום ויצר ציפייה שגויה ותלונות. הוסרה תווית 'צפי מסירה' מסקציית 'יצא להפצה' בציר הזמן, ובמקומה נוסף כרטיס מובלט מתחת לתיאור הסטטוס: 'צפי הגעה משוער — עד <תאריך מקסימלי>' עם משנה-תיאור 'יעד רגיל — עד 3 ימי הפצה' או 'יעד חריג — עד 7 ימי הפצה' לפי deliveryType של היישוב (REGULAR/EXTENDED) מטבלת הישובים. החישוב משתמש ב-addBusinessDays(delayClockStartedAt ?? createdAt, 3|7) — נקודת ההתחלה היא תאריך הגורם (delay_clock_started_at) שנקבע במעבר ראשון לסטטוס פעיל, עם fallback ל-createdAt עבור משלוחים שטרם נכנסו לשרשרת. הצפי מוצג רק במשלוחים פתוחים (לא נמסר/נכשל/בוטל). חיפוש היישוב מתבצע מול Settlement (case-insensitive) עם נפילה ל-SettlementAlias; כשהיישוב לא מוכר נופלים בברירת מחדל ל-EXTENDED (7 ימים) — fail-safe כדי לא להבטיח ללקוח מועד מוקדם מדי. API endpoint /api/public/shipments/[publicId]/tracking הורחב להחזיר estimatedArrivalBy ו-estimatedDeliveryDays. (7) באותו עמוד מעקב, סטטוס IN_TRANSFER הוחלף מנקודת מבט הנמען מ"יצא להפצה" ל"במרכז המיון": IN_TRANSFER מסמן הברה בין מרכזי מיון *לפני* יציאה להפצה לאזור הלקוח, ולכן הצגתו כשלב 'יצא להפצה' (עם איקון משאית כחול) יצרה אצל הנמען ציפייה שהמשלוח כבר על משאית בדרך אליו. תוקן ב-STATUS_ACTIVE_STEP — IN_TRANSFER ממופה עכשיו לשלב 1 ('נקלט במרכז המיון') ולא לשלב 2; STATUS_LABEL הוחלף מ'בהעברה' ל'במרכז המיון'; STATUS_DESCRIPTION עודכן מ'החבילה בדרכה אליך דרך תחנת ביניים' ל'החבילה בתהליך מיון ומועברת בין מרכזי מיון לקראת היציאה להפצה'. גם תיאור IN_INVENTORY עודכן ל'החבילה במרכז המיון, בתהליך מיון לאזורך' (במקום 'מועברת לנציג ההפצה') כדי שלא יבטיח שלב הבא. השינוי קוסמטי לחלוטין בצד הלקוח — הסטטוס הפנימי במערכת ושאר הזרמים נשארים כפי שהיו.
v01.43.000חדשwarehouse/3pl, warehouse/inbound, db/schemaminorמחסן 3PL — פאזה 3: זרם קליטת סחורה רשמי (Inbound)
פאזה 3 של מודול ה-3PL מציגה לראשונה זרם קליטה רשמי לסחורת לקוחות פורטל.
פרטים נוספים ↓הסתר ↑
פאזה 3 של מודול ה-3PL מציגה לראשונה זרם קליטה רשמי לסחורת לקוחות פורטל. עד היום, הוספת מלאי על-שם לקוח הייתה רק דרך InventoryAdjustDialog (ad-hoc, ללא תיעוד שהסחורה הגיעה מהלקוח). עכשיו: הלקוח (או staff) יכול ליצור 'תעודת קליטה צפויה' מראש עם פירוט מוצרים וכמויות, ובהגעת הסחורה ה-staff מאשר קליטה פיזית ובוחר מיקום לכל פריט — והמערכת מעדכנת את ה-WhInventory אוטומטית. נוסף עמוד חדש /warehouse/inbound עם תיבת כניסה (פעילות / כל הסטטוסים / לפי סטטוס בודד), בורר scope (לקוח/הכל/טננט) למי שיש WAREHOUSE_MANAGE_CUSTOMER_DATA, ופעולות שורה: 'קלוט' / 'פרטים' / 'ביטול' (רק לפני קליטה).
- schema: שני מודלים חדשים WhInboundShipment + WhInboundShipmentItem עם enums WhInboundStatus (EXPECTED/PARTIAL/RECEIVED/CANCELLED) ו-WhInboundSource (CUSTOMER_PRENOTIFIED/TENANT_ADHOC). owner_customer_id NOT NULL כי קליטה תמיד שייכת ללקוח. אינדקסים לפי (tenant_id, owner_customer_id) ו-(tenant_id, status).
- endpoints: POST/GET /api/warehouse/inbound (יצירה + רשימה עם סיכום items+qty), GET/DELETE /api/warehouse/inbound/[id] (פרטים מלאים עם hydration של product/location, ביטול רק במצב EXPECTED), ו-POST /api/warehouse/inbound/[id]/receive שמבצע את הקליטה: מעדכן/יוצר WhInventory בתוך transaction, מעדכן status האב (PARTIAL/RECEIVED) לפי מה שנקלט בפועל, ופולט inventoryChangedEvents שמתפעלים סנכרון לחנויות מקושרות.
- ה-receive חוסם owner mismatch במיקום: אם כבר קיים מלאי באותו (location, product) עם בעלים אחר — 409. תואם invariant של פאזה 2.
- UI: InboundCreateDialog מאפשר ל-staff לבחור לקוח, מחסן, אסמכתה, תאריך צפוי, והוספת/הסרת שורות פריטים. InboundReceiveDialog מציג כל פריט עם expectedQty קודם + שדה receivedQty (ברירת מחדל: הנותר) + בורר מיקום לבחירה.
- הרשאה חדשה שכבר הוגדרה בפאזה 0 — WAREHOUSE_INBOUND_RECEIVE — נדרשת עכשיו לאישור הקליטה. סטף ללא ההרשאה יכול לראות וליצור תעודות צפויות אבל לא לאשר קליטה פיזית.
- הוספת קישור 'קליטה' לסיידבר בקבוצת המחסן, מתחת ל'מלאי'. גלוי לכל מי שיש לו WAREHOUSE_INVENTORY_VIEW.
- schema migration רץ דרך prisma db execute (Prisma Postgres אינו תומך ב-prisma migrate dev). הקובץ נשמר ב-packages/database/prisma/migrations/add_inbound_shipments.sql לתיעוד.
- אינטגרציה לחיוב (פאזה 5) — האירוע של RECEIVE עדיין לא נוצר כ-WhBillingEvent; הגעה לזה בפאזה 5. הזרם הנוכחי מספק את התשתית לכך.
- השלמת זרם end-to-end לדיווח לקוח: לקוח שולח 100 יח׳ ל-staff (ידנית/מערכת), נוצרת תעודה EXPECTED → staff קולט בפועל ובוחר מיקום → המלאי מופיע ב-/warehouse/inventory בסקופ של הלקוח.
v01.42.002תיקוןmobile/pod, mobile/dev-tooling, shipments/detail, shipments/sync, db/schema, shipments/activity-log, warehouse/inventory, warehouse/locations, warehouse/3pl, portal/storesmobile — כרטיסיית הוכחת מסירה ישירה בדף הביקור + תשתית ngrok, ותיקון מיפוי הערות לליונוויל
נוספה כרטיסיית 'הוכחת מסירה' ישירה בדף פרטי הביקור, מקבילה לכרטיסיות לקוח/כתובת/חבילה: הכרטיסייה מציגה תמונות POD קיימות, סטטוס חתימה, ואפשרות לצלם/עדכן ולהוסיף חתימה ישירות מהדף — ללא צורך לאתר את הכפתור בשורת הפעולות ה…
פרטים נוספים ↓הסתר ↑
נוספה כרטיסיית 'הוכחת מסירה' ישירה בדף פרטי הביקור, מקבילה לכרטיסיות לקוח/כתובת/חבילה: הכרטיסייה מציגה תמונות POD קיימות, סטטוס חתימה, ואפשרות לצלם/עדכן ולהוסיף חתימה ישירות מהדף — ללא צורך לאתר את הכפתור בשורת הפעולות הדביקה. תוקן גם: מסך סיכום ה-POD הפך ל-ScrollView כך שכפתור 'הוסף חתימה' גלוי גם כשהתוכן ממלא את המסך. הוספת @expo/ngrok ו-@expo/ngrok-bin לתשתית הפיתוח לתמיכה ב-Expo tunnel. הכנת האפליקציה לפרסום בחנויות: גרסה שודרגה ל-1.0.0, נוספו buildNumber (iOS) ו-versionCode (Android), הוגדרה שדה icon, ו-eas.json עודכן עם הגדרות submission לשתי החנויות. תוקן שורש שגיאת React hydration #418 שחזרה בכל דף מאומת: useInboxUnread אתחל את ה-badge של "הודעות" מ-localStorage ישירות כ-lazy useState initializer — השרת החזיר 0, הקליינט קרא ערך שמור; שינוי ל-useState(0) עם טעינת localStorage ב-useEffect מסנכרן את שני הצדדים. בנוסף — תוקן באג עמוק במיפוי הערות מול ליונוויל: השדה destinationNotes ("הערת מיקום") נשלח לליונוויל כ-notes ברמת ה-task, אבל אצל ליונוויל זה בעצם "הערת משלוח", לא הערת היעד. התוצאה: עריכת "הערת מיקום" אצלנו דרסה את הערת המשלוח בליונוויל, וב-webhook הבא הערך עבר אצלנו ל-shipmentNote בעוד destinationNotes התאפס. במקביל הערת היעד האמיתית של ליונוויל (DELIVERY visit notes) אף פעם לא הסתנכרנה. תיקון: destinationNotes → destination_notes (DELIVERY visit), shipmentNote → notes (task-level) — שני המיפויים אומתו empirit. נוסף שדה חדש sourceNotes ("הערת מוצא") הממופה ל-source_notes (PICKUP visit), עם עמודה חדשה ב-DB, סכמה ב-PATCH, ועריכה ב-SourceCard. השדה הקיים shipmentNote הפך לעריך (היה תצוגה בלבד) ומסתנכרן עכשיו ל-task-level notes של ליונוויל. שיוך השמות אצלנו אוחד עם ליונוויל: "הערת מיקום" → "הערת יעד" ב-9 מקומות בקוד; aliases של ייבוא קובץ נשמרו. הערה ארגונית (org_note) עדיין silent-fail בצד ליונוויל — מטופל מולם. (2) היסטוריית פעולות במשלוח — מבצע הפעולה הופרד מתיאור הפעולה. נוספו עמודות actor_type ו-actor_name לטבלת audit_logs, ובכל הכתיבות הקיימות (webhook ליונוויל ב-data-service.ts, recompute אוטומטי של roundtrip ו-return) נשמר עכשיו מי המבצע: webhook → actorType='webhook' actorName='Lionwheel', recompute אוטומטי → actorType='system'. ה-details נוקה ממידע על המקור — לא יותר 'נוצר מ-Webhook ליונוויל (task_created)' או 'עודכן מ-Webhook ליונוויל (manual_create): סוג משימה'; עכשיו רק 'משלוח נוצר' / 'עודכנו השדות: ...'. ב-UI של ActivityLogTimeline נוסף ActorBadge שמופיע במקום שם המשתמש כש-userName=null — עם איקון ליונוויל וטקסט 'Webhook מליונוויל' לכל פעולה שמגיעה מהוובהוק, או 'מערכת' / 'Cron' / 'API' לפי actorType. בכך, שינוי סטטוס שמגיע מליונוויל מציג בעמודת מבצע הפעולה 'Webhook מליונוויל' במקום להישאר ריק. חיזוק הודעת ה-toast לשדה הערה ארגונית: עד עכשיו נאמר רק "לעדכן ידנית בליונוויל", עכשיו ההודעה מזהירה גם שאם לא יעודכן שם בהקדם — הערך יידרס בוובהוק הבא של ליונוויל. שדות מוצא המשלוח (שם/עיר/רחוב/מספר/טלפון) הפכו לעריכים ב-SourceCard ומסתנכרנים לליונוויל (PICKUP visit) — עד עכשיו הם היו תצוגה בלבד למרות שה-API של ליונוויל תומך בכולם. השדה sourceName נשאר read-only כאשר המשלוח מקושר ללקוח (CustomerNameDisplay עם לינק לכרטיס לקוח), אחרת הוא עריך כמו השאר. (25) מחסן — תיקון פער UX: נוסף כפתור 'הוסף פריט מלאי' בטולבר של /warehouse/inventory ובפורטל הלקוח. עד היום היה אפשר רק לערוך כמות של פריט מלאי קיים בטבלה — לא היה מסלול UI ליצירת השורה הראשונה של מוצר במיקום (WhInventory). דיאלוג חדש InventoryCreateDialog עם בוררי מחסן/מיקום/מוצר וכמות, רמז לכמות נוכחית אם כבר קיים שילוב, ו-pre-fill מהפילטרים הנוכחיים של הטבלה. ה-API הקיים /api/warehouse/inventory/adjust (upsert) משמש בלי שינוי. ה-empty state המטעה שהפנה ל'עמוד המיקומים' (שלא היה בו את היכולת הזו) הוחלף בהנחיה ללחוץ על הכפתור החדש. (26) מחסן — יצירת מיקום הפכה פשוטה יותר: עד היום היו 3 שדות חובה (אזור, מעבר, מדף) — לא מתאים למחסנים קטנים שאין בהם היררכיה עמוקה. עכשיו רק 'אזור' חובה; מעבר/מדף/קומה/תא — אופציונליים. הסכמה ב-POST/PUT של /api/warehouse/locations הוקלה, הטופס מציין '(אופציונלי)' ב-placeholder, ה-section header מסביר שאזור חובה ושאר השדות אופציונליים, וטור הטבלה מציג '—' כשהשדה ריק (כמו שהיה בקומה/תא). buildLocationCode ממילא מסנן ערכים ריקים, אז קוד המיקום הוא 'A' למחסן עם רק שדה אזור. (27) מחסן 3PL — פאזה 0 (תשתית בלבד, אין שינוי משתמש עדיין): הוספת הבסיס הקודי לתמיכה ב-multi-customer warehouse שבה הטננט מאחסן ומלקט עבור לקוחות פורטל. ב-lib/warehouse/owner-scope.ts נוספו getReadScope ו-resolveWriteOwner (הראשון להחזרת Prisma where fragment עם תמיכה ב-'all' כדי לראות את כל הלקוחות של הטננט; השני להחלטה על ה-ownerCustomerId שיירשם בשדה החדש). ה-API של getOwnerScope המקורי נשאר תואם לאחור — כל ה-routes הקיימים ממשיכים לעבוד בלי שינוי. נוספו 4 הרשאות חדשות: WAREHOUSE_MANAGE_CUSTOMER_DATA, WAREHOUSE_INBOUND_RECEIVE, WAREHOUSE_BILLING_VIEW, WAREHOUSE_BILLING_MANAGE — עם תיאורים, קטגוריה והקצאה ל-OWNER/PLATFORM_ADMIN/WAREHOUSE_MANAGER. נוספו שני flags חדשים בכותרת isMultiCustomerWarehouseEnabled ו-isWarehouseBillingEnabled שקוראים מ-tenant.settings.modules.warehouse_multi_customer / warehouse_billing (שניהם דורשים גם את ה-flag הבסיסי של warehouse). 17 בדיקות חדשות עוברות (10 ל-scope helpers + 7 ל-feature flags), סה"כ 689 tests עוברים. נוספו ב-SourceCard 3 שדות חדשים סימטריים ליעד: קומה, דירה, אימייל. עמודות חדשות ב-DB, mapping ב-lionwheel-sync ל-PICKUP visit, וקליטה מה-webhook. אומת empirit על משלוח 25020207. (28) מחסן 3PL — פאזה 1 (קריאה רב-לקוחית): נחשפה לראשונה היכולת ל-staff לראות נתוני מלאי ומוצרים של לקוחות הטננט. נוסף helper API מרכזי (lib/warehouse/parse-read-scope.ts) שמטפל ב-validation מלאה: הרשאת WAREHOUSE_MANAGE_CUSTOMER_DATA, flag warehouse_multi_customer, ושייכות לקוח לטננט. endpoint חדש /api/warehouse/customers מחזיר רק לקוחות עם מודול warehouse מופעל, ומסמן enabled=false כשהתכונה כבויה — כך ה-UI מתחבא אוטומטית בלי endpoint נפרד לבדיקת flag. רכיב חדש CustomerScopeSelector מופיע בטולבר של /warehouse/inventory ו-/warehouse/products כשהתכונה מופעלת; ערכי הבחירה: הכל / טננט בלבד / לקוח ספציפי. ה-GET routes של אותם עמודים הוסבו מ-getOwnerScope ל-parseReadScope (תומך ב-?ownerCustomerId=all/tenant/customerId). שתי העמודות מציגות עמודה נוספת 'שייך ל-' עם תווית 'הטננט' או שם הלקוח. בעמוד המלאי, כפתור 'הוסף פריט מלאי' מוסתר כשבחורה תצוגה של לקוח מסוים — פאזה 2 תוסיף תמיכה בכתיבה על-שם לקוח. הזרם הקיים תואם לאחור: בלי המודול מופעל, אף משתמש לא רואה שינוי. (29) היסטוריית פעולות במשלוח — שיפור תצוגה לשדות ליקוט: עד היום, כששדה pickingCategory השתנה דרך PATCH /api/shipments/[id] (לדוגמה מעובד שמשנה קטגוריית ליקוט מ-'ברירת מחדל' ל-'שוטף'), היסטוריית הפעולות הציגה רק 'עודכנו השדות: קטגוריית ליקוט' בלי לחשוף את הערך הישן והחדש. הסיבה: ה-FIELD_LABELS של /api/shipments/[id]/activity-log/route.ts (נפרד מה-PATCH route) לא כלל את pickingCategory, ולכן השינוי סונן ב-extractChanges. נוסף ל-FIELD_LABELS, ונוספו VALUE_DISPLAY_MAPS לשלושת השדות (pickingStatus: ממתין לליקוט/נלקט, pickingType: עלוני שבת/מוצרים, pickingCategory: שוטף/מזדמן) — כך שהטבלה תציג 'ברירת מחדל ← שוטף' במקום 'null ← regular'. בנוסף נוסף סט DATETIME_FIELDS ופונקציית formatDateTime למניעת הצגת תאריכים כ-ISO גולמי (למשל pickedAt, addedToPickingAt, estimatedDelivery, actualDelivery, pickupDate, deliveryDate, visitAt). (30) דף משלוח — סקציית ליקוט אוחדה עיצובית: סטטוס הליקוט הראשי (ממתין/נלקט) הפך לבאדג' צבעוני (ענבר/ירוק) עם ChevronDownIcon במקום טקסט עם PenLineIcon כחול, כדי להתאים לשני הבוררים הסמוכים (סוג ליקוט — עלוני שבת/מוצרים; קטגוריה — שוטף/מזדמן) שגם בהם הוחלף אייקון העט בחץ. כפתורי ה-V (סמן כנלקט) וה-X (הסר מליקוט) הוסרו מצד שמאל של השורה, כי כל מעבר סטטוס זמין עכשיו דרך ה-dropdown של הבאדג'. צד שמאל מציג עכשיו רק את כפתור 'הוסף לליקוט' (כשאין סטטוס) או את כפתור עריכת הערת הליקוט יחד עם חותמת זמן ה-pickedAt (כשהמשלוח נלקט). הוסר גם ה-separator (•) שהיה בין בורר סוג ליקוט לבורר הקטגוריה — מיותר עכשיו כששניהם באדג'ים עם גבול ברור. אותו עיקרון יושם בשורת 'יעד שבת': הטקסט 'פרשת X' הפך לבאדג' סגול עם ChevronDownIcon שלחיצה עליו פותחת dropdown של 4 הפרשות הקרובות + פריט 'הסר יעד שבת' (אדום, מתחת ל-DropdownMenuSeparator). הכפתורים הנפרדים 'שנה' (PenLineIcon) ו-X (אדום) הוסרו לחלוטין מצד שמאל — כל הפעולות זמינות עכשיו דרך הבאדג'. כשאין יעד שבת מוגדר נשאר כפתור '+ הוסף יעד שבת' מימין, בדומה לדפוס של 'הוסף לליקוט'. בנוסף — תווית 'יעד שבת' והערך (באדג'/טקסט) הועברו לאותה שורה במקום שני שורות, כדי לחסוך גובה אנכי בכרטיסיית התפעול. אותו דפוס יושם בשורת 'יעד אקספרס': התאריך הפך לבאדג' אינדיגו עם ChevronDownIcon שלחיצה עליו פותחת את ה-Popover של ExpressBulkDateMenu (7 הימים הקרובים + 'תאריך אחר' עם calendar + 'הסר מאקספרס') — נוסף ל-ExpressBulkDateMenu prop אופציונלי trigger שמחליף את כפתור ברירת המחדל; כפתור ה-X האדום החיצוני הוסר (מיותר כי 'הסר מאקספרס' קיים בתוך התפריט עצמו), והתווית והערך יושבים על אותה שורה. כשאין יעד אקספרס נשאר כפתור '+ הוסף יעד אקספרס' מימין. גם סקציית 'פניות שירות' (ShipmentServiceTicketsSection) קיבלה אותו טיפול: התווית והערך אוחדו לשורה אחת — במקום label מעל summary מעל שורת צ'יפים, עכשיו label + צ'יפים על אותה שורה ('פניות שירות [chip1] [chip2] ...'). הטקסט 'X פתוחות' / 'אין פניות פתוחות' הוסר כי הצ'יפים עצמם מתארים מצב כל פנייה (סטטוס + קטגוריה, צבע סטטוס לפי הסכמה הקיימת + opacity 60 לפניות סגורות); רקע sky עדיין מסמן את המצב הכללי שיש פניות פתוחות. כשאין פניות נשאר 'לא הוגדר' inline, וכשטוען 'טוען...'. הצ'יפים flex-wrap-ים כשהשורה צרה כדי לא לדחוק את כפתור 'פנייה חדשה'. EditablePickingStatusText קיבל prop נוסף onRemove + פריט 'הסר מליקוט' (אדום, מתחת ל-DropdownMenuSeparator) בתחתית ה-dropdown של סטטוס הליקוט — בדפוס של 'הסר יעד שבת'. בעבר ניתן היה להסיר משלוח מליקוט רק דרך כפתור X חיצוני שהוסר בשינוי קודם, ולכן הפעולה הזו לא הייתה נגישה יותר; עכשיו היא חזרה אבל מאוחדת עם ה-dropdown של הבאדג'. (31) מחסן 3PL — פאזה 2 (כתיבה רב-לקוחית): staff עם הרשאה יכול עכשיו ליצור מוצרים ולעדכן מלאי על-שם לקוח. נוסף helper lib/warehouse/parse-write-owner.ts שעוטף את resolveWriteOwner ומוסיף את ה-validation מול ה-DB (הרשאה WAREHOUSE_MANAGE_CUSTOMER_DATA, flag warehouse_multi_customer, שייכות הלקוח לטננט והפעלת מודול מחסן ללקוח). POST /api/warehouse/products ו-POST /api/warehouse/inventory/adjust מקבלים שדה אופציונלי ownerCustomerId ב-body; כש-staff נותן ערך הוא עובר את כל ה-validation, וכשהוא לא נותן — חוזרים להתנהגות הישנה (tenant-owned). אכיפה חדשה ב-/inventory/adjust: (א) המיקום חייב להיות בטננט (לאו דווקא בבעלות הלקוח — בעקבות גישה B שמיקומים תמיד אצל הטננט); (ב) המוצר חייב להיות בבעלות הזהה לבעלי המלאי החדש (invariant: product.ownerCustomerId === inventory.ownerCustomerId); (ג) אם כבר קיימת שורת מלאי במיקום+מוצר עם בעלים שונה — 409 במקום upsert שקט. ב-UI: ProductForm ו-InventoryCreateDialog קיבלו בורר 'שייך ל-' שמופיע רק כשהתכונה מופעלת; בורר המוצרים ב-InventoryCreateDialog מסונן אוטומטית לפי הבעלים הנבחר. כפתור 'הוסף פריט מלאי' חזר להיות זמין בכל מצב — ה-defaults מועברים מה-scope הנוכחי של העמוד. ProductForm נועל את בורר הבעלים במצב עריכה (בעלות לא ניתנת לשינוי אחרי יצירה). 13 בדיקות חדשות ל-parseWriteOwner; סה"כ 702 tests עוברים. השלמת סימטריה מלאה בין כרטיסיות המוצא והיעד: 3 שדות חדשים בכל אחת. בכרטיס יעד נוספו עריכה למיקוד (destination_zip_code), כניסה (destination_entrance) וקוד כניסה (destination_entrance_code) — קודם הם הוצגו רק מתוך parse של הערת היעד, עכשיו הם עמודות נפרדות ב-DB שמסתנכרנות עם DELIVERY visit. בכרטיס מוצא נוספו עריכה לאיש קשר (source_recipient_name), טלפון 2 (source_phone2) ומיקוד (source_zip_code). אומת empirit ש-6 השדות מסתנכרנים מקצה לקצה. הערה: source_entrance ו-source_entrance_code לא נוספו כי ליונוויל silent-fail עליהם ב-PICKUP visit (זהה לדפוס של org_note). במקביל הוצף הרווח האנכי בין השורות: space-y-3 → space-y-1.5 ו-py-1 → py-0.5 בשתי הכרטיסיות, כדי שהגובה לא יזנק עם השדות החדשים. (32) פורטל לקוחות — בדיקת חיבור WooCommerce שדרגה אבחון: עד היום ה-test פנה ישירות ל-/wp-json/wc/v3/system_status, שהוא endpoint שדורש הרשאת admin ב-WP, ולכן החזיר 404 (rest_no_route) בכל מקרה שבו (א) הכתובת שגויה, (ב) Pretty Permalinks כבויים, (ג) WC לא מותקן, (ד) תוסף אבטחה חוסם את namespace ה-API, או (ה) המפתחות נוצרו עבור משתמש שאינו admin — וההודעה הסתמית 'WooCommerce החזיר שגיאה (404)' לא עזרה ללקוח לאבחן את הבעיה. הלוגיקה החדשה בודקת ב-3 שלבים: (1) probe ל-/wp-json/wc/v3 ללא auth — מאתר 404 ברמת ה-namespace ומציג הודעה שמפרטת את 4 השאלות שצריך לבדוק; (2) auth ל-/orders?per_page=1 (דורש רק Read key) — מבדיל בין credentials שגויים (401/403 עם הודעה ברורה) לבין שגיאות אחרות שמוצגות עם גוף התשובה לדיבוג; (3) ניסיון best-effort ל-system_status רק כדי לחלץ שם חנות לתצוגה, אבל כשלון בו לא מפיל את ה-test. נוסף גם validation שכתובת החנות חייבת להתחיל ב-http(s)://.
v01.42.001תיקוןdocs/public, security, mobile/map, mobile/earnings, mobile/home, messages/inbox, messages/templates, search, driver/track, mobile/pod, warehouse/ai, mobile/ux, mobile/scanner, mobile/signature, portal/import, shipments/activity-log, shipments/lionwheel-sync, shipments/partner-transfersתיעוד — סדר ה-navbar תוקן ב-RTL ונוסף toggle של דארק/לייט
(20) נוספה חתימה דיגיטלית (אופציונלית) לתהליך הוכחת המסירה: בסיכום ה-POD מוצגת סקציית "חתימת לקוח" עם canvas ציור מלא-מסך — הלקוח חותם בזמן המסירה, החתימה נשמרת ב-Supabase Storage (category=signature) ומועלית יחד עם תמונ…
פרטים נוספים ↓הסתר ↑
(20) נוספה חתימה דיגיטלית (אופציונלית) לתהליך הוכחת המסירה: בסיכום ה-POD מוצגת סקציית "חתימת לקוח" עם canvas ציור מלא-מסך — הלקוח חותם בזמן המסירה, החתימה נשמרת ב-Supabase Storage (category=signature) ומועלית יחד עם תמונות ה-POD; אם הנהג לא מוסיף חתימה — ה-POD מוגש עם תמונות בלבד כרגיל. (17.5) שדרוג מנוע סריקת הברקודים באפליקציית השליחים ובסורק המחסן: עבר מ-expo-camera ל-react-native-vision-camera v4. Frame Processor רץ על thread נייטיבי — ללא JS bridge — הסריקה מהירה יותר משמעותית, עובדת טוב יותר בזוויות ובתאורה חלשה ומזהה ברקודים שחוקים. נוספו פורמטים לוגיסטיים: PDF-417 (מדבקות שליחות) ו-ITF (GTIN-14 מחסן). expo-camera נשאר לצילום תמונות POD בלבד. (16) טאב 'היום' שונה ל'משימות': נוסף date navigator (חיצים קדימה/אחורה) לצפייה במשימות של ימים קודמים ועתידיים; ShiftBanner ו-COD banner מוצגים רק כשמוצג היום; endpoint תומך ב-?date=YYYY-MM-DD. (15) מודול מחסן — Phase 4D הושלם: דפי "חידוש מלאי" ו-"Slotting" חוברו לסיידבר בפורטל הטננט ובפורטל הלקוח. כלל ארבעת תכונות ה-AI של Phase 4D זמינות כעת: התראות חידוש מלאי, המלצות Slotting, הצעות אצוות חכמות (ב-BatchListView) ואינדיקטור עומס אזורים (ב-MetricsDashboard). (14) נוסף אקורדיון לשורות הפירוט בטאב הכנסות המובייל: לחיצה על מסירות / איסופים / חזרות פותחת רשימת עצירות בודדות עם שם לקוח, ברקוד, עיר, תאריך וסכום לכל שורה. (12) תוקן: קו המסלול על המפה לא התחיל במדויק מנקודת ההתחלה — הגיאומטריה של OSRM מחזירה נקודה ראשונה מוצמדת לכביש (offset קטן) או מיקום ה-GPS של הנהג בזמן ההפעלה (offset גדול). תוקן על-ידי עיגון נקודת הפתיחה של הקו לקואורדינטות המדויקות של עצירה #1: עבור offset קטן (<55m) — מוחלפת רק הנקודה הראשונה; עבור offset גדול — נמצאת הנקודה הקרובה ביותר בגיאומטריה לעצירה #1 ומשם חותכים את הקו ומעגנים את ראשיתו. (11) עיצוב מחדש של אפליקציית השליחים: כרטיס hero לעצירה הבאה עם גרדיאנט אינדיגו ו-"נווט עם Waze" בולט, progress bar לנסיעה, מספרי עצירות בכרטיסים, מקטע ה-done מתקפל, מצב ריק ומצב "הכל הושלם" עם איקונים, skeleton loading, ניקוי כרטיס שיתוף המיקום (הוסרו קואורדינטות גולמיות, נוסף גריד מהירות/סוללה ענק). (10) תוקן: מחיקת תבנית Meta מהרשימה מחקה מקומית בלבד — עכשיו כשמוחקים תבנית מקושרת ל-Meta, הדיאלוג מודיע שהמחיקה תתבצע גם מ-Meta, וה-endpoint נקרא אוטומטית. כפתור 'מחק מ-Meta' בעורך הוצג רק לתבניות שאינן APPROVED — ההגבלה הוסרה ועכשיו מוצג לכל סטטוס (פרט ל-NOT_FOUND). שני תיקונים ב-header של /docs: (1) הקישורים (בית / פורטל לקוחות / מה חדש) הופיעו בצד שמאל מרוחק מהלוגו, עם החיפוש ביניהם — לא טבעי בעברית. סודרו מחדש: הניווט עכשיו צמוד ללוגו בצד ימין כמקובל בעברית, והחיפוש בצד שמאל. (2) חסר כפתור החלפת ערכת נושא — נוסף ModeToggle של המערכת ליד החיפוש כך שגם דף ה-docs (שפתוח לכולם בלי התחברות) תומך באותו toggle דארק/לייט. בנוסף, תוקנו שתי פרצות אבטחה: (3) שאילתת $queryRaw ב-sorting-errors הוספה לה סינון tenant_id למניעת דליפה cross-tenant; (4) endpoint של messages/analytics הוגבל ל-ANALYTICS_VIEW permission. (5) תוקנה שגיאת React hydration #418: ShabbatGuard, LiveClock ו-LiveDuration עברו לאתחול ריק ועדכון ב-useEffect; החלפת Math.random() בערכים יציבים ב-global-search ו-sidebar skeleton. (6) תוקנה קריסת Expo Go: טאב המפה המוביילי גרם ל-Invariant Violation (MLRNCameraModule) עקב import סטטי של MapLibre שמנע אתחול המודול הנייטיבי. פתרון: לוגיקת המפה הועברה ל-MapScreen.tsx נפרד; map.tsx הפך ל-guard דק שמשתמש ב-require() מותנה — ב-Expo Go מוצג מסך fallback ובבuild נייטיבי נטען MapScreen. (6.5) נוספו טאבי סינון למפה המוביילית: הכותרת הצפה ('47 פעילים · 6 נמסרו') הוחלפה בשלושה טאבים — הכל / במסלול / נמסרו. כל טאב מסנן את המרקרים המוצגים ואת מה שניתן לבחור בציור פוליגון. (6) תוקן lockout במobile login: loginAttempts עכשיו עולה בכל כישלון סיסמה, lockedUntil מוגדר אחרי 5 ניסיונות כושלים (15 דקות), ובדיקת נעילה מועברת לפני bcrypt. (7) תוקן באג: מרקר נקודת הסיום (כתום) לא הופיע על מפת המובייל כשלא הוגדרה ברירת-מחדל (isDefault=false). האתחול שונה כך שכאשר אין מיקום מסומן כברירת מחדל — נבחר אוטומטית המיקום השמור הראשון הזמין. (8) תוקן webhook WooCommerce: חיבורים ללא webhookSecret נדחים (fail-closed) במקום להתקבל ללא אימות — בהתאם לאופן שבו Shopify כבר עבד באותו handler. (9) תוקן webhook Green API: כשחסר שדה instanceData בגוף הבקשה — הוובהוק נדחה (fail-closed) במקום לעקוף את אימות ה-instanceId. (13) תוקן אפליקציית השליח (mobile): המונח "POD" הוחלף בכל מקומות ה-UI בביטוי "הוכחת מסירה" בעברית — כותרת מסך המצלמה, כיתוב תמונה, כפתור שמירה, כותרת סיכום, תווית סטטוס, toast, alert אישור מסירה ללא תיעוד, הודעת הרשאת מצלמה; בנוסף תורגם "photos" ל-"תמונות" ב-badge הספירה. (17) שיפורי UX אפליקציית שליחים: הוספת haptic feedback (בחירת טאב, לחיצה ארוכה, סיום משמרת); אנימציית fade 80ms→150ms במעבר בין טאבים; כרטיס ה-hero (עצירה הבאה) מציג פעולות ישירות — התקשר, WhatsApp, נווט ב-Waze; לחיצה ארוכה על כל כרטיס פותחת action sheet (iOS) / dialog (Android) עם אותן אפשרויות; כפתור 'סיים משמרת' ב-AllDoneCard; טאב 'לא במסלול' ממוין לפי מרחק מהנהג; HomeHeader קיבל רקע תכלת עדין (primary[50]). (18) Live badge על אייקון הבית בשורת הטאבים — מציג את מספר המשלוחים הפתוחים ומתעדכן אוטומטית; badge נעלם כשאין משלוחים פתוחים. (19) Optimistic UI — סימון 'נמסר' או 'נכשל' מעדכן מיד את cache הבית (status, stats) לפני חזרה למסך הרשימה; הרשימה, הפרוגרס בר, הבאדג' ותיבת 'כל המשלוחים הושלמו' מגיבים מיידית ללא המתנה לשרת. (21) פורטל לקוחות — בייבוא משלוחים (/portal/shipments/import) נוסף בורר 'מלא מתוך כתובת מועדפת' ליד שדות כתובת המוצא, בקונפיגורציה הראשונית ובדיאלוג עריכת ההגדרות. הבורר טוען את הרשימה מ-/api/portal/saved-addresses (אותן כתובות שמנוהלות ב-/portal/settings/addresses), ובחירה ממלאת אוטומטית עיר/רחוב/מספר. כשאין כתובות שמורות מוצג קישור ישיר לעמוד ניהול הכתובות. בפורטל הצוות הפיצ'ר מוסתר. (22) היסטוריית פעולות במשלוח — שלוש רשומות 'יצירה'/'עדכון' שנכתבו לכל משלוח חדש (אחת מה-webhook הראשון של ליונוויל task_created, שנייה מ-webhook נוסף manual_create שגרם ל'עדכון' של שדה taskType מ-ריק ל'משלוח', ושלישית מה-import/UI עם שם המשתמש) — מתאחדות עכשיו לרשומת יצירה אחת. נוסף helper upsertCreateAudit ב-lib/audit-logger.ts שמזהה רשומת create קיימת לאותו entity וממזג אליה את ה-newData, ה-details ו-userId של מקור נוסף — במקום ליצור רשומה נוספת. בנוסף, ב-data-service.ts ה-update flow של ה-webhook מזהה updates שמגיעים תוך 90 שניות מהיצירה (ה-cascade הטיפוסי של ליונוויל) ואינם כוללים שינוי סטטוס — וממזג אותם גם הם לתוך ה-create. שינוי סטטוס אמיתי באותו חלון זמן ממשיך להירשם כ-status_change בפני עצמו. הפתרון מכסה את כל מסלולי היצירה (UI ידני, יבוא אקסל, שכפול, bulk-duplicate, וכל webhook מליונוויל) ושומר על כל המידע — שם המשתמש שיצר, מקור היצירה (ידני/אקסל/שכפול), וציון 'סונכרן עם ליונוויל' כשרלוונטי — בלי לפצל למספר פעולות. (23) סנכרון לליונוויל — שני ניקויים בעקבות בדיקה empirit מקיפה של כל שדות העדכון מול ה-API: (א) השדה weight עוגל לשלם לפני שליחה, כי ליונוויל קוטמת ערכים עשרוניים (שלחנו 5.5, נשמר 5) ואז הווידוא שלנו דיווח על מצב מסונכרן עם ערך שונה. (ב) ה-mapping sameDay→same_day הוסר מ-LIONWHEEL_TASK_FIELDS — השדה מקובל ב-/tasks/create אבל מתעלם ב-/tasks/{id}/update (silent-fail), ובכל מקרה טופס עריכת המשלוח אצלנו אינו מאפשר לשנות אותו. הערות בקוד הוסרו לגבי visit-fields שחשבנו שעלולים לא לעבוד — בבדיקה כולם (phone, customerName, city, street, number, floor, apartment, notes) עובדים מצוין. (24) מזהי משלוחים בין-ספקיים — נוספה תמיכה מלאה ב-2 הזרימות של ליונוויל לקליטת משלוחים מספק אחר: (א) partner-transfer (origin_partner_task_id) ו-(ב) baldar (wp_order_id). עד היום שמרנו רק את המקרה הראשון, ואת השני לא בכלל. בנוסף תוקן באג ב-task-processor.ts שבו ה-backfill של מזהי partner רץ רק כשמשלוח יוצא (status IN_TRANSFER/OUT_INVENTORY) ולא כשנכנס. תוויות ה-UI ב-4 המקומות (כרטיס משלוח, טבלה ראשית, חיפוש גלובלי) הוחלפו מ"חיצוני"/"משוגר" ל"מזהה יוצא"/"מזהה נכנס". Backfill לשני המשלוחים הטסט (24996858 מ-baldar → 1897556, 25000309 מ-transfer → 24966518) אימת את התיקון end-to-end.
v01.42.000חדשdocs/publicminorמרכז תיעוד ציבורי חדש ב-/docs — סיידבר, TOC, חיפוש ⌘K, וכפתור AI לכל עמוד
התיעוד הציבורי של Shipnest עבר רה־ארגון מלא.
פרטים נוספים ↓הסתר ↑
התיעוד הציבורי של Shipnest עבר רה־ארגון מלא. הדף הישן ב-/api היה רוחב מוגבל (max-w-3xl) על מסך רחב, מה שהוביל לחלל ריק בצד שמאל וניצול ירוד של המסך. הוחלף ב-hub חדש ב-/docs במבנה 3 עמודות: סיידבר ניווט (קבוצות נושאים), תוכן רחב לקריאה, ו-TOC צד שמאל שמתעדכן auto לפי כותרות בדף עם scroll-spy. נוסף חיפוש גלובלי בלחיצת ⌘K (cmdk) שמחפש לפי כותרות, blurbs וקבוצות מילות מפתח. כל דף חושף כפתור 'שאל AI על העמוד' שמעתיק את כל תוכן העמוד כפרומפט מובנה (עם system primer של Shipnest), ולחיצה על אחד הספקים (ChatGPT / Claude / Gemini) פותחת אותם במסך חדש. הסיידבר כולל widget של 3 הרשומות האחרונות מ-changelog.json שמתעדכן אוטומטית. אגב — תוקנו /legal/terms ו-/legal/privacy שהחזירו 404 (היו ב-route group (legal) שמוחק את ה-prefix מה-URL; הועברו ל-app/legal/ הרגיל). /api ממשיך לעבוד דרך 301 ל-/docs/api.
- /docs — landing עם כרטיסי נושאים (API, Webhooks, Changelog, ועוד 6 שמסומנים 'בקרוב' לעמודי תפעול כמו משלוחים/COD/לקוחות)
- /docs/api — תיעוד API מלא ומורחב: כוסו webhooks management endpoints וביטול משלוחים (5 endpoints נוספים שהיו חסרים בתיעוד הקודם), נוספו סקציות best-practices (ניהול secrets, polling vs webhooks, error handling)
- /docs/changelog — לוג גרסאות מסודר לפי חודשים, כל רשומה עם type badge (חדש/תיקון/שיפור/ייעול), description קצר ופרטים מורחבים ב-<details>
- DocsShell — layout client component עם sticky top header, sidebar (lg ומעלה inline; mobile drawer דרך Sheet), TOC צדדי, footer. רספונסיבי מלא: 3 עמודות במסכים גדולים, עמודה אחת במובייל עם hamburger
- DocsToc — TOC client שבונה את עצמו מ-h2/h3 ב-article (data-docs-article), עם IntersectionObserver לסימון הסעיף הנוכחי בזמן גלילה
- DocsSearch — CommandDialog (cmdk) שמופעל מ-⌘K או '/' globally. ה-value של כל פריט כולל title + blurb + keywords כדי שחיפוש בעברית/אנגלית יחזיר תוצאות רלוונטיות (למשל 'token' מוצא את סעיף האימות)
- AiPromptButton — קורא את תוכן ה-article מה-DOM (תוך השמטת elements עם data-ai-skip), בונה פרומפט עם system primer של Shipnest, מעתיק ללוח. dropdown נוסף עם links ל-ChatGPT/Claude/Gemini שפותחים עם short bootstrap prompt
- ChangelogWidget — server component בסיידבר שמציג את 3 הרשומות האחרונות מ-changelog.json, עם type badges וקישור להיסטוריה המלאה
- DocsTodo / DocsTodoPage — רכיבי marker לתוכן בכתיבה. בפיתוח מציג בנר אדום בולט, בפרודקשן הודעה רכה. מאפשר לפרסם stubs לעמודים שייכתבו בעתיד מבלי לפרסם דף ריק
- CLAUDE.md — נוסף סעיף 'עדכון תיעוד ציבורי — שיקול דעת לפני כל push' שמנחה את ה-AI מתי לעדכן /docs (שינוי endpoint/event/scope/rate limit) ומתי לדלג (refactor פנימי, feature flag, ops פנימי)
- Bug fix — /legal/terms ו-/legal/privacy החזירו 404. הקבצים היו ב-app/(legal)/ (route group) שמתעלם מה-prefix, ולכן ה-URLs בפועל היו /terms ו-/privacy. הועברו ל-app/legal/ הרגיל וה-URLs עובדים
- Bug fix — /api נראה רע בגלל max-w-3xl על מסך רחב. הופנה ל-/docs/api עם layout 3 עמודות שמנצל את כל הרוחב
v01.41.001שיפורportalפורטל API — הסתרת מפתחות מבוטלים כברירת מחדל
טבלת 'המפתחות שלי' מציגה כעת רק מפתחות פעילים (כמו Stripe / GitHub / Vercel).
פרטים נוספים ↓הסתר ↑
טבלת 'המפתחות שלי' מציגה כעת רק מפתחות פעילים (כמו Stripe / GitHub / Vercel). מפתחות מבוטלים מוסתרים אבל נשמרים לאודיט — כפתור 'הצג מבוטלים (N)' מופיע כשיש כאלה, מאפשר לראות את ההיסטוריה. גם עודכן הקישור 'תיעוד טכני מלא' מ-/api ל-/docs/api הישיר אחרי המעבר של הדף.
v01.41.000חדשportalminorפורטל — ניהול מפתחות API ב-self-service במקום פנייה לתמיכה
בכרטיס 'המפתחות שלי' בראש דף /portal/settings/api לקוחות יכולים עכשיו ליצור, לרשום ולבטל מפתחות API לבד, באותו דפוס של Stripe / GitHub / Vercel / OpenAI — בלי לעבור דרך התמיכה.
פרטים נוספים ↓הסתר ↑
בכרטיס 'המפתחות שלי' בראש דף /portal/settings/api לקוחות יכולים עכשיו ליצור, לרשום ולבטל מפתחות API לבד, באותו דפוס של Stripe / GitHub / Vercel / OpenAI — בלי לעבור דרך התמיכה. נוסף POST/GET /api/portal/api-keys ו-DELETE /api/portal/api-keys/[id]. נוספה הרשאת CUSTOMER חדשה MANAGE_API_KEYS שמופעלת כברירת מחדל לבעלים. גבול של 10 מפתחות פעילים לטננט. הטוקן הגולמי מוצג פעם אחת בלבד בדיאלוג אחרי יצירה (כמו אצל כל ספק רציני) — הסיבה היא threat-model: דליפת DB לא חושפת מפתחות חיים, session hijack לא מקבל אותם 'תמיד גלוי', וזה דרישה של SOC 2 / ISO 27001. אם איבדו — בטלו וצרו חדש בקליק במקום פנייה לתמיכה.
- POST /api/portal/api-keys — יצירה: name, scopes (חובה), expiresAt (אופציונלי, presets: ללא תפוגה / 30 / 90 / 365 ימים). מחזיר את הטוקן פעם אחת.
- GET /api/portal/api-keys — רשימת כל המפתחות של ה-tenant (פעילים + מבוטלים), כולל prefix, scopes, lastUsedAt, status. הטוקן הגולמי לא חוזר אף פעם.
- DELETE /api/portal/api-keys/[id] — soft-revoke (revokedAt + revokedByName). Idempotent.
- ApiKeysSection client component — טבלה עם סטטוס badges (פעיל / פג / בוטל), כפתור 'צור חדש' עם דיאלוג טופס, ודיאלוג 'הצג פעם אחת' עם כפתור 'העתק' שכולל fallback ל-execCommand.
- CUSTOMER_PERMISSIONS.MANAGE_API_KEYS — הרשאה חדשה, OWNER_PERMISSIONS כולל אותה. הדף + ה-endpoints גם יחד מאמתים את ההרשאה.
- Step 1 בכרטיס 'תחילת עבודה' עודכן: 'צרו מפתח בכרטיס למעלה' במקום 'פנו לתמיכה'. נשמרה הודעת ה-warning שהמפתח מוצג פעם אחת, אבל נוסחה מחדש כי כעת הפתרון הוא לבטל-וליצור-חדש ולא לפנות לתמיכה.
v01.40.004תיקוןapi/middlewareתיקון — דף תיעוד ה-API ב-/api נחסם 401 לאורחים
ה-middleware התייחס לכל מה שמתחיל ב-/api כ-API route ודחה 401 JSON, כולל דף התיעוד עצמו ב-/api (הקובץ apps/web/app/(legal)/api/page.tsx).
פרטים נוספים ↓הסתר ↑
ה-middleware התייחס לכל מה שמתחיל ב-/api כ-API route ודחה 401 JSON, כולל דף התיעוד עצמו ב-/api (הקובץ apps/web/app/(legal)/api/page.tsx). תוקן: בדיקה מפורשת שמטפלת ב-/api (בדיוק) כ-content page ולא כ-API route, נוסף ל-publicRoutes. במקביל הוחזר הכפתור 'תיעוד טכני מלא' בכותרת של /portal/settings/api שהוסר קודם כי הוא הוביל ל-401. אומת — GET /api כעת מחזיר 200 text/html עם הדף המלא (~223KB).
v01.40.003שיפורportalפורטל API — קלפי המדריך מתקפלים כאקורדיון
ששת הקלפים של דף /portal/settings/api הומרו מ-sections פתוחים תמיד ל-<details> native — כל קלף נסגר ונפתח בלחיצה על הכותרת, עם chevron שמסתובב.
פרטים נוספים ↓הסתר ↑
ששת הקלפים של דף /portal/settings/api הומרו מ-sections פתוחים תמיד ל-<details> native — כל קלף נסגר ונפתח בלחיצה על הכותרת, עם chevron שמסתובב. כל הקלפים סגורים כברירת מחדל (כולל 'תחילת עבודה') כדי לתת מבט מרוכז במקום קיר טקסט, והמשתמש פותח רק את מה שמעניין אותו. שימוש ב-HTML semantic native (לא Radix accordion) כדי לחסוך JS וכדי שהדף יעבוד גם לפני הידרציה.
v01.40.002תיקוןapi/middlewareOpenAPI spec — להסיר את ה-auth gate מ-/openapi.yaml
ה-spec שנוסף ב-01.40.001 היה מאחורי middleware ה-auth — בקשה ל-/openapi.yaml מ-Swagger UI / n8n / Postman / AI הייתה מוחזרת כ-redirect ל-/login והדפדפן/הכלי מקבל HTML במקום YAML.
פרטים נוספים ↓הסתר ↑
ה-spec שנוסף ב-01.40.001 היה מאחורי middleware ה-auth — בקשה ל-/openapi.yaml מ-Swagger UI / n8n / Postman / AI הייתה מוחזרת כ-redirect ל-/login והדפדפן/הכלי מקבל HTML במקום YAML. נוסף /openapi.yaml ל-publicRoutes ב-middleware.ts. אומת ידנית — הקובץ מוגש עכשיו כ-text/yaml תקין (~31KB) ללא session. בנוסף — הוסר כפתור 'תיעוד טכני מלא' שהיה ב-header של דף הגדרות ה-API בפורטל; הוא הצביע על /api (route לא קיים) וגרם ללקוחות לקבל 401 Unauthorized מה-middleware. הדף עצמו כבר מהווה את התיעוד המלא, וכפתור OpenAPI spec הסמוך מספק את ה-spec הטכני.
v01.40.001חדשportal/apiOpenAPI spec זמין להורדה מהפורטל
נוסף קובץ OpenAPI 3.1 סטטי ב-/openapi.yaml (879 שורות) שמתעד את כל ה-endpoints של /api/v1, וכפתור חדש בראש דף הגדרות ה-API בפורטל שמקשר אליו.
פרטים נוספים ↓הסתר ↑
נוסף קובץ OpenAPI 3.1 סטטי ב-/openapi.yaml (879 שורות) שמתעד את כל ה-endpoints של /api/v1, וכפתור חדש בראש דף הגדרות ה-API בפורטל שמקשר אליו. מאפשר ללקוחות לייבא את ה-spec ישירות ל-Postman / Insomnia / n8n / Make ולקבל auto-completion ו-validation במקום לקרוא ידנית את התיעוד.
v01.40.000חדשportalminorפורטל — דף מדריך API ו-Webhooks מובנה לצד אזורי השימוש
נוסף לפורטל הלקוח דף ייעודי תחת 'הגדרות → API ו-Webhooks' שמסביר למתכנתי הלקוח איך להתחבר ל-Shipnest, באותו הקונספט של מדריכי החיבור הקיימים ל-WooCommerce / קונימבו / CashCow / Shopify — המדריך חי באזור השימוש, לא בעמוד …
פרטים נוספים ↓הסתר ↑
נוסף לפורטל הלקוח דף ייעודי תחת 'הגדרות → API ו-Webhooks' שמסביר למתכנתי הלקוח איך להתחבר ל-Shipnest, באותו הקונספט של מדריכי החיבור הקיימים ל-WooCommerce / קונימבו / CashCow / Shopify — המדריך חי באזור השימוש, לא בעמוד תיעוד נפרד שצריך לחפש. הדף בנוי כשישה קלפים ממוספרים: תחילת עבודה (עם curl ראשון מותאם ל-Base URL של הלקוח), טבלת scopes, רשימת endpoints מלאה (shipments, customers, webhook subscriptions), הסבר על Outbound Webhooks (אירועים, אימות HMAC, retries) ב-details collapsible, שיטות עבודה מומלצות (אבטחה, idempotency, polling vs webhooks, rate limits), ופרומפט מוכן ל-AI שמותאם דינמית עם tenantId ו-baseUrl של הלקוח וכפתור 'העתק' מובנה.
- נתיב חדש /portal/settings/api עם server-rendered SSR — Base URL ו-tenantId נשלפים מה-session ומה-request host, אז ה-curl examples וה-AI prompt מותאמים אישית
- כפתור 'העתק פרומפט' עם fallback ל-execCommand('copy') לדפדפנים ישנים / contexts לא מאובטחים
- AI prompt בן כ-60 שורות כולל auth, response envelope, רשימת endpoints מלאה (15 endpoints), קטלוג ה-events, פורמט החתימה, ו-conventions (כסף ב-agorot, זמנים UTC) — מוכן להדבקה כ-system prompt ב-Claude/ChatGPT/Cursor
- סעיף Outbound Webhooks משתמש ב-details/summary native כדי לחסוך אורך דף — 4 sub-cards (אירועים, headers, אימות חתימה ב-Node.js, retries) מתקפלים
- נוסף פריט סייד-בר 'API ו-Webhooks' עם CodeIcon מתחת ל'הגדרות', לפני warehouse module
v01.39.001תיקוןui/themeתיקון הבזק שחור בכותרת טבלת המשלוחים במצב לייט
משתמשים עם Windows ב-Dark וכרום שמציג ב-Light ראו הבזק שחור בשורת הכותרת של טבלת המשלוחים בכל רענון/ניווט, ממש לפני שהתוכן עלה.
פרטים נוספים ↓הסתר ↑
משתמשים עם Windows ב-Dark וכרום שמציג ב-Light ראו הבזק שחור בשורת הכותרת של טבלת המשלוחים בכל רענון/ניווט, ממש לפני שהתוכן עלה. הסיבה: תיקון FOUC קודם הזריק משתני dark דרך @media (prefers-color-scheme: dark) על :root:not(.light), אבל ה-class="light" של next-themes נוסף ל-html רק אחרי שה-ThemeProvider בתוך ה-body נטען — בפער הזה ה-CSS פתר את bg-muted/95 ו-bg-card של ה-thead לערכי כהים, ואז התהפך לבן. עכשיו ה-theme של המשתמש נשמר ב-cookie 'shipnest-theme' ו-layout.tsx (server component) מצמיד את ה-class ל-<html> כבר ב-SSR — אין רגע ש-CSS פוגע במשתני dark עבור משתמש light. ה-media query הותאם לעבוד רק כש-:root:not(.light):not(.dark) (visitor חדש בלי cookie). נוסף גם ThemeCookieSync שמסנכרן את ה-resolvedTheme ל-cookie בכל שינוי ערכה.
v01.39.000חדשwebhooksminorOutbound webhooks — הרחבת קטלוג האירועים מ-4 ל-8
קטלוג ה-events של ה-webhooks הציבוריים הוכפל: נוספו shipment.assigned (שיוך / העברת משלוח לשליח), shipment.failed (סימון כשל ע"י השליח, כולל סיבה ב-payload), visit.completed (השלמת ביקור — מקביל ל-shipment.delivered אבל …
פרטים נוספים ↓הסתר ↑
קטלוג ה-events של ה-webhooks הציבוריים הוכפל: נוספו shipment.assigned (שיוך / העברת משלוח לשליח), shipment.failed (סימון כשל ע"י השליח, כולל סיבה ב-payload), visit.completed (השלמת ביקור — מקביל ל-shipment.delivered אבל ברמת ה-Visit), ו-customer.created (יצירת לקוח חדש דרך API ציבורי או UI ניהול). בנוסף נסגר פער ותיק שבו ה-endpoint של המסירה ב-mobile (POST /api/v1/mobile/driver/visits/[id]/deliver) לא פלט shipment.delivered — עד כה האירוע הזה נפלט רק מנתיב הקליטה של Lionwheel, מה שהסביר שמשלוחים שנמסרו דרך האפליקציה לא הפעילו workflows חיצוניים.
- shipment.assigned נפלט מ-POST /api/v1/mobile/admin/visits/[id]/assign (גם שיוך ראשון וגם העברה משליח לשליח — payload מבחין עם action: 'assigned' | 'transferred')
- shipment.failed נפלט מ-POST /api/v1/mobile/driver/visits/[id]/fail עם reasonCode (no_answer / wrong_address / refused / closed / other) + reason טקסטואלי
- visit.completed + shipment.delivered נפלטים יחד מ-POST /api/v1/mobile/driver/visits/[id]/deliver (visit.completed מתאר את המאורע הטכני, shipment.delivered את המאורע העסקי)
- customer.created נפלט מ-POST /api/v1/customers (source: 'api') וגם מ-POST /api/customers הפנימי (source: 'admin') — מאפשר ל-CRM חיצוני להישאר מסונכרן ללא תלות בערוץ היצירה
- עודכנו רשימת ה-events ב-(platform)/admin/webhooks/page.tsx ובדף התיעוד הציבורי (legal)/api/page.tsx — שתיהן רואות עכשיו את שמונת ה-events
v01.38.002שיפורdistribution-gapsפערי הפצה — חגים יהודיים וערבי חג אינם נחשבים ימי עסקים
חישוב ימי העסקים בכל הטאבים של פערי הפצה (פערי מסירה / קריטיים / יום אחרון / פערי איסוף / כפולות) דילג עד היום רק על שישי ושבת.
פרטים נוספים ↓הסתר ↑
חישוב ימי העסקים בכל הטאבים של פערי הפצה (פערי מסירה / קריטיים / יום אחרון / פערי איסוף / כפולות) דילג עד היום רק על שישי ושבת. נוסף דילוג על חגים יהודיים אסורים במלאכה ועל ערבי החג שלהם: ר"ה (2 ימים), יוה"כ, סוכות יום א', שמיני עצרת, פסח יום א', שביעי של פסח, שבועות — כולם כולל ערב; וגם יום העצמאות ותשעה באב (ללא ערב). שינוי זה מתקן מצב שבו טאב 'יום אחרון להפצה' הציג רק 2 משלוחים השבוע כי תאריך הגורם נפל ביום חמישי 21.5 שהיה ערב שבועות. אחרי השינוי הטאב מציג כ-60 משלוחים — התפלגות חלקה במקום אנומליה.
v01.38.001תיקוןsecurityתיקון חקר אבטחה — הצגת משתמשים מחוברים מוגבלת לטננט
סריקת אבטחה חשפה 5 נקודות דליפה cross-tenant: (1) /api/users/online/stream החזיר משתמשים מכל הטננטים; (2-4) שלושת ה-endpoints של sorting-errors (GET/PATCH/POST/stats) לא סיננו לפי tenantId — אפשרו קריאה ועדכון של שגיאות …
פרטים נוספים ↓הסתר ↑
סריקת אבטחה חשפה 5 נקודות דליפה cross-tenant: (1) /api/users/online/stream החזיר משתמשים מכל הטננטים; (2-4) שלושת ה-endpoints של sorting-errors (GET/PATCH/POST/stats) לא סיננו לפי tenantId — אפשרו קריאה ועדכון של שגיאות מיון משל טננטים אחרים; (5) /api/debug-sorting לא סינן sortingError לפי tenantId. כולם תוקנו.
v01.38.000חדשportalminorאינטגרציה עם Shopify — חיבור חנויות בינלאומיות מהפורטל
לקוחות הפורטל יכולים כעת לחבר את חנות ה-Shopify שלהם לצד WooCommerce, קונימבו ו-CashCow.
פרטים נוספים ↓הסתר ↑
לקוחות הפורטל יכולים כעת לחבר את חנות ה-Shopify שלהם לצד WooCommerce, קונימבו ו-CashCow. בניגוד ל-CashCow/Konimbo (polling), Shopify דוחפת אלינו הזמנות חדשות בזמן אמת דרך webhook (orders/create, orders/paid, orders/updated) שעובר אימות HMAC-SHA256 base64 בעזרת ה-signing secret של החנות. עם מסירה — שיפנסט יוצרת Fulfillment על ההזמנה ב-Shopify דרך FulfillmentOrders API עם מספר המעקב, כך שהלקוח הסופי מקבל מייל אישור אוטומטי.
- ShopifyClient (apps/web/lib/integrations/shopify/client.ts) — Admin REST API 2024-01, X-Shopify-Access-Token; metoder: listRecentOrders, getShop (לtestConnection), createFulfillmentFromOpenOrders (שולף FulfillmentOrders פתוחים ויוצר Fulfillment משולב עם tracking_info)
- Webhook handler משותף ב-/api/webhooks/store/[connectionId] מזהה את platform=shopify אוטומטית, מאמת HMAC-SHA256 base64 על raw body (zero-trust — אם אין secret מוגדר ל-tenant ה-webhook נדחה)
- PLATFORMS extended: 'Shopify' כאופציה רביעית בטופס; supportsWebhook=true (לא polling); requiresSecret=false (טוקן יחיד shpat_); validation מחמירה ש-storeUrl חייב להסתיים ב-.myshopify.com (Admin API לא תומך ב-custom domains)
- ShopifyGuide חדש בפאנל הצדדי של הדיאלוג: מדריך דו-שלבי עם deep links ל-Apps/Develop apps ו-Settings/Notifications מבוסס על ה-storeUrl, רשימת scopes נדרשים (read_orders, write_orders, read_fulfillments, write_fulfillments, read_assigned_fulfillment_orders), אזהרת 'הטוקן נחשף פעם אחת בלבד'
- testConnection מציג שם החנות מ-/shop.json + הודעות שגיאה ספציפיות ל-401/403/404/429 עם body snippet מהשרת
- notifyShopifyDelivered חוברה ל-/api/v1/mobile/driver/visits/[id]/deliver כ-fire-and-forget לצד WC/Konimbo/CashCow
v01.37.000חדשapi/v1minorPublic API — השלמת CRUD ל-shipments ו-customers
נוספו 3 endpoints שהיו חסרים תחת /api/v1/, בהמשך לסבב ה-webhook subscriptions: ביטול משלוח כ-state transition נפרד (לא PATCH רגיל, כי הוא צריך להיות idempotent ולפלוט אירוע), וקריאה/עדכון של לקוח בודד לפי id.
פרטים נוספים ↓הסתר ↑
נוספו 3 endpoints שהיו חסרים תחת /api/v1/, בהמשך לסבב ה-webhook subscriptions: ביטול משלוח כ-state transition נפרד (לא PATCH רגיל, כי הוא צריך להיות idempotent ולפלוט אירוע), וקריאה/עדכון של לקוח בודד לפי id. עם אלה, ה-set של פעולות CRUD שמותרות דרך מפתח API מספיק כדי לבנות workflow מלא ב-n8n/Make: ליצור משלוח, לעדכן אותו, לבטל אותו, ולנהל את כרטיס הלקוח שלו.
- POST /api/v1/shipments/[barcode]/cancel — קובע canceledAt, idempotent (קריאה שנייה מחזירה alreadyCancelled=true ב-meta בלי לפלוט שוב את ה-webhook), פולט shipment.status_changed עם newStatus=canceled, ותומך ב-body אופציונלי { reason } שמתווסף ל-orgNote
- GET /api/v1/customers/[id] — קריאת לקוח בודד, scoped אוטומטית ל-tenant של ה-API key, scope customers:read
- PATCH /api/v1/customers/[id] — עדכון name/email/phone/address/isActive בלבד; שדות פנימיים (lionwheelId, summitId, picking config, accounting visibility) חסומים בכוונה. מאפשר null מפורש לעמודות nullable
- כל ה-endpoints החדשים שומרים על הקונבנציות הקיימות: withPublicApi, .strict() ב-zod, tenant מ-API key בלבד, ולא מחזירים שדות פנימיים אפילו אם הם קיימים במודל
v01.36.001תיקוןui/themeתיקון הבהוב שחור בכותרת טבלאות במצב לייט מוד
בעת טעינת דפי טבלה (כמו /shipments), משתמשים שמערכת ההפעלה שלהם dark אבל בחרו במצב לייט באפליקציה ראו הבהוב שחור חזק בשורת הכותרת לפני ש-next-themes הספיק להוסיף את class="light" ל-html.
פרטים נוספים ↓הסתר ↑
בעת טעינת דפי טבלה (כמו /shipments), משתמשים שמערכת ההפעלה שלהם dark אבל בחרו במצב לייט באפליקציה ראו הבהוב שחור חזק בשורת הכותרת לפני ש-next-themes הספיק להוסיף את class="light" ל-html. תיקון ה-FOUC הקודם לדארק היה מוסיף משתני צבע כהים דרך @media (prefers-color-scheme: dark) על :root:not(.light), מה שגרם לפער קצר שבו bg-card ו-bg-muted נפתרו לערכים כהים. נוסף inline script ב-<head> של ה-layout שרץ סינכרונית, קורא את localStorage.theme (או prefers-color-scheme אם system), ומוסיף את class="light"/"dark" ל-<html> לפני שה-CSS מתפרש. ה-media query הקיים נשאר כ-fallback כש-JS כבוי.
v01.36.000חדשapi/v1minorPublic API — ניהול webhook subscriptions דרך מפתח API
נוספו endpoints תחת /api/v1/webhooks המאפשרים ליצור, לרשום, לעדכן, למחוק ולבדוק webhook subscriptions באמצעות מפתח API (bearer ship_live_…), במקום רק דרך לוח האדמין הפנימי.
פרטים נוספים ↓הסתר ↑
נוספו endpoints תחת /api/v1/webhooks המאפשרים ליצור, לרשום, לעדכן, למחוק ולבדוק webhook subscriptions באמצעות מפתח API (bearer ship_live_…), במקום רק דרך לוח האדמין הפנימי. זו אבן הבניין הראשונה לקראת חיבור Shipnest לפלטפורמות אוטומציה חיצוניות (n8n, Make) — שני אלה דורשים endpoint רישום דינמי כדי שה-Trigger nodes שלהם יוכלו להירשם לאירועים.
- GET /api/v1/webhooks — רשימת ה-subscriptions של ה-tenant; לא מחזיר את ה-secret
- POST /api/v1/webhooks — יצירת subscription חדש; מחזיר את ה-secret פעם אחת בלבד (חתימת HMAC-SHA256 על payloads יוצאים)
- GET/PATCH/DELETE /api/v1/webhooks/[id] — קריאה, עדכון (name/url/events/isActive), ומחיקה
- POST /api/v1/webhooks/[id]/test — שליחת ping בדיקה ל-URL הרשום (rate-limited ל-10/60s כי זה side-effect חיצוני)
- כל ה-endpoints דורשים scope webhooks:manage, scoped אוטומטית ל-tenant של מפתח ה-API, ועוברים דרך withPublicApi (X-Timestamp, rate-limit פר-מפתח)
- מקור היצירה נרשם כ-api_key:<id> ב-createdById לצורך audit trail (מבדיל מ-subscriptions שנוצרו דרך לוח האדמין)
v01.35.000חדשportalminorאינטגרציה עם CashCow — חיבור חנויות מהפורטל
לקוחות הפורטל יכולים כעת לחבר חנות CashCow לצד WooCommerce וקונימבו, באותה זרימה.
פרטים נוספים ↓הסתר ↑
לקוחות הפורטל יכולים כעת לחבר חנות CashCow לצד WooCommerce וקונימבו, באותה זרימה. כמו קונימבו — CashCow אינה תומכת ב-webhooks ב-Shipnest כרגע, ולכן מומשה זרימת polling: cron הרץ כל 5 דקות מושך מ-https://api.cashcow.co.il/Api/Stores/Orders את ההזמנות החדשות (DaysFromNow=1 לרגיל, 7 בריצה ראשונה כדי לכסות backlog) וממיר אותן ל-Shipments. המסירה מסונכרנת חזרה ל-CashCow: כשנהג מסמן visit כ-delivered, נשלח POST ל-/Api/Stores/SendOrderUpdate עם order_status_type=6 (Delivered) ועם barcode כ-tracking_code.
- שכבת אינטגרציה חדשה ב-apps/web/lib/integrations/cashcow/: client (REST), types (כולל enum סטטוסים מספריים של CashCow), mapper (כתובת בשדות נפרדים — StreetNameAndNumber, City, ApartmentNumber, FloorNumber), delivery-sync
- Cron חדש /api/cron/sync-cashcow-orders בלו"ז 5 דקות; pagination עד 10 דפים×20 הזמנות per store; ברירת מחדל מסננת רק status=4 (שולם)
- PLATFORMS extended: 'CashCow' מופיע כאופציה שלישית לצד WooCommerce וקונימבו
- טופס דינמי: עבור CashCow מוצגים API Token + שדה Store ID מספרי חובה (זיהוי החנות הספציפית בחשבון)
- הגדרות אופציונליות פר-חנות: storeId (חובה) ו-orderStatusFilter (קודי סטטוס מופרדים בפסיקים — 4=שולם, 6=נמסר, 7=בבדיקה, 9=נדרש החזר)
- CashCowGuide חדש בפאנל הצדדי של הדיאלוג — מדריך 2 שלבים: קבלת Access Token מ-app.cashcow.co.il → Account settings → API/Webhooks settings, ואיתור Store ID מ-URL
- validation ב-zod: storeId חובה כאשר platform=cashcow (refine נוסף ב-createSchema)
- test-connection חדש ל-CashCow מטפל ב-401/403/429 עם הודעות מפורטות בעברית, surfaces את ה-body של CashCow
- delivery-sync שולף את email מ-additionalData (CashCow דורש email_address ב-SendOrderUpdate כאימות ownership של ההזמנה)
v01.34.000חדשportalminorאינטגרציה עם קונימבו — חיבור חנויות ישראליות מהפורטל
לקוחות הפורטל יכולים כעת לחבר את חנות הקונימבו שלהם דרך לשונית 'החנויות שלי' באותה זרימה כמו WooCommerce.
פרטים נוספים ↓הסתר ↑
לקוחות הפורטל יכולים כעת לחבר את חנות הקונימבו שלהם דרך לשונית 'החנויות שלי' באותה זרימה כמו WooCommerce. בניגוד ל-WooCommerce (push דרך webhooks), קונימבו לא תומכת ב-webhooks ולכן מומשה זרימת polling — cron הרץ כל 5 דקות מושך מ-https://api.konimbo.co.il/v1/orders את כל ההזמנות החדשות מאז ה-lastSyncAt וממיר אותן ל-Shipments. המסירה מסונכרנת חזרה לקונימבו: כשנהג מסמן visit כ-delivered, סטטוס חדש מתווסף להזמנה בקונימבו דרך PUT /v1/orders/{id}.
- שלוש שכבות חדשות: KonimboClient (REST), mapper (כתובת עברית מפורקת מ-string מאוחד), delivery-sync
- Cron חדש /api/cron/sync-konimbo-orders בלו"ז 5 דקות; מסונכרן רק מ-lastSyncAt (או createdAt בריצה ראשונה — בלי לייבא היסטוריה)
- PLATFORMS extended: 'קונימבו' מופיע כאופציה בבחירת פלטפורמה לצד WooCommerce
- טופס דינמי: עבור Konimbo רק 'API Token' (Consumer Secret/Webhook Secret מוסתרים)
- הגדרות אופציונליות פר-חנות (JSONB חדש על CustomerStoreConnection): paymentStatusFilter (default 'שולם,אשראי - מלא'), shippedStatusText (default 'נשלח')
- KonimboGuide חדש בפאנל הצדדי של הדיאלוג — מדריך 2 שלבים עם deep link לאזור הניהול
- תיקון deep links במדריך קונימבו — admin מרוכז ב-secure.konimbo.co.il (לא תלוי-חנות); קישור ישיר ל-/admin/api_users במקום ניווט ידני
- הנחיות מדויקות במסך יצירת משתמש API בקונימבו — איזה כפתור הרשאה להפעיל ('Orders - Used Externally'), מה לרשום ב'שם משתמש'/'מצב משתמש'/'access control allow origin', איפה הטוקן מופיע אחרי שמירה
- מודל DB: עמודה settings JSONB חדשה ב-customer_store_connections (גנרי לפלטפורמות עתידיות)
- מובייל — מרקרי מפתח בולטים: מרקר שליח כחול (42×42, halo שקוף + אייקון navigation + תווית 'אני') בכל המצבים פרט לציור; מרקר סיום כתום (flag, halo כתום, תווית שם המיקום); מרקר התחלה ירוק — עיגול עם play icon כשהמסלול התחיל מ-GPS, או טבעת ירוקה (startPinHalo) על ה-teardrop pin של הביקור הראשון ב-kind:visit/auto; state RouteStart מאפס בכל handleClear/handleEdit/enterDrawing/handleStartRoute
- מחסן Phase 4D.5 — זיהוי עומס אזורים: congestion.ts פונקציה טהורה מחשבת ציון עומס פר WhLocation.zone (משימות ממתינות + מלקטים פעילים×2 + סגמנטים IN_PROGRESS×3); סף 5 → אזור מסומן כעמוס
- GET /api/warehouse/congestion — חישוב live ללא טבלה, owner-scoped, עטוף ב-withWarehouseApi; ZoneCongestionPanel ב-MetricsDashboard עם רמות clear/moderate/high, רענון אוטומטי כל 2 דקות
- אינטגרציה אדיטיבית ב-batch-suggestion.ts: groupFulfillmentsByProximity מקבל congestedZones?:Set<string>; קנס של 10 נקודות פר אזור עמוס; ה-API contract לא השתנה
- 25 טסטים חדשים ל-congestion.ts — כיסוי מלא: ציון, ספירת מלקטים ייחודיים, מיון יורד, סף מותאם
- פורטל — מדריך חיבור WooCommerce state-aware: Step 1 מסומן ✓ כשהמפתחות מוזנים, Step 2 (Webhook) נפתח אוטומטית; מצב עריכה — Step 1 תמיד ✓, Step 2 פתוח עם ה-URL האמיתי; StoreCard — אחרי בדיקת חיבור מוצלחת מוצג CTA ישיר למדריך ה-Webhook
v01.33.000חדשwarehouseminorמחסן — סנכרון מלאי יוצא לחנויות eCommerce
Phase 4A.6 — שינוי מלאי במחסן מתעדכן אוטומטית בחנויות Shopify ו-WooCommerce המחוברות.
פרטים נוספים ↓הסתר ↑
Phase 4A.6 — שינוי מלאי במחסן מתעדכן אוטומטית בחנויות Shopify ו-WooCommerce המחוברות. כל שינוי ב-WhInventory (התאמה ידנית, ליקוט מאושר) מפעיל דחיפת רמת מלאי דרך ה-connector המתאים עם retry ו-backoff. כשל דחיפה מבודד לחלוטין — לא מפיל פעולות מחסן, נרשם ב-WhStoreSyncLog. פאנל יומן סנכרון מציג רשומות נכנסות ויוצאות per-connection עם מצב הצלחה/כשל. סנכרון מלאי ידני זמין ברשימת החיבורים. בנוסף: מערכת offline sync במובייל — פעולות COD/POD/Fail נשמרות בתור כשאין חיבור ומסונכרנות כשהחיבור חוזר; SyncChip בכותרת מציג סטטוס סנכרון בזמן אמת. שיפורי route optimizer — תמיכה ב-startVisitId וב-endLocationId, הוסף endLeg לתוצאה.
- inventoryChangedEvents — event-bus חדש; יורה מ-inventory/adjust ומ-pick-tasks confirmPick
- inventory-sync.ts: pushProductInventoryToStores עם retry 3 ניסיונות + backoff; כשל מתמשך ⇒ lastError על החיבור
- ליקוט מאושר (confirmPick) גם מפחית WhInventory.quantity ⇒ push אוטומטי לחנות
- POST /api/warehouse/connections/[id]/sync-inventory — דחיפת כל המוצרים הממופים ידנית
- GET /api/warehouse/connections/[id]/sync-logs — לוג סנכרון owner-scoped
- ConnectionSyncLogPanel — Sheet עם יומן סנכרון, כפתור 'סנכרן מלאי עכשיו', lastSyncAt
- פעולת 'יומן סנכרון' נוספה לרשימת החיבורים
- 9 טסטים חדשים — computeAvailableQuantity + buildSyncLogMessage; סה"כ 472 טסטים
- מובייל: offline-queue-store + net-status listener — פעולות משלוח עובדות ללא רשת
- מובייל: SyncChip בHomeHeader — מציג pending/syncing/failed בזמן אמת
- מובייל: RTL self-heal reload עם AsyncStorage guard למניעת לולאה אינסופית
- Route optimizer: תמיכה ב-startVisitId (נקודת התחלה מקובעת) ו-endLocationId, הוסף endLeg לתוצאה
- מובייל — מסך מפה: RouteSetupSheet — רשימת המשלוחים הנבחרים עם כפתור 'התחל מכאן' לכל משלוח (startVisitId), כפתורי 'התחל ממיקומך' (GPS) ו'בחירה אוטומטית' בפוטר; בורר נקודת סיום משפיע על שלושתם; ספינר per-button בזמן חישוב; מרקר ירוק של נקודת הסיום על המפה
- מובייל — מסך 'מיקומים שמורים' (4B): ניהול מלא — הוספה/עריכה/מחיקה עם אישור; geocoding בשמירה; מתג ברירת מחדל; כניסה מהגדרות; queryKey משותף עם המפה → עדכון אוטומטי של בורר נקודת הסיום
- מובייל: useVisitSyncStatus מומש — קורא את תור ה-offline פר-ביקור ומחזיר pending/failed/action; קודם היה stub שהחזיר false קבוע, כך שה-badge 'ממתין' וחסימת הכפתורים במסך הביקור לא פעלו
- מובייל: תיקון fallback ה-offline במסך פרטי ביקור — useVisit עבר מ-placeholderData ל-initialData; placeholderData נזרק כשהשאילתה נכשלת, מה שגרם למסך ליפול ל-ErrorState אחרי ~3ש offline
- מובייל: התחלת משמרת עמידה לכשל מעקב מיקום — startShift לא נכשל יותר כש-startLocationUpdatesAsync זורק, ו-restoreTrackingIfNeeded לא מסיים משמרת פעילה; מעקב מיקום הוא best-effort
- מובייל: זמן מסירה/כשל נרשם לפי הרגע שהשליח ביצע את הפעולה במכשיר (occurredAt מתור ה-offline) ולא לפי זמן הסנכרון; שעון מכשיר עתידי עובר clamp ל-now
- Phase 4B.1 — DB: WhTote + WhZoneSegment (+enums WhToteStatus/WhZoneSegmentStatus) — בסיס ל-Cluster & Zone picking
- Phase 4B.2 — CLUSTER picking: WhPickType הורחב (CLUSTER/ZONE); יצירת אצווה CLUSTER מקבצת N הזמנות, יוצרת WhTote פר-fulfillment, מנתבת S-shape על האיחוד; GET /batches/[id] מחזיר tote פר-משימה; 11 טסטים חדשים ל-cluster-utils
- Phase 4B.3 — מסך ליקוט מובייל תומך ב-CLUSTER: TaskCard מציג שורת 'שבץ לטוטה' (קוד טוטה, אייקון inbox) כשtote != null; snapshot API מחזיר WhTotes לאצוות CLUSTER (additive — מערך ריק עבור SINGLE/BATCH); buildTasksFromSnapshot ממפה fulfillmentId→tote; GET /api/v1/mobile/warehouse/batches/[id] כולל tote פר-משימה; WhBatchSummary.type הורחב ל-CLUSTER|ZONE
- Phase 4B.4 — ZONE picking engine: batch POST מחלק משימות לפי WhLocation.zone, ניתוב S-shape פר-אזור בנפרד, סדר ביקור אזורים מ-S-shape הגלובלי, יצירת WhZoneSegment פר-אזור (ראשון READY, שאר PENDING), WhTote יחידה לבאצ'ה; zone-segment-progression.ts — לוגיקה טהורה: nextSegmentToActivate + areAllSegmentsCompleted; GET /api/warehouse/zone-segments?batchId + PATCH /api/warehouse/zone-segments/[id] (assign/start/complete עם מעבר תוטה ACTIVE↔STAGED↔CLOSED); 16 טסטים חדשים; סה"כ 499 טסטים
- Phase 4B.5 — Zone picking במובייל: GET /api/v1/mobile/warehouse/batches/[id] מחזיר zoneSegments לאצוות ZONE; PATCH /api/v1/mobile/warehouse/zone-segments/[id] (start/complete) — auth מובייל, auto-assign pickerId, זהה לתוגיקת Zone engine; [batchId].tsx — מסך בורר אזורים (READY: 'התחל', IN_PROGRESS: 'המשך', PENDING: נעול, COMPLETED: ✓), משימות מסוננות לאזור הפעיל, מסך 'סיים אזור ומסור טוטה' לאחר השלמת כל משימות האזור; כפתור download מוחלף באייקון wifi — אצוות ZONE אינן offline-capable; zone field נוסף ל-OfflineLocation + snapshot API (additive)
- Phase 4B.6 — UI יצירה וניטור אצוות: BatchCreateDialog — 4 כרטיסי אסטרטגיה (SINGLE/BATCH/CLUSTER/ZONE) עם תיאור, SINGLE מגביל לבחירה אחת; BatchDetailSheet — פאנל טוטות ל-CLUSTER (קוד, סטטוס ACTIVE/STAGED/CLOSED, התקדמות משימות פר-הזמנה), פאנל סגמנטי אזור ל-ZONE (רצף, שם אזור, סטטוס, מלקט, התקדמות), עמודת סוג בטבלה צבעונית; GET /api/warehouse/batches/[id] מחזיר totes + zoneSegments + zone בלוקיישן; רכיב אחד משותף לצוות ולפורטל
- פורטל — מדריך חיבור WooCommerce עודכן על-בסיס בדיקה חיה: הוסף אזהרת סדר פעולות (חיבור בפורטל קודם, הגדרת webhook אחר-כך), הדגשה על העתקת ה-URL המלא דרך כפתור ההעתקה, והבהרה ש-WooCommerce ממלא את שדה ה-Secret אוטומטית — יש להשאיר ריק
- בדיקות אוטומטיות Feature C (route endpoints): 11 טסטים חדשים ל-optimizer.test.ts (startVisitId+endLocation combo, end-never-in-middle, single-visit edge cases, startLocation precedence) + קובץ route-api-helpers.ts עם 3 פונקציות טהורות (startVisitIdInList, startVisitSurvivedFilter, buildMatrixPoints) + 19 טסטים ב-route-api-helpers.test.ts
- תיקון באג: geocoding מיקום שמור עלול להחזיר עיר שגויה כשרחוב קיים בכמה ערים — הקו על המפה נמשך לעיר הלא נכונה. נוספה isGeoWithinCity ב-geocoding.ts (haversine בין תוצאת geocoding למרכז היישוב מה-Settlement table, סף 10 ק"מ); POST ו-PATCH של saved-locations מחזירים 422 GEOCODE_CITY_MISMATCH כשהפער גדול; כשהיישוב לא נמצא בטבלה — אין דחייה. סה"כ 590 טסטים
- Phase 4D.1 — DB: WhReplenishmentAlert + WhSlottingRecommendation (+enums WhAlertStatus/WhRecommendationStatus) owner-scoped — בסיס לאנליטיקה היוריסטית; שלד analytics/ (consumption/slotting/batch-suggestion/congestion) — פונקציות טהורות בלבד, ללא DB ישיר, ללא ML
- פורטל — ויזרד חיבור חנות דו-שלבי: שלב 1 בחירת פלטפורמה + URL + שם; שלב 2 מפתחות API עם מדריך ישיר ולינקים חיים; פאנל ימין מציג תקציר מה נדרש בשלב 1 ומדריך מלא בשלב 2; edit mode עוקף לשלב 2 ישירות
- Phase 4D.2 — התראות חידוש מלאי: consumption.ts — 5 פונקציות טהורות (computeDailyConsumptionRate, computeDaysToDepletion, shouldRaiseAlert, buildReplenishmentRationale, computeReplenishmentForProduct) + 30 טסטים; POST /api/warehouse/replenishment/run — ניתוח owner-scoped, קצב מ-WhPickTask (חלון 30 יום), upsert להתראה, auto-resolve כשסיכון חלף; GET /api/warehouse/replenishment — רשימת התראות עם שם מוצר; PATCH /api/warehouse/replenishment/[id] — ACKNOWLEDGED/RESOLVED; ReplenishmentAlertsView — כרטיסי מוצר עם מלאי/קצב/ימים-נותרים, urgency צבע, 'הרץ ניתוח עכשיו'; 564 טסטים
- Phase 4D.3 — Slotting — אופטימיזציית מיקום מלאי: slotting.ts — 6 פונקציות טהורות (computeLocationTravelCosts — שימוש חוזר ב-S-shape, computePickVelocities, computeAffinityPairs, computeVelocityRecommendations, computeAffinityRecommendations, computeSlottingRecommendations) + 26 טסטים; inventory-adjust-helper.ts — applyInventoryAdjust + moveInventoryBetweenLocations שעוטפים נתיב ה-Phase 1 (upsert+event) בלי שכפול; POST /api/warehouse/slotting/run — ניתוח owner-scoped, velocity + affinity, upsert המלצות; GET /api/warehouse/slotting — רשימה עם שמות מוצר ומיקום; PATCH /api/warehouse/slotting/[id] — apply (העברת מלאי דרך moveInventoryBetweenLocations+invalidate inventory) | dismiss; SlottingRecommendationsView — כרטיסי המלצה עם מיקום נוכחי/מוצע, חיסכון משוער, נימוק, Confirm Dialog לאישור, 'הרץ ניתוח עכשיו'; 590 טסטים
- Phase 4D.4 — הצעות אצוות חכמות: batch-suggestion.ts — 6 פונקציות טהורות (computeZoneJaccard, countSharedZones, selectStrategy, buildRationale, computeGroupScore, groupFulfillmentsByProximity) + 46 טסטים; groupFulfillmentsByProximity — אלגוריתם greedy clustering לפי חפיפת אזורים; selectStrategy — SINGLE/BATCH/CLUSTER/ZONE לפי מספר אזורים ו-fulfillments; GET /api/warehouse/batch-suggestions — מחושב live ללא טבלה, owner-scoped, מפשר שמות מוצר ← WhInventory → WhLocation → zones; BatchCreateDialog — פאנל 'הצעות חכמות' מעל כרטיסי האסטרטגיה, קליק על הצעה ממלא selectedIds+pickType, יצירה דרך מנוע POST /api/warehouse/batches הקיים — ללא שכפול ולא עקיפה; 636 טסטים
v01.32.000חדשcreditsminorזיכויים — טאב היסטוריית עריכה
הוספת מעקב אחר כל הפעולות על זיכוי: יצירה, עריכה, אישור וביטול.
פרטים נוספים ↓הסתר ↑
הוספת מעקב אחר כל הפעולות על זיכוי: יצירה, עריכה, אישור וביטול. כל פעולה נשמרת ב-AuditLog עם שם המשתמש, זמן הפעולה, ורשימת השדות שהשתנו (לפני/אחרי). בפאנל הזיכוי נוסף טאב 'היסטוריה' עם ציר זמן מקובץ לפי תאריך.
- logAudit ב-create, update, approve ו-cancel — כולל diff שדות לעדכון
- GET /api/credit-notes/[id]/activity-log — מחזיר רשומות עם שם משתמש ושינויי שדות מפורמטים
- CreditNoteSheet — טאב 'פרטים' / 'היסטוריה'; ציר זמן מקובץ לפי תאריך עם badge צבעוני לכל פעולה
- AuditAction type הורחב ל-approve ו-cancel
- טופס זיכוי — רשימת הלקוחות מצטמצמת אוטומטית לשולחי המשלוחים שנבחרו (intersection לפי customerId). שדה הלקוח והשליח עצמאיים — סינון רק על לקוח כי השליח האמיתי במסירה עשוי להיות אחר. שדה customerId נחשף ב-/api/shipments barcode lookup וב-global search
v01.31.000חדשmobileminorמובייל — חיווי סנכרון offline ומסך ניהול תור
Phase E של מנוע ה-Offline: שכבת UX גלובלית מעל המנוע הקיים.
פרטים נוספים ↓הסתר ↑
Phase E של מנוע ה-Offline: שכבת UX גלובלית מעל המנוע הקיים. באנר amber מופיע מתחת ל-SafeArea כשאין חיבור לרשת. chip סנכרון ב-HomeHeader מציג מצב התור בסדר עדיפויות: כשלים (אדום) > מסנכרן > ממתינים (amber). לחיצה על ה-chip פותחת מסך סנכרון ייעודי עם רשימות pending/failed, כפתורי 'נסה שוב' ו'מחק' פר-פריט, וכפתור 'סנכרן עכשיו' גלובלי. הוספו actions חדשים לסטור: retryOne(id) ו-removeAction(id). store קישוריות חדש (connectivity-store) מוזן על-ידי מאזין NetInfo הקיים. תיקון: שגיאת Meta 131048 (הגבלת מספר טלפון עקב ספאם) מוצגת כעת בעברית. מסגרת הסריקה (scan.tsx ו-[batchId].tsx) הוגדלה לדינמית — 85% מרוחב המסך במקום 250px קבועים.
- OfflineBanner — פס amber מתחת ל-safe-area, מופיע/נעלם לפי קישוריות
- SyncChip ב-HomeHeader — עדיפות: כשלים > מסנכרן > ממתינים > מוסתר
- מסך sync-status: רשימות pending/failed, retry/delete פר-פריט, 'סנכרן עכשיו'
- connectivity-store: Zustand ללא persist, מוזן מ-NetInfo הקיים
- retryOne(id) ו-removeAction(id) נוספו ל-offline-queue-store
- Phase F — תשתית vitest: 4 סוויטות בדיקות (33 טסטים) לכיסוי connectivity-store, offline-queue-store, net-status ו-sync-processor; checklist בדיקה ידנית ל-5 תרחישי offline
- מפה: בורר סגנון מתעדכן מיידית עם חזרה לטאב (useFocusEffect)
- מפה: תיקון ציור פוליגון — worldSize 512 + unproject מ-MapLibre בסיום הגרירה
- מפה: markers שוחזרו לעיצוב pin טיפתי (עיגול + גוף מחודד) עם צל
- מפה: תיקון offset ציור פוליגון — mapLayout הומר מ-state ל-ref כדי למנוע closure מושרש בגובה חלון מלא
- webhook: תיקון סנכרון פריטי הזמנה מליונוויל — כאשר ה-webhook לא כולל order_items, מביאים אותם ישירות מה-API; מעתה מסתנכרנים גם ביצירת משלוח חדש ולא רק בעדכון
- סכמה — תכונה C שלב 1: מודל DriverSavedLocation (מיקומים שמורים פר-שליח לנקודות סיום מסלול) + שדה endLocationId ב-RouteBuild; Prisma client עודכן
- אופטימייזר מסלול — תכונה C שלב 2: startLocation/endLocation כצמתים אמיתיים במטריצה; חתימה חדשה optimizeRoute(visits, options?, matrix?); haversine fallback מאוחד לנתיב יחיד; endLeg בתגובה; 31 בדיקות יחידה
- תכונה C שלב 3A — API מיקומים שמורים לשליח: GET/POST /api/v1/mobile/driver/saved-locations + PATCH/DELETE /[id]; geocoding חובה ביצירה ובעדכון כתובת; cap 20 מיקומים; טרנזקציית isDefault; קליינט מובייל saved-locations.ts
- תכונה C שלב 3B — route/optimize + route/activate: startVisitId, endLocationId; מטריצה כוללת endPoint; geometry מסתיים בנקודת הסיום; endLeg בתגובה (finalLegKm/Minutes); RouteBuild שומר endLocationId; קליינט מובייל מורחב
- ייבוא משלוחים — כפתור "ייבא מחדש" נפרד: טוען את כל השורות מייבוא קודם (כולל הצלחות) לייבוא חוזר של אותה עבודה שבועית; "ייבא כשלים" ממשיך לעבוד כרגיל ומוצג רק כשיש כשלים
- Phase 4A.1 — eCommerce Store Connections: 4 מודלים חדשים (WhStoreConnection, WhStoreProductLink, WhStoreOrderLink, WhStoreSyncLog) + 4 enums; CRUD /api/warehouse/connections owner-scoped, credentials מוצפנים AES-256-GCM, לעולם לא מוחזרים ב-API
- Phase 4A.2 — Connector abstraction: ממשק EcommerceConnector אחיד; ShopifyConnector (Admin API + HMAC) ו-WooCommerceConnector (REST Basic Auth + HMAC) — אדישים-לפלטפורמה, ללא if-platform בלוגיקת הליבה; factory createConnector; POST /api/warehouse/connections/[id]/test מעדכן status/lastError; domain types ב-apps/api/src/modules/warehouse/; 22 טסטי יחידה (HMAC + נרמול הזמנה) — ירוקים
- Phase 4A.3 — מסך חיבורי חנות: StoreConnectionsView (UnifiedTable, badges פלטפורמה/סטטוס, tooltip שגיאה, זמן סנכרון יחסי) + StoreConnectionForm (password fields, toggle show/hide, credentials לעולם לא מוחזרים ב-UI); פעולות שורה: בדיקה / עריכה / השבתה / מחיקה; דפי staff+portal thin wrappers; ניווט sidebar (staff + portal)
- Phase 4A.4 — מיפוי מוצרים (SKU auto-match + ידני): autoMatchProducts() — פונקציה טהורה עם 11 טסטים (התאמת SKU case-insensitive, מניעת כפילויות, owner-scope isolation); API: GET/POST /product-links, POST /product-links/import (fetchProducts + bulk match), DELETE+PATCH /product-links/[linkId]; StoreProductMappingView — טבלת מיפויים, banner תוצאות ייבוא, רשימת unmatched למיפוי ידני; StoreProductMapDialog — חיפוש WhProduct + אישור; דף staff+portal; פעולת 'מיפוי מוצרים' ברשימת החיבורים
- Phase 4A.5 — ייבוא הזמנות: webhook POST /api/webhooks/warehouse/[connectionId] קולט order.created מ-Shopify ו-WooCommerce (אימות HMAC, flag check, אידמפוטנטיות דרך WhStoreOrderLink); ייבוא ידני POST /api/warehouse/connections/[id]/import-orders עם פרמטר days; לוגיקת ייבוא ב-order-import.ts: parseStreetAddress/normalisePhone/findUnmatchedSkus — פונקציות טהורות עם 20 טסטים; יצירת Shipment + WhFulfillment(NEW) + WhStoreOrderLink + WhStoreSyncLog בטרנזקציה אחת; שורה ללא מיפוי SKU — נרשמת ב-SyncLog כאזהרה ולא מפילה ייבוא; פעולת 'ייבא הזמנות' נוספה לרשימת החיבורים
- מובייל: מרחק בכל כרטיס ביקור מחושב עתה client-side מ-GPS הנהג (haversine) — מוצג לכל ביקור כולל 'לא במסלול'; fallback לערך ה-API כאשר GPS אינו זמין
- תיקון offline — מסך פרטי ביקור נטען מ-cache של 'היום שלי' כשאין רשת (placeholderData ב-useVisit; error gate שונה ל-isError && !data בכל מסכי הביקור)
- תצוגת ציר זמן — תיקון: 'יציאה' מוצגת רק לאחר שה-visit בוצע בפועל (נמסר/כשל) או שהתקבל OUT_INVENTORY; קודם cron rollover-open-visits היה מזיז את visitAt להיום וגורם לתאריך כוזב
- תיקון: סינון לפי סטטוס נכשל (ואחרים) גרם ל-500 — עמודת error_code הוזכרה בשאילתת raw SQL בשם "errorCode" (camelCase במרכאות) במקום error_code, מה שגרם ל-Postgres לזרוק שגיאה; תוקן ל-s.error_code as "errorCode"
- ציר זמן — מיון אירועים לפי תאריך עם עדיפות לוגית לבו-זמניים (ליקוט ← איסוף ← קליטה); קו סגול בין אירועים שקרו באותה דקה
- תיקון: חיפוש משלוח בטופס יצירת זיכוי לא החזיר תוצאות — API דרש תאריכים גם לחיפוש לפי ברקוד; נוסף early-return ייעודי ל-barcode query שעוקף את חובת טווח התאריכים
- מחירון לקוח — תיקון מילוי אוטומטי: מעבר מ-onBlur ל-onChange עם מצב autoFillSource; כל עוד המשתמש מקליד בשדה הראשון, כל שאר השדות מתעדכנים בזמן אמת; עם יציאה מהפוקוס המילוי האוטומטי מסתיים ולכל שדה ערך עצמאי
- תיקון: שדות סכומים בטופס זיכוי — אייקון ₪ ומספר נצמדו שמאלה ודרסו אחד את השני; תוקן ל-right-3/pr-8 בהתאם לפטרן במחירון הלקוח
v01.30.001תיקוןmobileמובייל — תיקון תוויות מפה לעברית (MapLibre vector)
הפרמטר &language=he ב-URL של style.json אינו מלקלל תוויות וקטוריות — הן מרונדרות בצד הלקוח לפי text-field של שכבות הסמלים.
פרטים נוספים ↓הסתר ↑
הפרמטר &language=he ב-URL של style.json אינו מלקלל תוויות וקטוריות — הן מרונדרות בצד הלקוח לפי text-field של שכבות הסמלים. התיקון: טעינת style JSON, מעבר על כל שכבות symbol, והחלפת text-field ל-coalesce name:he/name:latin/name. בנוסף תוקנו שלוש רגרסיות: (1) הגנת usesNameField — רק שכבות מבוססות name משוכתבות, שלטי כבישים (ref), גובה (ele) ומספרי בית נשמרים ללא שינוי. (2) לחיצה על marker של עצירה פותחת כרטיס פרטים — הוספת markerJustPressedRef למניעת ביטול ידי Map.onPress. (3) markers הוגדלו ל-22px עם צל לשיפור נראות וקלות לחיצה.
v01.30.000חדשwarehouse, integrationsminorמחסן — חוויית offline מלאה + מסך הכרעת קונפליקט
Phase 4C.6: חוויית offline שקופה למלקט.
פרטים נוספים ↓הסתר ↑
Phase 4C.6: חוויית offline שקופה למלקט. באנר קישוריות אדום בכל מסכי המחסן בעת חוסר רשת. תג סטטוס offline פר-אצווה ברשימה (זמינה offline / ממתינה לסנכרון / מסונכרנת / קונפליקט). מסך הכרעת קונפליקט: כשmutations נדחו — הצגת הפעולות שנדחו ואפשרות לבטל ולנקות. אזהרת קישוריות כשמנסים לגשת לאצווה לא מורדת בלי רשת. בנוסף: עיצוב מחדש של דף האינטגרציות — קיבוץ לפי קטגוריה (משלוחים / הנה"ח / WhatsApp) עם דיאלוגים ייעודיים לכל קטגוריה.
- ConnectivityBanner — מוצג בכל מסכי המחסן בעת חוסר רשת
- תג offline פר-אצווה ב-BatchCard עם צבע לפי סטטוס סנכרון
- ConflictResolutionSheet — הצגת פעולות מתנגשות + ביטול מאושר
- אזהרה מונעת גישה לאצווה לא מורדת בלי רשת
- לחיצה על סטריפ קונפליקט במסך הליקוט פותחת את מסך ההכרעה
- דף אינטגרציות: קיבוץ לפי קטגוריה — ספק משלוחים (כרטיסייה אחת עם radio), הנה"ח, WhatsApp
- DeliveryDialog: radio לבחירת Lionwheel/בלדר/SmארטRun + toggle משלוחים עצמאיים
- AccountingDialog: ספק הנה"ח (Summit + עתידי) בדיאלוג ייעודי
v01.29.000שיפורintegrationsSummit — חיבור דרך דף האינטגרציות
אינטגרציית Summit עברה מקריאת מפתחות ממשתני סביבה גלובליים לטעינה per-tenant מ-TenantProviderConfig, בדיוק כמו Lionwheel ו-Meta.
פרטים נוספים ↓הסתר ↑
אינטגרציית Summit עברה מקריאת מפתחות ממשתני סביבה גלובליים לטעינה per-tenant מ-TenantProviderConfig, בדיוק כמו Lionwheel ו-Meta. נוסף שורת ExternalProvider ל-Summit ב-DB, וכעת ניתן להגדיר את המפתחות דרך דף הגדרות > אינטגרציות.
v01.29.000חדשwarehouseminorמחסן — מנוע סנכרון offline + זיהוי קישוריות
Phase 4C.5: מנוע סנכרון לאצוות שהורדו לעבודה offline.
פרטים נוספים ↓הסתר ↑
Phase 4C.5: מנוע סנכרון לאצוות שהורדו לעבודה offline. זיהוי קישוריות ב-NetInfo מפעיל סנכרון אוטומטי בחזרת רשת. outbox מנוקז לפי sequence ל-POST /api/v1/mobile/warehouse/sync עם retry ו-backoff מעריכי. תוצאות פר-mutation (applied/duplicate → synced, conflict → conflict). אינדיקטור סטטוס סנכרון ב-UI: ממתין לסנכרון / מסנכרן / מסונכרן / קונפליקט. כפתור 'סנכרן עכשיו' ב-UI. קוד הסנכרון בשרת הועבר ל-sync-core.ts משותף ל-web ו-mobile. אין רגרסיה בזרימה המקוונת מ-Phase 2.
- NetInfo — סנכרון אוטומטי בחזרת קישוריות
- Retry + exponential backoff (1s/2s/5s/10s/20s) על כשלי רשת ו-5xx
- idempotency: mutationId ב-WhSyncLog — duplicate מוחזר ולא מיושם פעמיים
- SyncBanner ב-batch list + sync strip ב-picking screen
- sync-core.ts — קוד מיושם ב-web וב-mobile route משותף
v01.28.000חדשmobileminorמובייל — בורר סגנון מפה בהגדרות
הוספת בורר סגנון מפה בדף הפרופיל.
פרטים נוספים ↓הסתר ↑
הוספת בורר סגנון מפה בדף הפרופיל. המשתמש יכול לבחור מ-4 סגנונות MapTiler: רחובות, שטח, לוויין, בהיר. הבחירה נשמרת ב-AsyncStorage וטעונה עם אתחול המפה. כל הסגנונות מוצגים בעברית מלאה (language=he).
- 4 סגנונות MapTiler לבחירה: streets-v2 / outdoor-v2 / hybrid / basic-v2
- Bottom-sheet Modal — חוויה נייטיב, ניתן לסגור בהקשה מחוץ
- בחירה נשמרת ב-AsyncStorage וטעונה עם כניסה למפה
- כל הסגנונות נטענים עם language=he — עברית תמיד
v01.27.000שיפורmobileminorמובייל — מעבר למפה וקטורית MapLibre (תוויות עברית)
שכתוב מסך המפה מ-react-native-maps למפה וקטורית אמיתית עם @maplibre/maplibre-react-native.
פרטים נוספים ↓הסתר ↑
שכתוב מסך המפה מ-react-native-maps למפה וקטורית אמיתית עם @maplibre/maplibre-react-native. תוויות המפה בעברית מלאה ב-streets-v2 של MapTiler ללא תלות בשפת המכשיר. כל ההתנהגות הקיימת נשמרה: סיכות ממוספרות, קווי מסלול עם גאומטריית OSRM, ציור פוליגון במגע, ושני מצבי route. המרת קואורדינטות בציור הועברה למשוואת Mercator שמחשבת מ-zoomLevel + center.
- מפה וקטורית — תוויות חדות בכל zoom, RTL-aware
- GeoJSONSource + Layer לקווי מסלול ופוליגון ציור
- Marker component לסיכות — תמיכה ב-custom views ממוספרים
- screenToLatLng מבוסס-Mercator — ציור פוליגון דיוק זהה
- בורר סגנון: mapStyle prop מ-AsyncStorage עם fallback
v01.26.001שיפורmobileמובייל — התקנת MapLibre (תשתית)
התקנת @maplibre/maplibre-react-native ^11.2.1 והוספת ה-plugin ל-app.json.
פרטים נוספים ↓הסתר ↑
התקנת @maplibre/maplibre-react-native ^11.2.1 והוספת ה-plugin ל-app.json. expo-dev-client כבר היה מותקן. הכנה לשכתוב מסך המפה ממפת הבסיס הנייטיב למפה וקטורית.
v01.26.000חדשwarehouse / mobileminorמחסן — ליקוט offline מלא למלקט המובייל (Phase 4C.4)
מלקט המובייל יכול עכשיו להוריד אצווה לעבודה ללא קישוריות.
פרטים נוספים ↓הסתר ↑
מלקט המובייל יכול עכשיו להוריד אצווה לעבודה ללא קישוריות. לחיצה על כפתור הורדה בראש מסך האצווה שומרת את כל נתוני הסנפשוט מקומית (AsyncStorage). בזמן ליקוט offline — כל פעולה (ליקוט, דילוג, חריגה, סיום) מתעדכנת מיידית ב-store המקומי ומצטברת ב-outbox לסנכרון מאוחר. הזרימה המקוונת מ-Phase 2 נשמרת ללא רגרסיה.
- כפתור 'הורד לעבודה offline' בכותרת מסך האצווה — endpoint חדש /api/v1/mobile/warehouse/batches/[id]/snapshot
- מסך הליקוט עובד מול store מקומי בלבד עבור אצווה שהורדה (ללא תלות ברשת)
- אימות ברקוד ומיקום offline מול נתוני הסנפשוט המקומי
- BATCH_START אוטומטי לפני הפעולה הראשונה; BATCH_COMPLETE בסיום כל המשימות
- הזרימה המקוונת מ-Phase 2 נשמרת ללא שינוי
v01.25.000חדשintegrationsminorאינטגרציה עם WooCommerce
חיבור חנויות WooCommerce לשיפנסט: כל הזמנה חדשה נוצרת אוטומטית כמשלוח, ועם מסירה — סטטוס ההזמנה בחנות מתעדכן אוטומטית ל-Completed.
פרטים נוספים ↓הסתר ↑
חיבור חנויות WooCommerce לשיפנסט: כל הזמנה חדשה נוצרת אוטומטית כמשלוח, ועם מסירה — סטטוס ההזמנה בחנות מתעדכן אוטומטית ל-Completed. הגדרה מתבצעת הן בדשבורד הלקוח (admin) והן בפורטל הלקוח — כל לקוח יכול לחבר חנויות מרובות עצמאית.
- יבוא הזמנות אוטומטי דרך WooCommerce Webhook (order.created / order.updated)
- מיפוי כתובת ישראלית: פיצול רחוב/מספר, דירה, עיר
- בדיקת חיבור מובנית (Test Connection) עם Consumer Key + Secret
- עדכון סטטוס הזמנה ל-Completed בחנות עם מסירת המשלוח
- אימות חתימת HMAC-SHA256 על webhooks נכנסים
- פורטל לקוח — עמוד 'החנויות שלי': חיבור וניהול חנויות מרובות לכל לקוח
- Webhook URL ייחודי לכל חנות (per-connection) מוצג ישירות בפורטל
v01.24.002שיפורmobileמובייל — תוויות מפה קבועות בעברית דרך אריחי MapTiler
מפת הנהג מציגה עכשיו תוויות בעברית ללא תלות בשפת המכשיר.
פרטים נוספים ↓הסתר ↑
מפת הנהג מציגה עכשיו תוויות בעברית ללא תלות בשפת המכשיר. הוטמע רכיב UrlTile מ-react-native-maps המציג אריחי raster של MapTiler (streets-v2 + language=he) מעל מפת הבסיס. על Android הוסף customMapStyle שמסתיר תוויות POI/כביש נייטיב כדי למנוע כפילות. אם EXPO_PUBLIC_MAPTILER_KEY לא מוגדר — מפת הבסיס הנייטיב נשארת ללא קריסה.
v01.24.001שיפורmobileמובייל — ציור קו מסלול מבוסס-כביש על המפה
אפליקציית המובייל מציגה כעת קו מסלול לאורך הכבישים במקום קו ישר.
פרטים נוספים ↓הסתר ↑
אפליקציית המובייל מציגה כעת קו מסלול לאורך הכבישים במקום קו ישר. בעת אופטימיזציית מסלול — גאומטריית OSRM מוחזרת מה-API ומוצגת ב-Polyline; כשה-geometry חסר (OSRM לא זמין) — fallback לקו ישר בין העצירות. המסלול הפעיל (view mode) טוען את הגאומטריה השמורה מ-route_build דרך activeRoute.geometry ב-today API. activateRoute שולח את הגאומטריה ל-backend לשמירה. עדכוני טיפוסים: geometry + routingSource ב-OptimizedRouteData; ActiveRoute interface חדש ב-TodayData.
v01.24.000חדשwarehouseminorמודול מחסן — Phase 2.6: UI תור ליקוט, אצוות, אריזה וחריגות
תיקון 4 כשלוני טסטים pre-existing: הודעות ברירת מחדל ב-api-errors עודכנו לעברית (לא מורשה / אין הרשאה / לא נמצא); ציפיית EMPLOYEE_MANAGER בטסט role-permissions תוקנה לשקף שיש לו SHIPMENTS_VIEW (כפי שמוגדר בקוד).
פרטים נוספים ↓הסתר ↑
תיקון 4 כשלוני טסטים pre-existing: הודעות ברירת מחדל ב-api-errors עודכנו לעברית (לא מורשה / אין הרשאה / לא נמצא); ציפיית EMPLOYEE_MANAGER בטסט role-permissions תוקנה לשקף שיש לו SHIPMENTS_VIEW (כפי שמוגדר בקוד). Phase A — אידמפוטנטיות ב-Backend לפעולות שטח במובייל: מודל Prisma חדש MobileActionIdempotency (טבלה mobile_action_idempotency, @@unique[tenantId, idempotencyKey]); helper withMobileIdempotency — קורא Idempotency-Key header, תופס את המפתח ב-INSERT, מריץ handler פעם אחת ושומר status+body, בקריאה חוזרת מחזיר תגובה שמורה מילה-במילה; in-flight → 409; חסר header → backward-compatible. שכבה שנייה: deliver מחזיר 200 אם כבר deliveredAt (לא 409); fail מחזיר 200 אם כבר failedAt. כל 4 endpoints (deliver/fail/cod/pod) חוברו דרך ה-helper. cron cleanup-logs מנקה רשומות ישנות מ-7 ימים. 8 טסטי vitest כוסו את כל הנתיבים (no-key, claim+cache, replay, in-progress, race, diff-keys, handler-throws, non-P2002-error). 4 רכיבים משותפים חדשים ב-components/warehouse/: FulfillmentQueueView (תור + הוספה לתור מרשימת משלוחים זמינים), BatchListView (יצירת אצווה, בחירת fulfillments + type, BatchDetailSheet עם משימות לפי sequence), PackingView (אריזה + מעבר PICKED→PACKING→PACKED), ExceptionListView (רשימת חריגות + ExceptionStatusSheet לעדכון סטטוס ושיוך מטפל). כל רכיב עצמאי — צוות ופורטל מייבאים אותו ישירות ללא שכפול קוד. הוספת 4 עמודים לצוות ו-4 לפורטל. עדכון ניווט: 4 פריטים חדשים בתפריט המחסן של הצוות ו-4 בפורטל (גדורים ב-warehouseEnabled). עדכון API: GET /fulfillments מצרף נתוני משלוח; GET /batches/[id] מצרף location + product לכל pick task. Phase 2.7: הרחבת mobile auth לקבלת CustomerUser (מלקט-לקוח) — login/me/refresh. 3 endpoints מובייל חדשים: GET /warehouse/batches, GET /batches/[id] (auto-assign OPEN→ASSIGNED), PATCH /pick-tasks/[id] (confirmPick/skip/reportException). אפליקציית מובייל: route group (warehouse) עם מסך רשימת אצוות ומסך ליקוט מלא (סריקת מיקום → סריקת מוצר → haptic → הבאה).
- רכיבים משותפים — צוות ופורטל משתמשים באותו קוד, כל צד רק ה-owner שלו
- FulfillmentAddDialog — חיפוש משלוחים זמינים בזמן אמת
- BatchCreateDialog — multi-select fulfillments + בחירת סוג ליקוט
- PackingView — מעבר PICKED→PACKING→PACKED עם toast ברקוד המשלוח
- ExceptionListView — פילטר status/type + Sheet לטיפול וסגירה
- Mobile: CustomerUser auth — מלקט-לקוח מתחבר עם אותו JWT, skip device check
- Mobile: זרימת ליקוט — סרוק מיקום → סרוק מוצר → haptic success → משימה הבאה
- Mobile: דיווח חריגה ממסך הליקוט + skip
- תיקון: loading skeleton של דף עדכונים תואם כעת למבנה ה-changelog (major/minor/patch cards)
- תיקון: הסרת 'use client' מדף עדכונים — מרונדר בשרת, ללא הבהוב בהיר במעבר מהסקלטון
- תיקון: FOUC במצב דארק — @media prefers-color-scheme:dark מגדיר border/bg מיידית לפני ה-JS; html מקבל background-color ישיר
- תיקון: הבזק בורדר לבן בשורות טבלה — TableRow/Header/Footer מחליפים border-neutral-200 dark:border-neutral-800 ב-border-border (CSS variable, מוגן כבר ע"י media query)
- ניתוב מבוסס-כביש: OSRM client (lib/routing/osrm-client.ts) — getTravelMatrix + getRouteGeometry עם timeout 5s ו-fallback null; optimizer.ts תומך ב-TravelMatrix (NN+2-opt על זמני נסיעה אמיתיים, legs ממטריצת distances/durations); optimize endpoint מחזיר geometry ו-routingSource; activate שומר geometry ב-route_build; today מחזיר activeRoute.geometry לאפליקציה
- תיקון Phase 2.8 — לוגיקת מעברי סטטוס חולצה ל-lib/warehouse/status-progression.ts (פונקציות טהורות ניתנות לטסט); 23 טסטי vitest מכסים את כל מקרי הקצה
- תיקון Phase 2.8 — layout route group (warehouse) במובייל כולל כעת בדיקת דגל פיצ'ר (GET /api/v1/mobile/warehouse/enabled) בנוסף לבדיקת role; כשהדגל כבוי — redirect אוטומטי גם ל-WAREHOUSE_WORKER
- Phase 3.1 — שדות חותמת-זמן למדידה (nullable, אדיטיביים): WhBatch.startedAt/completedAt, WhFulfillment.pickingStartedAt/pickedAt/packedAt, WhPickTask.pickedAt; מאוכלסים אוטומטית בנקודות מעבר הסטטוס הקיימות
- Phase 3.2 — GET /api/warehouse/metrics: KPI cards (fulfillments לפי סטטוס, קצב ליקוט, זמן מחזור, זמן אצווה, אחוז חריגות, חריגות פתוחות), משפך סטטוסים, סדרת זמן יומית, טבלת מלקטים — הכול owner-scoped, עטוף ב-withWarehouseApi
- Phase 3.3 — דשבורד ביצועים משותף (MetricsDashboard) — רכיב אחד משמש הן לצוות (/warehouse/dashboard) והן לפורטל (/portal/warehouse/dashboard); 6 KPI cards, AreaChart יומי, PieChart משפך, טבלת מלקטים — כולם Recharts כמו מודול האנליטיקס; DateRangeFilter עם ברירת מחדל this_month; פריט ניווט דשבורד נוסף לסרגל הצוות ולפורטל
- חיזוק withMobileIdempotency: 5xx לא נשמר — רשומה נמחקת ו-response מוחזר כמות שהוא לניסיון חוזר; json() עטוף ב-try/catch — כשל גורם למחיקת הרשומה ו-502 במקום נעילת המפתח; רשומה in-flight ישנה מ-2 דקות נמחקת (key reclaimable) ומוחזר 409; 3 טסטים נוספים (11 סה"כ)
- Mobile Phase B (offline queue engine): stores/offline-queue-store.ts — Zustand+persist (shipnest_offline_queue, AsyncStorage); QueuedAction עם id=UUID/Idempotency-Key, type, visitId, payload, photoUris, attempts, status; derived: pendingCount/syncingId/failedCount; guard כפיל type+visitId; onRehydrateStorage מאפס syncing→pending לאחר app kill. lib/offline/sync-processor.ts — flushQueue() סדרתי FIFO, isFlushing guard; 4xx permanent → markFailed+המשך, רשת/5xx/409 → incrementAttempt+עצור. lib/offline/net-status.ts — initOfflineSync() מנוי NetInfo+AppState, flush בחיבור ו-foreground. endpoints (delivery/cod/pod): +idempotencyKey פרמטר, httpStatus בשגיאות. התקנת @react-native-community/netinfo ו-expo-crypto
- Mobile Phase C (חיווט מסכים דרך התור): fail.tsx ו-cod.tsx הפכו סינכרוניים — אין spinner/loading, enqueue() מיידי + toast + navigate. visit/[id].tsx: useVisitSyncStatus + useOfflineQueueStore; handleMarkDelivered סינכרוני עם enqueue; COD בתור → deliveryState מוכפה READY_TO_DELIVER; כפתורי פעולה נחסמים כשיש pending; HeroSection מציג תווית ממתין/נכשל; syncBanner מעל כפתורים; CODCard מציג 'גביה הושלמה' כש-pendingSync=true. VisitCard: תג syncBadge (pending/failed). מסך היום: useVisitSyncStatus בכל VisitRow → syncBadge מוצג בכרטיסיה
- Mobile Phase D (חיווט POD דרך התור): pod.tsx הפך סינכרוני — הסרת uploadPod/useQueryClient/ActivityIndicator/isUploading/uploadProgress; handleFinish מבצע enqueue({type:'pod',...,photoUris}) + toast + back; upload overlay ו-retry dialog הוסרו; קבצי תמונה לא נמחקים ב-enqueue (sync-processor מוחק בהצלחה, handleClose מוחק ביציאה). חסימת כפתורים עודנה: deliver/fail/cod pending → חוסם את כל 4 הכפתורים; pod pending → חוסם רק כפתור POD (מסירה/כישלון/גוביינא נשארים זמינים); syncLabel מציג 'POD ממתין לסנכרון' בנפרד
- תיקון רגרסיית RTL: _layout.tsx — self-heal אחרי native rebuild; _didForceRTL מאפשר reload אוטומטי פעם אחת (DevSettings.reload); guard ב-AsyncStorage (rtl_reload_done) מונע לולאת reload אינסופית ב-Expo Go; console.log אבחוני [RTL] isRTL+appOwnership בהפעלה
- Phase 3.4 — ליטוש מסכי פורטל המחסן: מצב שגיאה עם כפתור 'נסה שנית' ב-9 מסכים (FulfillmentQueueView, BatchListView, PackingView, ExceptionListView, MetricsDashboard, מחסנים, מיקומים, מוצרים, מלאי); זרימת onboarding 3-שלבית בדף מחסנים ריק; aria-label לשדות חיפוש
- Phase 3.5 — אימות: 22 טסטים חדשים ל-warehouse-metrics (owner-scope isolation, time series, funnel, KPI calculations, BigInt conversion); 20 קבצי טסט עוברים (369 סה"כ); tsc + lint נקיים
- Phase 4C.1 — DB: טבלת WhSyncLog (wh_sync_log) לאידמפוטנטיות offline-sync; GET /api/warehouse/batches/[id]/snapshot — קריאה אחת עם snapshot מלא (batch+tasks+fulfillments+locations+products+snapshotAt), owner-scoped ומגבילה למלקט המשויך
- Phase 4C.2 — POST /api/warehouse/sync: מקבל מערך mutations (BATCH_START/TASK_PICK/TASK_SKIP/TASK_EXCEPTION/BATCH_COMPLETE) מסודר לפי sequence; כל mutation בטרנזקציה עצמאית — בדיקת WhSyncLog לאידמפוטנטיות, בדיקת owner+pickerId לגילוי קונפליקט, החלת מעברי סטטוס דרך status-progression.ts הקיים; מחזיר תוצאה פר-mutation (applied/duplicate/conflict); קונפליקט בודד אינו עוצר את שאר ה-mutations; 19 טסטי vitest חדשים (getCallerPickerId, checkBatchEligibility, אידמפוטנטיות, קונפליקט, owner-scope)
- Phase 4C.3 — מובייל: שכבת persistence מקומית (תשתית בלבד, ללא שינוי זרימת הליקוט הקיימת): lib/warehouse/types.ts — טיפוסי OfflineSnapshot (batch/pickTasks/products/locations/fulfillments) ו-OutboxMutation; lib/warehouse/db.ts — AsyncStorage DAO (saveSnapshot/loadSnapshot/deleteSnapshot/listCachedBatchIds); stores/warehouse-store.ts — Zustand+AsyncStorage slice לפי דפוס offline-queue-store: מטא-דאטה לאצוות offline, outbox mutations עם mutationId (UUID), sequence מונוטוני, markMutationSynced/Conflict, pendingCount
v01.23.000חדשwarehouseminorמודול מחסן — Phase 2.4–2.5: ליקוט, חריגות ואריזה
Phase 2.4: PATCH /api/warehouse/pick-tasks/[id] — שלוש פעולות דרך discriminatedUnion: confirmPick (ולידציית סריקת מיקום + ברקוד), skip, reportException.
פרטים נוספים ↓הסתר ↑
Phase 2.4: PATCH /api/warehouse/pick-tasks/[id] — שלוש פעולות דרך discriminatedUnion: confirmPick (ולידציית סריקת מיקום + ברקוד), skip, reportException. התקדמות סטטוס אוטומטית בטרנזקציה: משימה ראשונה → WhBatch=IN_PROGRESS + WhFulfillment=PICKING; כל tasks הושלמו → WhFulfillment=PICKED; כל fulfillments → WhBatch=COMPLETED. GET/POST /exceptions + PATCH /exceptions/[id] — פילטר status/type, ולידציית ownership. Phase 2.5: GET /packing — WhFulfillments בסטטוס PICKED/PACKING עם נתוני משלוח לאיפוס מדבקה. PATCH /packing/[id] — PICKED→PACKING→PACKED; בהגעה ל-PACKED משדר אירוע wh.fulfillment.packed דרך warehouseEvents (TenantEventBus); handler מינימלי ב-lib/warehouse/fulfillment-packed-handler.ts; Shipment.status לא מעודכן ישירות. Audit log על כל פעולת ליקוט ואריזה.
- ליקוט עם ולידציית סריקה — אי-התאמה מיקום/ברקוד מחזירה שגיאה 422 ברורה
- Auto-progression אטומי בטרנזקציה: task→fulfillment→batch
- API חריגות: GET/POST/PATCH עם ownership isolation
- אריזה + אירוע wh.fulfillment.packed — ללא פגיעה בלוגיקת Shipment
v01.23.000חדשwarehouseminorמודול מחסן — Phase 2.3: מנוע אצוות + S-shape routing
Phase 2.3: API אצוות תחת /api/warehouse/batches — GET רשימה עם מונה tasks; POST יצירת אצווה סינכרונית מ-fulfillmentIds[]: לכל OrderItem מתבצע חיפוש WhProduct לפי name (case-insensitive, owner-scoped), אם לא נמצא מוצר/מלא…
פרטים נוספים ↓הסתר ↑
Phase 2.3: API אצוות תחת /api/warehouse/batches — GET רשימה עם מונה tasks; POST יצירת אצווה סינכרונית מ-fulfillmentIds[]: לכל OrderItem מתבצע חיפוש WhProduct לפי name (case-insensitive, owner-scoped), אם לא נמצא מוצר/מלאי נוצר WhException(MISSING_PRODUCT). WhPickTask נוצרות עם locationId מה-WhInventory עם הכמות הגבוהה ביותר, ומסודרות לפי S-shape (serpentine). lib/warehouse/s-shape.ts — פונקציה טהורה: מסדרונות ממוינים aisle-ascending, מסדרון אי-זוגי rack/shelf עולים, זוגי יורדים; natural sort עם Intl.Collator. GET/PATCH /batches/[id] — אצווה + tasks לפי sequence + pickerId/pickerType. WhFulfillments מעודכנות ל-BATCHED עם batchId. הכול בעסקת $transaction אחת. 8 טסטי יחידה למנוע ה-S-shape.
- מנוע בניית אצווה סינכרוני — resolves products/inventory/locations בבלק אחד
- S-shape (serpentine) routing — פונקציה טהורה עם 8 טסטים
- MISSING_PRODUCT exception אוטומטי לפריטים ללא קטלוג/מלאי
- הכל בעסקת DB אחת — אטומי
v01.23.000חדשwarehouseminorמודול מחסן — Phase 2.1–2.2: מנוע פולפילמנטים
Phase 2.1: ארבעה מודלי Prisma חדשים — WhFulfillment (1:1 למשלוח, shipmentId @unique ללא relation מאולץ), WhBatch (אצוות ליקוט עם code ייחודי), WhPickTask (משימות ליקוט עם sequence ו-pickedQuantity), WhException (חריגות ע…
פרטים נוספים ↓הסתר ↑
Phase 2.1: ארבעה מודלי Prisma חדשים — WhFulfillment (1:1 למשלוח, shipmentId @unique ללא relation מאולץ), WhBatch (אצוות ליקוט עם code ייחודי), WhPickTask (משימות ליקוט עם sequence ו-pickedQuantity), WhException (חריגות עם type/status). שישה enums: WhFulfillmentStatus (NEW/BATCHED/PICKING/PICKED/PACKING/PACKED/EXCEPTION), WhBatchStatus, WhTaskStatus, WhPickType, WhExceptionType, WhExceptionStatus. טבלאות DB נוצרו דרך SQL ישיר (Prisma Postgres). Phase 2.2: API תחת /api/warehouse/fulfillments — GET eligible (משלוחים ללא WhFulfillment עדיין, scoped לפי בעלים), GET/POST queue, GET/PATCH [id] עם OrderItems מהמשלוח ו-validated status transitions. כל route עטוף ב-withWarehouseApi, owner-scoped דרך getOwnerScope, ולידציית Zod.
- ארבעה מודלים + שישה enums (Phase 2 DB layer)
- API תור ליקוט: eligible shipments, יצירת fulfillment, פרטים עם OrderItems
- Transition guard על סטטוסי WhFulfillment
- Owner isolation מלא — assertOwner על כל קריאת [id]
v01.22.000חדשcreditsminorמערכת זיכויים וניכויים
תיקון קריטי: טריגרים אוטומטיים שנחסמו בשבת כעת מתוזמנים לאחר ההבדלה (ScheduledMessage) במקום להירשם ככישלון סופי — ה-cron שולח אותם אחרי השבת.
פרטים נוספים ↓הסתר ↑
תיקון קריטי: טריגרים אוטומטיים שנחסמו בשבת כעת מתוזמנים לאחר ההבדלה (ScheduledMessage) במקום להירשם ככישלון סופי — ה-cron שולח אותם אחרי השבת. הוסף blockedReason ל-MessageSendResult. הודעות שגיאה ב-WhatsApp מוצגות כעת בעברית ב-inbox — תרגום ב-frontend גם עבור רשומות ישנות בבסיס הנתונים. מערכת מלאה לניהול זיכויים ללקוחות וניכויים משליחים. תהליך טיוטה → אישור עם מספור אוטומטי ZK-YYYY-NNN. כל זיכוי כולל: סיבה (שבר/אובדן/איחור/קנס/אחר), סכומי צד לקוח (משלוח + תכולה + פיצוי), סכומי צד שליח (ספיגת זיכוי + קנס), קישור למשלוחים ספציפיים (עיקרי/תחליפי), ותמיכה בהעלאת מסמכי הוכחת נזק. ממשק: עמוד ייעודי עם UnifiedTable, בורר תאריכים, חיפוש וטאבים לפי סטטוס. Sheet פרטים נפתח בלחיצה על שורה — כולל צפייה בסכומים, מסמכים מצורפים עם הורדה ומחיקה, אישור עם בורר חודש, ועריכה מלאה של טיוטות. אפליקציה מובייל (Sprint 9c): שער משמרת חוסם פעולות שטח (מסירה, כישלון, COD, POD) ללא משמרת פעילה; hook use-shift-gate.ts מציג Alert + מאפשר פתיחת משמרת on-the-fly. ShiftBanner עוצב מחדש: בנר ענבר להתרעה כשהמשמרת כבויה, בנר ירוק עם שעת התחלה כשפעילה. תוקן באג: שליח הנוכחי מסונן מרשימת היעד בהעברת ביקור (אסור לבחור בעצמו). Sprint 5e (מפה ופרטי ביקור): (א) תוקן מונה ק"מ שהציג 0 תמיד — endpoint /today מחשב כעת מרחק הוורסין בין עצירות רצופות במסלול הפעיל; (ב) Polyline של מסלול פעיל מצוייר ב-view mode של המפה עם markers ממוספרים לפי רצף; (ג) MiniMap בכרטיס כתובת הוחלף ב-MapView אמיתי (150px, non-interactive) — הקשה פותחת ניווט ב-Waze/Google Maps. ביקורת: תוקן פגם ב-pod.tsx — אחרי העלאת POD נוסף invalidateQueries לפי visitQueryKey לצד setQueryData הקיים, כדי שנתוני הביקור (כולל notes שהשרת עדכן) יישמרו עדכניים.
- CreditNote + CreditNoteShipment + CreditNoteAttachment — מודלים חדשים ב-Prisma
- API routes: CRUD, אישור עם appliedMonth, ביטול, קישורי משלוחים, העלאת קבצים ל-Supabase Storage
- CreditNoteDialog — טופס יצירה ועריכה עם SearchCombobox לחיפוש לקוח/שליח/משלוח
- CreditNoteSheet — side sheet עם פרטים מלאים, מסמכים, אישור עם month picker ועריכה
- עמוד /credits — PageToolbar, UnifiedTable, DateRangeSplitButton, ServerPagination, Excel export
- עמוד /messages — עיצוב מחדש: הוסר אקורדיון+טאבים; טבלה שטוחה כמו /shipments עם עמודת פעולות מוצמדת, תצוגת עמודות, ייצוא Excel; הודעות נכשלות מציגות Info-Popover (ריחוף/לחיצה) עם סיבת הכשל וכפתור שליחה מחדש
- SettlementApprovalDrawer — תיקון עיצוב: border-border/40, rounded-md, space-y-4, p-4/px-4 py-3 במקום p-6/space-y-8; הוסרו title= (הוחלפו ב-Tooltip); עודכן CLAUDE.md עם קונבנציית drawer
- תשתית OSRM (infra/osrm/): docker-compose, Caddyfile (reverse proxy + TLS + X-OSRM-Key auth), prepare.sh ו-refresh.sh לעיבוד מפת ישראל+פלסטין, .env.example ו-README עברי
- תיקון תשתית OSRM: registry שונה מ-osrm/osrm-backend (Docker Hub נטוש) ל-ghcr.io/project-osrm/osrm-backend; הוסף שלב אימות גרסה ל-README; הערת אזהרה ב-.env.example שהתג תלוי-גרסה וחייב להתאים בין עיבוד להרצה
- תשתית OSRM — TLS: עבר מ-ACME אוטומטי לתעודת Origin של Cloudflare (tls explicit ב-Caddyfile, volume certs/:ro ב-compose, certs/.gitignore); הוסר פורט 80 מ-compose ומ-ufw; נוסף שלב הנפקת Origin Certificate ל-README עם הסבר על Full (strict)
v01.21.003חדשwarehouseמודול מחסן — Phase 0: תשתית דגלי פיצ'ר
תיקון עקביות RTL: ~25 קבצים עברו המרה של class-ים פיזיים ל-logical equivalents; נמחק DateRangeSelector.tsx (dead code); DriverDetails/EmployeeDetails/LeadDetails/AgentDetails: SheetHeader text-right → text-end; bulk-hist…
פרטים נוספים ↓הסתר ↑
תיקון עקביות RTL: ~25 קבצים עברו המרה של class-ים פיזיים ל-logical equivalents; נמחק DateRangeSelector.tsx (dead code); DriverDetails/EmployeeDetails/LeadDetails/AgentDetails: SheetHeader text-right → text-end; bulk-history TableHead: text-right × 4 → text-end; CustomerDetailClient: text-right × 2 + mr-1 → text-end/ms-1; summit dialogs (pl-10/ml-1/ml-2 → ps-10/ms-1/ms-2); admin pages (ml-auto/mr-auto/ml-1 → ms/me); text-left/text-right → text-start/text-end בכל הרכיבים. בתוך אלמנטי RTL בלבד; איסים dir="ltr" (inputs מספריים, כתובות, מזהים חיצוניים) נותרו ללא שינוי. תוקן: SortingErrorsTable — בורר טווח תאריכים גולמי (Calendar+Popover מקומי) הוחלף ב-DateRangeFilter המשותף מ-components/shared; נוספו presets (היום/שבוע/חודש/הכל) והלוגיקה עברה ל-handleDatePresetChange/handleCustomDateRangeChange. הנחת תשתית אופציונליות דו-שכבתית למודול מחסן (warehouse). עמודת settings נוספה לטבלת customers (JSONB, default '{}') לאחסון דגלי מודולים. שלוש פונקציות גישה ב-lib/warehouse/feature-access.ts (isWarehouseEnabledForTenant / isWarehouseEnabledForCustomer / canStaffAccessWarehouse) — מקור אמת יחיד לכל gating. Wrapper API withWarehouseApi מחזיר 404 (לא 403) כשהמודול כבוי. קודי הרשאה גרנולריים נוספו: WAREHOUSE_INVENTORY_VIEW, WAREHOUSE_INVENTORY_MANAGE, WAREHOUSE_PICK, WAREHOUSE_BATCH_MANAGE — משויכים ל-OWNER, ADMIN, WAREHOUSE_MANAGER, WAREHOUSE_WORKER. מתג הפעלה ברמת טננט נוסף ל-tenant-form.tsx (קורא ושומר settings.modules.warehouse עם deep merge). מתג הפעלה ברמת לקוח נוסף ל-CustomerDetailClient.tsx — מוצג רק כשהטננט הפעיל את המודול, שומר דרך PATCH עם deep merge. Route groups ריקים עם שומרים: (site)/warehouse/layout.tsx (canStaffAccessWarehouse → redirect '/') ו-portal/(app)/warehouse/layout.tsx (isWarehouseEnabledForCustomer → redirect '/portal'); שני placeholder pages עם 'בקרוב'. Gating בניווט: קבוצת 'מחסן' ב-app-sidebar.tsx מתרנדרת רק כשwarehouseEnabled מועבר מה-server layout; פריט 'מחסן' ב-PortalSidebar.tsx עם requiresFlag warehouseEnabled; portal layout מחשב warehouseEnabled במקביל ל-accountingAvailableCount. Phase 1 tasks 1.1–1.2: ארבעה מודלי Prisma חדשים (WhWarehouse, WhLocation, WhProduct, WhInventory) — כל אחד נושא tenantId + ownerCustomerId? (NULL=טננט, מאוכלס=לקוח), timestamps, @@unique ו-@@index owner-scoped; ארבע טבלאות DB נוצרו (wh_warehouses, wh_locations, wh_products, wh_inventory) דרך SQL ישיר; lib/warehouse/owner-scope.ts עם getOwnerScope(session) + assertOwner(session, record) — מקור אמת יחיד לפילטרי בעלות בכל ה-routes. Phase 1 tasks 1.3 + 1.5 (חלקי): API routes מלאים תחת /api/warehouse/warehouses ו-/api/warehouse/locations — CRUD מלא עטוף ב-withWarehouseApi, כל שאילתה דרך getOwnerScope, ולידציית Zod, פורמט { success, data, meta }; בניית קוד-מיקום אוטומטית מהרכיבים (zone-aisle-rack-shelf-bin); רכיבי טופס משותפים WarehouseForm + LocationForm (יעשה בהם שימוש חוזר בפורטל); עמוד /warehouse עם UnifiedTable + יצירה/עריכה/מחיקה; עמוד /warehouse/[warehouseId] — רשימת מיקומים עם ניווט חזרה + תצוגת קוד בזמן-אמת. Phase 1 tasks 1.4 + 1.5 (קטלוג + מלאי): API routes — products CRUD עם חיפוש חופשי (sku/barcode/name); inventory GET עם סינון locationId/productId; inventory/adjust POST עם upsert לפי @@unique([locationId,productId]) + רישום audit log; רכיבי טופס משותפים ProductForm + InventoryAdjustDialog; עמוד /warehouse/products — קטלוג עם UnifiedTable + יצירה/עריכה/מחיקה; עמוד /warehouse/inventory — תצוגת מוצר↔מיקום↔כמות עם סינון מחסן/מיקום/מוצר + badge ירוק/ענבר/אדום לפי כמות; ניווט צד עדכן: מחסנים, קטלוג מוצרים, מלאי. Phase 1 task 1.6 — UI פורטל: 4 דפי פורטל מחסן (warehouses, locations, products, inventory) שמשתמשים חוזרים ברכיבי הטופס המשותפים (WarehouseForm, LocationForm, ProductForm, InventoryAdjustDialog) ומפנים ל-/portal/warehouse/...; PortalSidebar עודכן עם קישורי מחסנים/קטלוג/מלאי; owner-scope נאכף לחלוטין ב-API — לקוח רואה רק את הנתונים שלו.
v01.21.002חדשSprint 9b Phase 1-4 — Push Notifications: רישום token
Sprint 9b מלא — Push Notifications.
פרטים נוספים ↓הסתר ↑
Sprint 9b מלא — Push Notifications. Phases 1-4: expo-notifications מותקן, app.json עודכן (POST_NOTIFICATIONS + plugin), lib/notifications/push.ts עם setNotificationHandler + registerForPushNotifications (graceful אם EAS לא מקושר), POST /api/v1/mobile/notifications/register-token שומר token ב-user_devices. Phases 5-8: lib/notifications/expo-push.ts עם sendPushNotifications + notifyDriver helper, trigger ב-assign route (שליח חדש: 'משלוח חדש', שליח ישן בהעברה: 'משלוח הועבר ממך'), tap handler ב-_layout.tsx לניווט deep link ל-/visit/[id]. NOTES.md עודכן עם הוראות EAS projectId.
v01.21.001חדשSprint 9a — GPS מעקב מיקום ברקע (Mobile)
הטמעת מעקב GPS לאפליקציה המובייל: TaskManager background task עם battery-aware intervals (2 דק' רגיל, 5 דק' כשסוללה מתחת ל-20%), תור offline ב-AsyncStorage עם flush אוטומטי בחזרת קישוריות.
פרטים נוספים ↓הסתר ↑
הטמעת מעקב GPS לאפליקציה המובייל: TaskManager background task עם battery-aware intervals (2 דק' רגיל, 5 דק' כשסוללה מתחת ל-20%), תור offline ב-AsyncStorage עם flush אוטומטי בחזרת קישוריות. Backend: שני endpoints חדשים — POST /api/v1/mobile/location/ping ו-/batch (עם skipDuplicates). JWT: driverId נוסף ל-access token לחיסכון ב-DB lookup. Shift Store (Zustand) עם persist ל-AsyncStorage ושחזור tracking אוטומטי בהפעלה מחדש של האפליקציה. Phase 5: ShiftBanner ב-Today screen — כפתור ירוק לתחילת משמרת, בנר ירוק עם אפשרות סיום כשבמשמרת, dot ירוק על Avatar ב-HomeHeader. Backward compat: fallback DB lookup לtokens ישנים ב-ping/batch endpoints.
v01.21.000שיפורui/tablesminorאחוד טבלאות — מעבר מלא ל-UnifiedTable
כל 13 הטבלאות הגולמיות במערכת הוחלפו ב-UnifiedTable (TanStack React Table wrapper).
פרטים נוספים ↓הסתר ↑
כל 13 הטבלאות הגולמיות במערכת הוחלפו ב-UnifiedTable (TanStack React Table wrapper). כל הטבלאות נהנות כעת מ-skeleton loading אחיד, empty state עם אייקון ותיאור, server-side pagination מובנית, בחירת שורות עם bulk actions, ו-sticky actions column. הדפים שעברו מעבר: ShipmentMessagesCard, ShipmentDetails (פריטים), admin/api-keys, admin/webhooks (כולל deliveries dialog), settings/audit-log, drivers/[id] (zone rates), attendance/payroll, attendance/reports (4 טאבים), admin/sync-errors.
- admin/sync-errors — selection עם renderBulkActions (retry/dismiss/delete/restore) וו-confirmation dialogs מבוססי pendingTargetsRef
- attendance/payroll ו-reports — server pagination מובנית, skeleton loading, 4 טבלות בטאבים
- admin/webhooks — deliveries dialog עם UnifiedTable פנימי וו-6 עמודות
- כל טבלה: emptyState עם אייקון ו-accentColor מותאמים לתוכן
v01.20.001תיקוןsettings/updatesדף עדכונים — מחיצת תאריך לפני רשומות minor/major
תוקן: רשומות minor ו-major לא הציגו כותרת תאריך, מה שגרם להן להיראות כשייכות לתאריך מאוחר יותר.
פרטים נוספים ↓הסתר ↑
תוקן: רשומות minor ו-major לא הציגו כותרת תאריך, מה שגרם להן להיראות כשייכות לתאריך מאוחר יותר. כעת מוצגת מחיצת תאריך לפני כל רשומה שהתאריך שלה שונה מהקודמת. רשומות patch שמופיעות אחרי minor/major באותו תאריך לא מציגות כותרת כפולה.
v01.20.000חדשmobile/adminminorSprint 8b — Admin Mode Mobile UI
ממשק מנהל מלא באפליקציה המובייל: ד-שבורד ניהולי עם KPI, רשימת שליחים וקלפי ביצוע.
פרטים נוספים ↓הסתר ↑
ממשק מנהל מלא באפליקציה המובייל: ד-שבורד ניהולי עם KPI, רשימת שליחים וקלפי ביצוע. מסך ביקורים לא משויכים עם שיוך מהיר לשליח. מסך פרטי שליח עם כל ביקוריו ואפשרות העברה. מסך בחירת שליח (שיוך/העברה) עם עיצוב dark-header אחיד. תוקנו חוסרי עקביות עיצוביים: `<a href>` פנימי הוחלף ב-Link, `<select>` גולמי (מפה + ToolbarTabs) הוחלף ב-shadcn Select.
- AdminDashboard — KPI grid (פתוחים/בשטח/נמסרו/ממתינים), banner ביקורים לא משויכים, DriverCards עם progress bar ופעולות מהירות
- UnassignedScreen — רשימת ביקורים ממתינים לשיוך, כפתור 'שייך' לכל ביקור
- DriverDetailScreen — כל ביקורי השליח ליום, כפתור 'העבר' לביקורים פתוחים
- AssignScreen — בחירת שליח עם radio selection + confirm (שיוך/העברה)
- HomeHeader — טוגל מנהל/שליח מוצג רק למשתמשים עם role ניהולי
- Admin API hooks — useAdminDrivers, useUnassignedVisits, useDriverVisits, useAssignVisit
v01.19.006שיפורshipments/timeline, ui/consistencyציר זמן משלוח — ליקוט ויציאה להפצה נפרדים
הוספת עמודה outInventoryAt לטבלת shipment — נכתבת בפעם הראשונה שמגיע webhook עם סטטוס OUT_INVENTORY (sticky, לא מתאפס).
פרטים נוספים ↓הסתר ↑
הוספת עמודה outInventoryAt לטבלת shipment — נכתבת בפעם הראשונה שמגיע webhook עם סטטוס OUT_INVENTORY (sticky, לא מתאפס). הוספת עמודה inTransferAt לטבלת shipment — נכתבת בפעם הראשונה שמגיע webhook עם סטטוס IN_TRANSFER (sticky, לא מתאפס). ציר הזמן בדף המשלוח מציג כעת 7 אירועים נפרדים: הקמה → איסוף → קליטה במחסן → ליקוט → בהעברה → יציאה להפצה → כשל/מסירה. ציר הזמן תומך במחזורי הפצה מרובים (כשל + נסיון מחדש) — מבוסס על כלל visits מסוג DELIVERY לפי סדר כרונולוגי; כשל ופרטי הסיבה מוצגים בשורה אחת. תוקן: Lionwheel לא שולח failed_at בנתוני ה-visit — הוסף לוגיקה ב-data-service שכותבת failedAt=now() על DELIVERY visit שלא הושלם כשמגיע webhook עם סטטוס FAILED/FINAL_FAILED; הוסף fallback בציר הזמן להציג כשל גם ל-visits ישנים ללא failedAt. תוקן: שמות ה-labels מוצגים בצורה עסקית ברורה יותר. תוקנו כל ה-tooltip הפרימיטיביים (title=) במערכת — הוחלפו ב-Tooltip/TooltipTrigger/TooltipContent מ-shadcn. אוחד שימוש בלוחות שנה: כל 6 מקומות שהשתמשו ב-Calendar + Popover מקומי הוחלפו ב-DatePicker המשותף מ-components/shared. תוקן: בר הפגינציה בדף הזדכויות (settlements) הוצג ללא border/card — נוסף wrapper זהה לשאר הדפים.
v01.19.005חדשmobile/adminSprint 8a — Admin Mode Backend
הרחבת seed לשלושה משתמשים: דני כהן (EMPLOYEE_DRIVER), יוסי לוי (EMPLOYEE_DRIVER, driverId=473), רון מנהל (DISTRIBUTION_MANAGER, ללא driver record); 3 משלוחים ליוסי + 3 ללא שיוך (driverId=null).
פרטים נוספים ↓הסתר ↑
הרחבת seed לשלושה משתמשים: דני כהן (EMPLOYEE_DRIVER), יוסי לוי (EMPLOYEE_DRIVER, driverId=473), רון מנהל (DISTRIBUTION_MANAGER, ללא driver record); 3 משלוחים ליוסי + 3 ללא שיוך (driverId=null). נוספו 4 endpoints admin למובייל: GET /api/v1/mobile/admin/drivers (כל שליחי ה-tenant + סטטיסטיקות יומיות + isOnShift מ-DriverLocation); GET /api/v1/mobile/admin/visits/unassigned (visits היום ללא שיוך + shipment info); GET /api/v1/mobile/admin/drivers/:driverId/visits (visits יומיות של שליח ספציפי + stats); POST /api/v1/mobile/admin/visits/:id/assign (שיוך/העברת visit לשליח — מאפס inActiveRoute+routeSequence, logAudit עם פרטי ממי למי). Role check על כל endpoint: DISTRIBUTION_MANAGER/ADMIN/OWNER/WAREHOUSE_MANAGER/EMPLOYEE_MANAGER; שליח רגיל מקבל 403. דף משלוח: ציר זמן (timeline) במקום גריד שטוח — כל אירוע (הקמה, קליטה, איסוף, ליקוט, כשל, מסירה) מוצג עם נקודה וקו מחבר; כשל ופרטי הסיבה מוצגים בשורה אחת; כשל מוצג היסטורית גם אחרי שינוי סטטוס (מבוסס על Visit.failedAt); אייקון העתקה לכל שורה.
v01.19.004שיפורmobile/settlement, web/settlementהזדכות COD — פר משלוח במקום בחירה מרובה
שינוי מדיניות הזדכות: במקום לסמן כמה גוביינאות ולהזדכות על כולן יחד, כל הזדכות היא על משלוח בודד.
פרטים נוספים ↓הסתר ↑
שינוי מדיניות הזדכות: במקום לסמן כמה גוביינאות ולהזדכות על כולן יחד, כל הזדכות היא על משלוח בודד. מסך הרשימה הופך לרשימה ניתנת-ללחיצה; לחיצה על שורה מעבירה ישירות למסך ההעלאה עם פרטי אותו משלוח. כפתור 'שלח' שינה לטקסט 'שלח לאישור מנהל' להבהרה שההזדכות עוברת אישור לפני סגירה. תוקן גם import של expo-file-system/legacy (EncodingType). Sprint 7 Phase 1 — נוספו 4 endpoints web-admin: GET /api/settlements (רשימה+ספירות לפי סטטוס), GET /api/settlements/:id (פרטים+CodTrackings), POST /api/settlements/:id/approve (אישור→IN_SAFE), POST /api/settlements/:id/discrepancy (פער→DISCREPANCY); נוספו permissions SETTLEMENT_VIEW/SETTLEMENT_APPROVE. תוקן: שורת הסיכום (KPI) בכרטסת חשבונאית מציגה עכשיו יתרה תואמת לאחר ביטול כפל-חיוב — computeBalanceTotals קיבלה גם היא את מנגנון suppression של דרישות תשלום מכוסות (הוריסטיקת סכום+תאריך). Sprint 7 Phases 2-5 — ממשק web-admin לאישור הזדכויות: דף /settlements עם טאבים לפי סטטוס (AWAITING_APPROVAL/APPROVED/DISCREPANCY), רשימת הזדכויות עם שם שליח/סכום/תאריך, sheet צד עם גלריית תמונות+lightbox (Dialog), רשימת גוביינות, טופס אישור עם שדות 'מזומן בפועל'/'צ׳קים בפועל' ממולאים מראש בסכומים המוצהרים, חישוב פער חי (כלומר 'פער: -₪50' באדום), כפתור משתנה בין 'אישור תואם'↔'דיווח פער'+חובת הערה. הוספת הרשאות SETTLEMENT_VIEW/SETTLEMENT_APPROVE לתפקידים OWNER/ADMIN/ACCOUNTING/CUSTOMER_SERVICE. הוספת 'הזדכויות' לתפריט הצד (קבוצת תפעול). שדרוג UX: כל שימושי title= פרימיטיביים הוחלפו בטולטיפים מעוצבים (shadcn Tooltip) ב-8 קבצים — ShipmentRow (עמודות truncated), ShipmentDetailClient, תבניות Meta, AdminTaskBellButton, admin/webhooks, admin/users, DistributionGapsTable, integration-dialog.
v01.19.003חדשmobile/settlementSprint 6b — Settlement Mobile UI Phase 1-3
Phases 1-6 של ממשק ההזדכות בנייד: (1) API layer — settlement.ts עם getPendingObligations/createSettlement/getSettlements/getSettlement + use-settlements.ts עם hooks; (2) Today banner ענבר מעל ה-tabs שמציג את סכום וכמות ח…
פרטים נוספים ↓הסתר ↑
Phases 1-6 של ממשק ההזדכות בנייד: (1) API layer — settlement.ts עם getPendingObligations/createSettlement/getSettlements/getSettlement + use-settlements.ts עם hooks; (2) Today banner ענבר מעל ה-tabs שמציג את סכום וכמות חובות WITH_DRIVER; (3) Stage 1 — מסך רשימת חובות עם checkboxes, summary card (מזומן/צ'קים), toggle all, sticky bottom עם count+total+כפתור 'המשך להזדכות'; (4) Stage 2 — מסך העלאת תמונות עם photo grid 5 slots (מצלמה/גלריה), thumbnails עם מחיקה, textarea הערות, כפתור 'שלח הזדכות'; (5) מסך סטטוס ההזדכות — 3 מצבים: AWAITING_APPROVAL/APPROVED/DISCREPANCY עם hero icon, כרטיס פרטים, רשימת חובות, כפתורי ניווט; (6) מסך היסטוריית הזדכויות + קישור ממסך הפרופיל.
v01.19.002חדשmobile/settlementsSprint 6a — Settlement Backend (הזדכות COD)
נוספה תשתית backend מלאה לתהליך הזדכות COD בין שליח לחברה.
פרטים נוספים ↓הסתר ↑
נוספה תשתית backend מלאה לתהליך הזדכות COD בין שליח לחברה. נוסף מודל CodSettlement (טבלת cod_settlements) עם שדות: settlementNumber, declaredCashAmount/CheckAmount/Total, proofImageUrls, status (AWAITING_APPROVAL→APPROVED/DISCREPANCY). נוסף שדה settlementId לטבלת cod_tracking. נוספו 4 endpoints ל-API v1 mobile: GET /settlements/pending (חובות WITH_DRIVER ללא settlementId), POST /settlements (יצירת הזדכות: אימות בעלות, העלאת תמונות ל-Supabase, יצירת רשומה, עדכון CodTrackings ל-AWAITING_SAFE), GET /settlements (היסטוריה), GET /settlements/:id (פרטים + רשימת COD).
v01.19.001תיקוןmobile/mapמפה ניידת — ציור פולגון + אופטימיזציית מסלול + מסלול פעיל
תוקן ממשק ציור הפולגון במפת השליח: הציור הקודם התבסס על לחיצות (onPress) שגרמו לעיכובים ולתגובה לא אחידה.
פרטים נוספים ↓הסתר ↑
תוקן ממשק ציור הפולגון במפת השליח: הציור הקודם התבסס על לחיצות (onPress) שגרמו לעיכובים ולתגובה לא אחידה. הוחלף ב-PanResponder שמנטר תנועת אצבע בזמן אמת (דגימה כל 8px) ללא עיכוב. הוסף אלגוריתם אופטימיזציית מסלול (Nearest-Neighbor + 2-opt, Haversine) ב-TypeScript עם חישוב ETA לכל עצירה, API endpoint ו-UI מלא: Polyline על המפה + שיט תחתי עם רשימת עצירות ממוינת + ETA + מרחק. הוסף endpoint להפעלת מסלול פעיל (POST /route/activate) עם transaction: reset + set, ושדות DB חדשים: inActiveRoute, routeBuildId, routeSequence, estimatedArrival. Today מציג 4 טאבים: במסלול / לא במסלול / נמסרו / נכשלו; ברירת מחדל חכמה — נפתח ב-'במסלול' אם יש מסלול פעיל; VisitCard בטאב 'במסלול' מציג bubble כחול עם מספר רצף + ETA מהמסלול; empty state "במסלול" עם כפתור מעבר למפה. תוקן עמודת יתרה בכרטסת לקוח (פורטל ואדמין): מסמכים מאותו תאריך קיבלו יתרת ביניים שרירותית כתוצאה מסדר מיון לא-יציב — חשבוניות זיכוי מאותו יום מוינו לפני חשבוניות חוב ויצרו ערכים מטעים (חובה שירדה ואח"כ עלתה). כעת כל מסמך מציג יתרה אישית אחרי התנועה שלו, עם סדר מוסכם: חשבוניות חוב מעובדות לפני חשבוניות זיכוי (שתיהן ממוינות לפי מספר מסמך עולה); טבלת התצוגה ממוינת בסדר הפוך (זיכויים למעלה, חובות למטה) כך שקריאה מלמטה למעלה מספרת נרטיב קוהרנטי: חוב עולה עם כל חשבונית, ואז יורד עם כל זיכוי. תוקן תצוגה מקדימה של מסמכים בכרטסת לקוח: הוחלף iframe ב-react-pdf (PDF.js) שמרנדר כל עמוד כ-canvas — עובד על כל הדפדפנים כולל iOS ו-Android שבהם iframe מיירט PDF ופותח בטאב חדש. שודרגה טבלת הכרטסת החשבונאית ל-UnifiedTable: עמודת פעולות מוצמדת, כותרות עמודות עם dropdown לסיווג ומיון, נעיצת עמודה, הסתרת/הצגת עמודות, ייצוא Excel, עימוד תחתון מעוצב — עקבי עם כל שאר הטבלאות במערכת. אייקון צפייה עבר לתוך תפריט הפעולות; נוסף כפתור FileText ליד מספר המסמך לפתיחה מהירה של תצוגה מקדימה.
- תוקן: /today חזר מ-select→include כדי למנוע שגיאת Prisma 'Unknown field' בסביבת ייצור לאחר migration
- תוקן: query key ב-map.tsx עודכן מ-['today'] ל-['driver','today'] כדי להתאים ל-TODAY_QUERY_KEY
- תוקן: activate/route.ts — הוחלף $transaction בפעולות עצמאיות (Prisma Postgres לא תומך ב-batch $transaction) + נוסף try-catch מלא שמחזיר JSON במקום HTML 500
- תוקן: optimize/route.ts — סינון ביקורים שכבר נמסרו (deliveredAt) או נכשלו (failedAt) לפני חישוב המסלול
- הסרת קוד דיבאג זמני: console.error ב-normalizeDocument ו-endpoint /api/debug/summit-raw שנוצרו לחקירת שדות API של סאמיט
- תיקון כפל-חיוב בכרטסת: דרישת תשלום סגורה (IsClosed=true) שמקושרת לחשבונית מס באותו סכום (בטווח 180 יום) מוצגת כניטרלית בעמודת תנועה ויתרה — ה-Invoice הוא שנושא את החיוב. הלוגיקה ב-buildCoveredPaymentRequestIds (התאמת סכום + תאריך הוריסטית, ללא שדה קישור ב-API של סאמיט)
v01.19.000חדשfinance/creditsminorמערכת זיכויים וניכויים
הוספת מערכת מלאה לניהול זיכויים ללקוחות וניכויים משליחים.
פרטים נוספים ↓הסתר ↑
הוספת מערכת מלאה לניהול זיכויים ללקוחות וניכויים משליחים. ניתן ליצור זיכוי על שבר, אובדן, איחור, קנס או סיבה אחרת — מלא או חלקי, על עלות משלוח, ערך תכולה ופיצוי נוסף. הזיכוי מופיע בחשבון החודשי של הלקוח, והניכוי/קנס נגזר ממנו ומופיע בדוח התשלום החודשי של השליח. ניתן לקשר זיכויים למשלוחים ספציפיים (עיקרי/תחליפי) או להשאירם עצמאיים. תהליך טיוטה ← אישור מובנה. תוקן (שורש הבעיה — כרטסת פורטל): קוד הסנכרון עם API סאמיט סרק רק 10 דפים × 500 = 5,000 מסמכים. ב-DB של סאמיט יש ~14,500 מסמכים; חשבוניות מס/קבלה של לקוחות מסוימים מופיעות בדפים 10-11 ולכן לא נסרקו. ה-maxPages הוגדל מ-10 ל-60 (30,000 מסמכים). כמו כן תוקן מיזוג תוצאות byId+byName לכיסוי מסמכים ללא CustomerID. תוקן: מודל תצוגה מקדימה של מסמכים (PDF) בכרטסת הלקוח — הוצג צר מאוד עקב override של max-width ב-Tailwind; כעת מוצג ב-95% רוחב המסך. תוקן חישוב יתרת לקוח בכרטסת: (א) חשבונית זיכוי וחשבונית זיכוי/קבלה (types 5,6) — Summit מחזיר ערכים שליליים ולכן `return -doc.total` שיגר חיוב כפול; תוקן ל-`-Math.abs(total)`. (ב) קבלת זיכוי (type 7) גם כן תוקנה לתנועת זכות. (ג) הופרדה לוגיקת תצוגה (`balanceImpact`) מלוגיקת חישוב יתרה פתוחה (`openBalanceImpact`): דרישת תשלום שסגורה (IsClosed=true) אינה נחשבת חוב כי ה-Invoice/InvoiceReceipt שהוּפק אחריה מייצג את ההתחייבות; חשבונית מס/קבלה (type 1) מטופלת כנטרלית ביתרה הפתוחה (invoice+תשלום בוצעו במקביל — נטו 0).
- עמוד ייעודי /credits לניהול כל הזיכויים במערכת
- טאב 'זיכויים' בכרטיס לקוח עם סיכום חודשי
- ניכויי זיכויים מוצגים בדוח הרווחים החודשי של שליח
- קישור זיכויים למשלוחים ספציפיים (עיקרי / תחליפי)
- תהליך אישור — DRAFT ← APPROVED
- מספור אוטומטי ZK-YYYY-NNN
- עמוד /credits עוצב מחדש בסגנון אחיד — PageToolbar, UnifiedTable, ServerPagination, ייצוא Excel
- דף משלוח: הוספת שורת תאריך כשל (מ-failedAt של הביקור) מעל סיבת הכשל; אייקון העתקה לכל שורת תאריך/סיבה
v01.18.001שיפורmessages/triggersכרטיסי טריגר — badge ערוץ לכל נמען + אזהרת תבנית בעיה
כרטיס הטריגר ברשימה מציג כעת badge ערוץ לכל נמען: סגול 'Meta' כשיש תבנית מאושרת, ענבר 'Meta' אם התבנית נדחתה/לא נמצאה, אפור 'Green' לטקסט חופשי.
פרטים נוספים ↓הסתר ↑
כרטיס הטריגר ברשימה מציג כעת badge ערוץ לכל נמען: סגול 'Meta' כשיש תבנית מאושרת, ענבר 'Meta' אם התבנית נדחתה/לא נמצאה, אפור 'Green' לטקסט חופשי. אם אחד מהנמענים מוגדר עם תבנית Meta שאינה מאושרת, מופיעה על הכרטיס כולו באנר אזהרה ענבר עם פירוט הנמען הבעייתי. תוקן שדה channel ב-DB: בשמירת טריגר, הערוץ מחושב מה-templateIds בפועל (meta-cloud-api אם לפחות נמען אחד מקושר לתבנית Meta, green-api אחרת) — עד כה נשמר תמיד green-api כברירת מחדל. תוקן: webhook כשלון מ-Meta עם קוד 131026 (Message Undeliverable) יציג עכשיו את הסיבה 'המספר אינו רשום ב-WhatsApp או שגוי' במקום הטקסט הגולמי של Meta; כמו כן נשמר errorCode על השורת משלוח לצורך תצוגה מדויקת ב-UI. תוקן תצוגת הודעות נכנסות בתיבת הדואר: reaction מוצג כאמוג'י (במקום טקסט 'reaction' עם אייקוני מסמך/לינק), מדבקה (sticker) מוצגת כתמונה. תוקן טאב 'משלוחים פתוחים' בדף נהג: משלוחים עם סטטוס טרמינלי (COMPLETED, CANCELED, FINAL_FAILED) לא יופיעו עוד כפתוחים גם אם ה-Visit לא סומן isDone=true — הסטטוס מ-additionalData משמש כ-override. תוקן הבאדג' בסיידבר: הציג בעבר מספר שיחות 'לא נענו', כעת מציג שיחות 'לא נקראו' בפועל (לפי זמן הצפייה האחרון ב-localStorage).
v01.18.000שיפורmessages/triggersminorעיצוב מחדש של טופס הטריגר — ערוץ שליחה ברור וגלוי
ממשק הטריגרים עוצב מחדש כדי להפוך את ערוץ השליחה (Meta / Green-API) לגלוי ומפורש.
פרטים נוספים ↓הסתר ↑
ממשק הטריגרים עוצב מחדש כדי להפוך את ערוץ השליחה (Meta / Green-API) לגלוי ומפורש. עד כה הבחירה בין ערוצים הייתה שקטה ונגזרת מקיום קישור תבנית — מה שגרם לטריגרים לצאת דרך Green-API בלי ידיעת המשתמש. כעת כל לשונית נמען (נמען/שולח/מותאם) מציגה שתי כרטיסיות ערוץ בחלק העליון: 'תבנית Meta' (ירוק, עם אינדיקטור חיבור) ו'טקסט חופשי' (ענבר, עם אזהרה). כרטיסיית Green-API מציגה באנר ענבר שמסביר את המגבלה ומציע קישור לתבנית Meta. כרטיסיית Meta מציגה תצוגה מקדימה של התבנית המקושרת עם אפשרות החלפה/ניתוק. נוסף picker מוטמע לחיפוש ובחירת תבנית מאושרת מתוך הטופס עצמו, ללא צורך לצאת לדף התבניות. תוקן באג בRecipientChannelBadge: שני הענפים השתמשו באותו צבע (סגול) — כעת Meta=ירוק, Green-API=ענבר, גיבוי=ענבר כהה. תוקן ה-validation: כשתבנית Meta מקושרת לנמען, המערכת לא דורשת עוד inline body (הגוף נלקח מהתבנית). תוקן באג multi-tenancy בדף פרטי נהג: שליפת הנהג לא סיננה לפי tenantId — משתמש יכול היה לגשת לנהג של tenant אחר לפי ID.
- שתי כרטיסיות ערוץ גלויות בכל לשונית נמען — Meta (ירוק) ו-Green-API (ענבר)
- אינדיקטור חיבור בזמן אמת לכל ערוץ (מחובר / לא מחובר)
- picker מוטמע לחיפוש ובחירת תבנית Meta מאושרת ישירות מהטופס
- באנר אזהרה ענבר בטקסט חופשי עם קישור לשדרוג לתבנית Meta
- תיקון validation — תבנית Meta מקושרת פוטרת מחובת inline body
v01.17.005תיקוןdistribution-gapsתיקון: פילטרים ועימוד בפערי הפצה
עימוד שרת הוסר — כעת השרת מחזיר את כל הנתונים בבקשה אחת והעימוד וכל הפילטרים מתבצעים בצד הלקוח.
פרטים נוספים ↓הסתר ↑
עימוד שרת הוסר — כעת השרת מחזיר את כל הנתונים בבקשה אחת והעימוד וכל הפילטרים מתבצעים בצד הלקוח. הספירות שליד הפילטרים (משובץ/לא משובץ, שליח, סטטוס) מחושבות כעת לפי cross-filtering נכון: כל קטגוריה מציגה ספירות לפי הפילטרים האחרים הפעילים בלבד, ומתעדכנת בזמן אמת כשמשנים סינון. נוסף פילטר עיר לפערי הפצה — מציג ספירות לכל עיר מסונכרנות עם שאר הפילטרים הפעילים (בלשונית פערי איסוף מסנן לפי עיר המקור). נוסף פילטר אזור חלוקה עם תמיכה ב-ללא אזור. שונה שם הפילטר שיבוץ שליח ל-משובץ עם ערכים כן/לא. אפליקציה: cron חדש (00:00 שעון ישראל) מגלגל ביקורים פתוחים מיום קודם ליום הנוכחי תוך שמירה על שעת הביקור המקורית. שיפור ביצועים: שאילתת דף ההודעות מביאה כעת רק שדות orderItems/visits/shipmentSetting הנדרשים לתצוגה, במקום כל העמודות. תוקן באג multi-tenancy: MessagesContent לא סינן לפי tenantId בטעינה הראשונית. שאילתת סטטוס משלוח בדף שגיאות מיון עברה ל-$queryRaw שמחלץ רק שדה status מה-JSON במקום שליפת additionalData המלא. תוקן באג multi-tenancy בדף הגדרות הטריגרים (SettingsContent לא סינן לפי tenantId); שתי השאילתות עברו ל-Promise.all. ארבע שאילתות עצמאיות בדף פרטי נהג עברו ל-Promise.all (חיסכון של ~3 round-trips לDB). אפליקציה Sprint 5a: מפה אמיתית (react-native-maps 1.20.1) עם 8 markers ממוספרים וצבועים לפי סטטוס, callout עם פרטי לקוח, ניווט ל-visit detail בטאפ, floating header עם ספירת פעילים/נמסרו.
v01.17.004שיפורmessages/inboxחיפוש inbox בצד שרת על כלל השיחות
חיפוש הצ'אטים עבד עד כה רק על 20 השיחות הטעונות (client-side).
פרטים נוספים ↓הסתר ↑
חיפוש הצ'אטים עבד עד כה רק על 20 השיחות הטעונות (client-side). כעת, כל חיפוש שולח בקשה לשרת עם debounce של 300ms, מחזיר עד 50 תוצאות מכלל השיחות, ומציג skeleton loading בזמן החיפוש. תוקן: שאילתת החיפוש הראשונה סרקה את כל ה-messages ואז סיננה — הוחלפה בגישת matching_phones שמזהה קודם את הטלפונים הרלוונטיים (לפי שם לקוח / מספר טלפון) ורק אז שולפת פרטי שיחה עבורם. הוסר חיפוש לפי גוף הודעה אחרון שגרם לתוצאות שגויות. נוסף: חיפוש לפי ברקוד משלוח — הקלדת מספר ברקוד מוצאת את שיחת הלקוח הקשורה למשלוח.
v01.17.003תיקוןwebhooks/green-api, sorting-errorsתיקון: התראות מיון לא נסגרו למרות 👍
race condition בין כרון החזרת התראות לבין ה-webhook של ה-👍: הכרון שלח הודעה חדשה ועדכן את ה-messageId ב-DB לפני שהריאקציה הגיעה — כך שחיפוש לפי messageId נכשל ו-acknowledgedAt לא הוגדר.
פרטים נוספים ↓הסתר ↑
race condition בין כרון החזרת התראות לבין ה-webhook של ה-👍: הכרון שלח הודעה חדשה ועדכן את ה-messageId ב-DB לפני שהריאקציה הגיעה — כך שחיפוש לפי messageId נכשל ו-acknowledgedAt לא הוגדר. תוקן: fallback לחיפוש לפי chatId כאשר messageId לא נמצא, כך שלחיצת 👍 על כל הודעה בקבוצה (גם ישנה) תסגור את ה-alert. תוקן: בדיקת האמוג'י שינוי מ-=== ל-startsWith כדי לתמוך ב-👍 עם גוון עור (skin tone). תוסף: polling fallback בקרון החזרה — לפני כל שליחה חוזרת הקרון מושך את הסטוריית הצ'אט מ-Green API ובודק אם כבר הוגב ב-👍 על ההודעה האחרונה; אם כן, הוא מסמן את ה-alert כ-acknowledged ולא שולח עוד (מגן מפני כשלי webhook). תיקון תוכן הודעה ב-/messages: הודעות תבנית Meta נשמרות עם הטקסט המרונדר (displayBody) — במקום ה-placeholder הישן [תבנית Meta: ...]. פאנל הפרטים כעת מציג שם תבנית ותצוגה מקדימה של גוף התבנית עבור הודעות ללא טקסט שמור. אחידות צבעים בטפסי עריכת טריגרים: כל הצבעים (כתום, כחול, ירוק) הוחלפו בצבע הסגול של המערכת.
v01.17.002חדשshipments, target-shabbat, mobile, messagesשכפול משלוח + הוספת משלוחים ליעד שבת
אבחון כשלי הודעות: נוסף שדה error_code לטבלת shipment — המערכת שומרת קטגוריה מובנית לכל כשל שליחה (אין WhatsApp, הגבלת קצב, חלון 24ש׳ פג, שגיאת תבנית, שגיאת הרשאה, שגיאת ספק, שגיאת רשת).
פרטים נוספים ↓הסתר ↑
אבחון כשלי הודעות: נוסף שדה error_code לטבלת shipment — המערכת שומרת קטגוריה מובנית לכל כשל שליחה (אין WhatsApp, הגבלת קצב, חלון 24ש׳ פג, שגיאת תבנית, שגיאת הרשאה, שגיאת ספק, שגיאת רשת). בטבלת ההודעות מוצג badge עם סיבת הכשל ישירות בשורה ללא צורך לפתוח פרטים. נוסף פילטר "סיבת כשל" בסרגל הכלים לסינון לפי קטגוריה. טריגרי מערכת לעובדים: נוספו שלושה טריגרי WhatsApp לעובדים — LEAVE_REQUEST_SUBMITTED (שידור למנהלים), LEAVE_REQUEST_APPROVED ו-LEAVE_REQUEST_REJECTED (שליחה ישירה לעובד). ניתן להגדיר את הטריגרים דרך /messages/triggers; טריגרי אישור/דחייה אינם דורשים רשימת טלפונים כי הנמען נקבע אוטומטית. כניסה עם Google לפורטל עובדים: כפתור 'המשך עם Google' בדף הלוגין — העובד חייב להיות רשום במערכת עם אותו אימייל; עובד PENDING מופעל אוטומטית בכניסה הראשונה. תיקון: דף הפעלת חשבון עובד נכשל כי params.token היה undefined — ב-Next.js 15 params הוא Promise ולא חיכו לו. תוקן ל-async page + await params. אפשרות לשכפל משלוח בודד דרך תפריט הפעולות בשורה, ושכפול מרובה דרך ה-bulk actions bar. השכפול יוצר משלוח חדש בליונוויל עם כל שדות הנמען, הכתובת, ההגדרות הארגוניות ושדות מותאמים — ללא העתקת ברקוד, סטטוס, תאריכי מסירה, או מידע תפעולי. בנוסף, נוסף כפתור "הוספת משלוחים" בדף יעד שבת — פותח מודל עם אינפוט מרובה שורות לברקודים (הדבקה מאקסל) ובחירת פרשה, מאפשר לעדכן יעד שבת למשלוחים שאינם מוצגים כרגע בטבלה. שני המודלים עוצבו מחדש לפי שפת העיצוב של המערכת: כותרת דבוקה עם אייקון גרדיאנט + badge, מיין גלילה, תחתית דבוקה, כותרות קטעים עם צ'יפ צבעוני, שדות עם תוויות uppercase. תיקון: פיקר תבניות Meta המאושרות בטפסי הטריגרים לא אפשר גלילה ברשימה — נוספה max-h-64 overflow-y-auto ל-CommandList בהתאם לדפוס שנהוג בשאר הפיקרים. תיקון: דף /messages/triggers הציג חלל ריק גדול בתחתית — הוסר flex-1 מה-wrapper של SettingsContent והוחלף ב-pb-2 בלבד. תיקון: אינבוקס — כשהיה פוקוס על שדה ההקלדה בתחתית הצ'אט הופיע רינג כפול (על ה-wrapper וגם על הטקסטאריה הפנימית) — הוסרה בורדר הפוקוס הפנימית עם !important.
- סטטיסטיקות מסרונים: דף חדש /messages/analytics עם עלויות Meta Cloud API בדולר ושקל (שער חי), חלוקה לשיחות בתשלום מול שיחות שירות חינם (חלון 24h), פירוט ספקים (Meta/Green API), גרף לפי יום/שבוע/חודש, וטבלה מפורטת לפי תקופה
- תיקון ניווט: /analytics עבר ללשונית הגדרות (במקום מסרונים); /messages/analytics הוא הדף הסטטיסטי החדש
- טריגרי עובדים: 3 טריגרי WhatsApp חדשים — בקשת חופשה הוגשה (שידור למנהלים), אושרה/נדחתה (לעובד ישירות)
- אפליקציה: תיקון cache POD — שימוש ב-refetchQueries (במקום invalidateQueries) כדי שהcache יהיה עדכני לפני router.back(); sticky bottom מתעדכן מיד ללא pull-to-refresh
- אפליקציה: POD הפך ל-optional — state machine הסיר NEED_POD; sticky מציג 'צלם POD' + 'דווח כשל' כשניות כשאין POD ב-READY_TO_DELIVER
- אפליקציה: אישור מסירה ללא POD — Alert עם 3 אפשרויות: ביטול / צלם POD / אשר ללא POD; עם POD — Alert פשוט
- Backend: הוסר בדיקת POD_REQUIRED מ-deliver endpoint; COD_NOT_COLLECTED נשאר כדרישה עסקית
- טריגר טעות מיון עם חזרה אוטומטית: אפשרות לשלוח התראת טעות מיון לקבוצת WhatsApp (Green API) ולהפעיל לולאת חזרה כל 5 דקות — נעצרת כשאחד מחברי הקבוצה מסמן 👍 על ההודעה
- אפליקציה: מסך Today — Filter Chips הוחלפו ב-3 לשוניות עליונות (פעילים/נמסרו/נכשלו) בסגנון pill עם מונה; טאב עם 0 פריטים מואפל; empty state מותאם לכל לשונית
- אפליקציה: VisitCard — שורת badges קומפקטית חדשה: דחוף (אדום), אקספרס (סגול), שבת (טורקיז), COD עם סכום (ענבר); מחליפה את שורת ה-COD הגדולה הישנה
v01.17.001ייעולmessages-inboxייעול טעינת צ׳אט ב-inbox
שני שלבי ייעול לטעינת הצ׳אט: (1) הפחתת round trips לDB — הודעות ומשלוחים נשלפים במקביל, ובדיקת חלון 24ש מחושבת מהשורות שכבר הוחזרו ללא שאילתה נוספת.
פרטים נוספים ↓הסתר ↑
שני שלבי ייעול לטעינת הצ׳אט: (1) הפחתת round trips לDB — הודעות ומשלוחים נשלפים במקביל, ובדיקת חלון 24ש מחושבת מהשורות שכבר הוחזרו ללא שאילתה נוספת. (2) אינדקס פונקציונלי חדש על shipment(tenant_id, regexp_replace(phone)) — שאילתת חיפוש משלוח לפי טלפון עברה מ-full table scan עם regex per-row לחיפוש אינדקס, קיצור מ-6 שניות להאצה משמעותית. גם messages/route.ts וגם conversations/route.ts עודכנו להשתמש בביטוי תואם לאינדקס (IN במקום CASE).
v01.17.000חדשemployee-portalminorפורטל עובדים — ממשק מלא
ווידג'ט נוכחות ב-Navbar: משתמשי STAFF המקושרים לרשומת עובד מקבלים ממשק כניסה/יציאה ממשמרת ישירות מהנאבר — טיימר חי בעת משמרת פעילה, כפתור 'כנס' בעת חוסר משמרת עם בחירת סוג עבודה אם יש יותר מאחד.
פרטים נוספים ↓הסתר ↑
ווידג'ט נוכחות ב-Navbar: משתמשי STAFF המקושרים לרשומת עובד מקבלים ממשק כניסה/יציאה ממשמרת ישירות מהנאבר — טיימר חי בעת משמרת פעילה, כפתור 'כנס' בעת חוסר משמרת עם בחירת סוג עבודה אם יש יותר מאחד. גישה לניהול הנוכחות חסומה לאותם משתמשים כברירת מחדל (אפילו אם הם ADMIN); ניתן להפעיל עבור אחראי שכר דרך טאב חדש 'משתמשי מערכת' בהגדרות הנוכחות. שיפורי עיצוב כותרת סיידבר: הגדלת אייקון הלוגו, padding פנימי לכפתור, ורווחים עקביים של 8px בין כל האלמנטים בכותרת. פורטל לקוח — טבלת משלוחים: שדרוג מלא לרמת טבלות האדמין — sticky actions column, בחירה מרובה, bulk actions bar מתחת לטבלה (העתק ברקודים / הדפס מדבקות / ייצא לאקסל), הרחבת עמודות בגרירה, ניהול עמודות ו-Excel עברו לתפריט בכותרת עמודת הפעולות, נקודות לאורך, סקרולבר אופקי, toolbar נקי. תיקון: קישורי הזמנת עובד נבנים כעת מ-AUTH_URL/NEXTAUTH_URL/NEXT_PUBLIC_APP_URL ולא מה-origin header — מונע מצב שה-URL ריק ומייל ההזמנה לא ניתן ללחיצה. שדרוג מקיף של פורטל העובד: דף נוכחות עם תצוגת סטטוס חיה, טיימר משמרת, כפתורי כניסה/יציאה, דיווח רטרואקטיבי ומשמרות בהמתנה. היסטוריית משמרות מקובצת לפי יום עם Accordion, ניווט חודשי/שבועי. בקשות חופשה עם עיצוב מחדש ותצוגה מדורגת. משימות עם הערת עובד, badge איחור וקטע הושלמו מתקפל. הוסרה דף 'חברי צוות' מההגדרות — הפונקציונליות קיימת ב'משתמשים'. שדרוג דף המשתמשים: pagination server-side (תוקן באג שהסתיר משתמשים מעל 50), עמודת טלפון, שינוי תפקיד inline בטבלה, סינון 'מחוברים עכשיו', ואיפוס סיסמה עם סיסמה זמנית. עמודת 'כניסות' כעת מציגה session count — כל חזרה לאפליקציה אחרי פער של 5+ דקות נספרת ככניסה. עמודת מעורבות חדשה עם badge צבעוני (פעיל/מדי פעם/רדום/חדש). פאנל נוכחות חיה (SSE) — מציג מי מחובר ובאיזה דף. פילטר רדומים (30+ יום) עם חסימה קבוצתית. כתיבה מחדש של דף הגדרות הנוכחות: שדות מסודרים לפי המודל הנכון (regularDayHours, overtimeThreshold125/150, מכפילי שבת), טאב שעות נוספות מורחב, טאב בונוסים חדש עם ניהול בונוסים לכל עובד. שיפורי Meta API: קודי שגיאה ידידותיים (130429/131026/131047/190 ועוד), banner תבניות לא פעילות, בדיקת תוקף Token בדף אינטגרציות, זמן נותר לחלון 24ש ב-inbox, retry אוטומטי על rate-limit.
- דף נוכחות: dot מהבהב, טיימר חי, דיווח רטרו עם dialog, פאנל משמרות ממתינות/נדחות
- היסטוריה: Accordion לפי יום, toggle חודש/שבוע, ניווט קדימה/אחורה
- חופשות: עיצוב מחדש עם אייקונים, תצוגה נפרדת ממתין/היסטוריה
- משימות: הערת עובד, badge באיחור, קטע הושלמו מתקפל
- ניווט תחתון: 5 כרטיסיות — נוכחות, היסטוריה, חופשות, מסמכים, משימות
- API חדשים: me, retro-shifts (GET/POST/DELETE), shifts/history
- ממשק מנהל: דיאלוג עריכת משמרת (שעות, הפסקה, סטטוס, הערת מנהל), דחייה עם סיבה חופשית, כפתור 'ממתינות לאישור' עם ספירה בטולבר
- דשבורד נוכחות: כרטיס 'ממתינות לאישור' עם ספירה ולינק ישיר לדף המשמרות המסונן
- דף משמרות: אישור כולל (bulk approve) עם progress counter, ייצוא CSV עם BOM לתאימות Excel, פילטר סטטוס מ-URL query param
- פורטל עובד: בחירת סוג עבודה inline לפני כניסה — כפתורי toggle עם צבע, ברירת מחדל אוטומטית, מוסתר כשיש פחות מ-2 סוגים; שם סוג העבודה מוצג גם בכרטיס הסטטוס ובמשמרות האחרונות
- הגדרות נוכחות: כתיבה מחדש עם שדות נכונים מהסכמה (regularDayHours, overtimeThreshold125/150, autoBreakAfterHours/Minutes, sabbathMultiplier*), API GET/PUT מחובר כראוי
- בונוסים לעובדים: API GET/POST/DELETE, טאב ייעודי בהגדרות עם פתיחת/קריסת רשימת בונוסים לכל עובד, דיאלוג הוספת בונוס עם סוג/סכום/תאריכים/הערה
- לוח שנה: תצוגת גריד חודשי עם ניווט חודש/שנה, הדגשת שבת/יום נוכחי, לחיצה על יום מציגה אירועיו בפאנל צדדי; toggle בין גריד ורשימה שנתית
- דף תבניות Meta: תיקון באג — תבניות שטרם נשלחו ל-Meta מוצגות עכשיו ברשימה (badge 'טרם נשלחה'); חיפוש וסינון בצד הלקוח לפי שם/קטגוריה/סטטוס; stats panel ב-aside (מאושרות/ממתינות/נדחו/טרם נשלחו); dropdown פעולות במובייל; תאריך עדכון אחרון בכל שורה; empty state מותאם לפילטר עם כפתור ניקוי; 4 skeletons טעינה; הסרת קוד מת (VARIABLE_KEYS, MetaBinding, MetaTemplateOption, MetaStatusBadge)
- build fix: הסרת prop לא חוקי dir מ-DropdownMenuContent בדף תבניות (TypeScript error בדיפלוי)
- שכר מנהל: תוקן מנוע חישוב — שימוש ב-TenantWorkRules לסף שעות נוספות ומכפילים, תמיכה בבונוסים (חודשי/שעתי/חד-פעמי), חישוב bulk לכל עובדים; דיאלוג פירוט בלחיצה על שורה עם breakdown שעות+סכומים ואישור; ייצוא CSV; כרטיסי סיכום
- שכר עובד: API עצמי (/api/attendance/self/payroll) + card שכר בדף הנוכחות מציג 3 חודשים אחרונים עם שעות, שעות נוספות וסהכ
- ווידג'ט נוכחות ב-navbar: משתמשי מערכת (STAFF) המקושרים לרשומת עובד רואים טיימר משמרת פעילה (ציר ירוק מהבהב + שעון) וכפתור כניסה/יציאה ממשמרת ישירות מהנאב. חסימת גישה לממשק ניהול הנוכחות למשתמשי מערכת עם employeeId — ניתן לביטול חסימה ספציפית per-user דרך טאב 'משתמשי מערכת' בהגדרות הנוכחות.
- מסמכים עובד: פורטל העלאת מסמכים עצמי עם UploadDialog, הצגת בקשות ממתינות/שהושלמו, סינון וגבול 5 מסמכים עם toggle; API PENDING_APPROVAL לכל העלאה
- מסמכים מנהל: ניהול בקשות מסמכים (יצירה/הפעלה/מחיקה) דרך דיאלוג ייעודי בטולבר; תיקון באג fullName → firstName+lastName בטבלה, חיפוש ו-preview dialog
- אישור/דחיית מסמכים: API PATCH לעדכון סטטוס + כפתורי אשר/דחה לשורות PENDING_APPROVAL בדף מסמכים מנהל + dialog דחייה עם סיבה
- dashboard נוכחות: כרטיס מסמכים פגי תוקף (30 יום) עם לינק לדף המסמכים; grid שונה ל-6 עמודות
- אישור חופשה חלקי: dialog אישור עם DatePicker לעריכת תאריכים לפני אישור; API approve מקבל startDate/endDate אופציונליים ומחשב totalDays מחדש; dialog דחייה עם שדה סיבה
- דף דוחות: כתיבה מחדש עם נתונים אמיתיים — 4 טאבים (משמרות/שכר/חופשות/מסמכים פגי תוקף), פילטר חודש+שנה, ייצוא CSV עם BOM, טבלת סיכום בתחתית שכר
- כרטיסי סיכום בדשבורד נוכחות: עיצוב מחדש לפי דפוס ShipmentStats — אייקון בקונטיינר רקע צבעוני עם rounded-lg, מספרים ניטרליים font-bold, ביטול גבולות צבעוניים על כרטיסים
- כרטיסי סיכום בדפי דוחות ושכר: אחידות עם הדשבורד — אותו דפוס icon-in-bg-container בכל דפי הנוכחות
- שכר — טבלה: הסרת צבעי טקסט מוגזמים משורות הטבלה; תיקון באג כפתור מחיקה שלא הופיע (חסר class='group' על שורת הטבלה)
v01.16.001חדשemployees, messagesהתחזות לעובד מדף העובדים
הוספת יכולת התחזות לעובד עבור מנהלי מערכת (OWNER ומעלה).
פרטים נוספים ↓הסתר ↑
הוספת יכולת התחזות לעובד עבור מנהלי מערכת (OWNER ומעלה). לחיצה על 'התחבר כעובד' בטבלת העובדים מעבירה את המנהל לפורטל העובד תחת זהות העובד, עם באנר התחזות ואפשרות חזרה מיידית. בנוסף הורחב פורטל העובד לממשק מלא: דף בקשות חופשה, דף מסמכים אישיים, דף משימות — עם ניווט תחתון בין הדפים. תיקון שגיאת Meta #132001 — תבניות שאינן קיימות ב-Meta מסומנות כ-'לא נמצאת ב-Meta' עם כפתור ניתוק קישור; שם התבנית נוסף ל-log כדי לאפשר אבחון.
v01.16.000חדשmobileminorאפליקציה ניידת — טופס גביית גוביינא (COD)
נוסף מסך גביית גוביינא באפליקציית השליח.
פרטים נוספים ↓הסתר ↑
נוסף מסך גביית גוביינא באפליקציית השליח. אמצעי התשלום נקבע ע"י ה-Operator מראש (מזומן/צ'ק) — השליח מאשר בלבד ואינו בוחר. לצ'ק: toggle בין צילום הצ'ק להקלדה ידנית — אחד מהם מספיק. Backend מוסק סכום ואמצעי מ-DB ומאכף עליהם.
- מזומן: הצגת הסכום read-only + אישור בלחיצה אחת
- צ'ק: toggle בין מצב צילום (Phase 3) למצב הקלדה ידנית — אחד מספיק
- Backend: אמצעי תשלום נשלף מ-CodTracking.codType (לא נשלח מ-client)
- Seed עודכן: SHP00001+SHP00007=cash, SHP00005=check
- /today API מחזיר codType לכל ביקור עם גוביינא
- Phase 3: מצלמה אמיתית דרך expo-image-picker + דחיסה ל-1600px / 0.85 quality עם expo-image-manipulator; thumbnail מוצג לאחר צילום
- Phase 4: submitCod() שולח base64 (photo) או 5 שדות (manual); הצלחה → Alert + invalidateQueries + router.back(); שגיאה → Alert עם 'נסה שוב'
- אקורדיון מסרונים בדף משלוח: הצגת מסרונים שנכשלו גם כשה-message ריק (sendStatus=FAILURE)
- דף תבניות Meta: header עטוף (flex-wrap) ב-mobile, כפתורים icon-only במסכים צרים, Dialog גלילה ב-mobile
- דף שינוי סיסמה: נוסף /auth/change-password עם אימות סיסמה נוכחית + API route POST /api/users/change-password
- Sprint 4d Phase 1: POST /api/v1/mobile/driver/visits/:id/deliver — בדיקת POD + COD לפני סימון + update isDone/deliveredAt
- Sprint 4d Phase 1: POST /api/v1/mobile/driver/visits/:id/fail — reasonCode + notes (חובה) + העלאת תמונת תיעוד אופציונלית; failureReason נשמר ב-shipment
- Sprint 4d Phase 2: delivery.ts — markDelivered() + markFailed() עם base64 photo conversion ו-typed error codes
- תיקון deriveStatus: failedAt לבד (ללא isDone) מחזיר status='failed' — תואם ל-fail שלא מסמן isDone
- תיקון middleware: /employees (ניהול) זוהה בטעות כנתיב פורטל עובדים — גרם להפניה ל-/shipments; תוקן startsWith ל-/employee/
- שדות תאריך התחלה/סיום בטופס עובד הוחלפו בבורר תאריכים עם לוח שנה (Popover + Calendar mode=single) — כולל כפתור ניקוי לתאריך הסיום
- Sprint 4d Phase 3: state machine חכם ב-sticky bottom — NEED_POD/NEED_COD/READY_TO_DELIVER; HeroSection בצבעי כחול/ירוק/אדום לפי status; handleMarkDelivered עם Alert אישור
- Sprint 4d Phase 4: מסך fail.tsx — radio picker לסיבת כשל, textarea חובה, תמונת תיעוד אופציונלית עם מצלמה; submit → markFailed() + Alert + router.replace
v01.15.001שיפורtasksלוח משימות — תיקון רווחים לעיקרון 8px אחיד
תוקנו כל חריגות הרווח בתצוגת הדסקטופ של לוח הקנבן: gap בין אזורים, gap בסרגל הפילטרים, gap בין עמודות, padding בכותרת העמודה, gap בשורת המטאדאטה בכרטיס ובאזור הפעולות — הכל עבר ל-8px בדיוק.
פרטים נוספים ↓הסתר ↑
תוקנו כל חריגות הרווח בתצוגת הדסקטופ של לוח הקנבן: gap בין אזורים, gap בסרגל הפילטרים, gap בין עמודות, padding בכותרת העמודה, gap בשורת המטאדאטה בכרטיס ובאזור הפעולות — הכל עבר ל-8px בדיוק. בוטל padding פנימי ברירת-מחדל (10px) שקומפוננט KanbanColumn הוסיף מסביב לתוכן העמודה.
v01.15.000חדשcustomer-portalminorפורטל לקוחות — כתובות מועדפות ולינק מעקב
לקוחות בפורטל יכולים כעת לשמור כתובות מועדפות (מחסן, משרד וכו') ולטעון אותן בלחיצה אחת בטופס יצירת משלוח.
פרטים נוספים ↓הסתר ↑
לקוחות בפורטל יכולים כעת לשמור כתובות מועדפות (מחסן, משרד וכו') ולטעון אותן בלחיצה אחת בטופס יצירת משלוח. הכתובות משותפות בין כל המשתמשים תחת אותו חשבון לקוח. בנוסף, בדף פרטי המשלוח נוסף כפתור 'לינק מעקב' שמעתיק ללוח את הקישור הציבורי של המשלוח לשליחה ללקוח הקצה. חיפוש בדף הלקוחות עבר לעבודה בצד הלקוח — מיידי, ללא debounce וללא בעיות focus.
- עמוד 'כתובות מועדפות' תחת הגדרות הפורטל — ניהול מלא (הוסף, ערוך, מחק)
- כפתור 'מועדפות' בטופס יצירת משלוח — מאכלס אוטומטית את כל שדות הכתובת
- כתובות משותפות ברמת חשבון הלקוח — לא אישיות למשתמש
- כפתור 'לינק מעקב' בדף פרטי משלוח — מעתיק את כתובת הטראקינג הציבורית
- הגבלת 50 כתובות לחשבון
v01.14.000חדשattendanceminorפורטל עובדים — כניסה עצמאית לנוכחות
עובדים שכירים מנוהלים עכשיו בנפרד ממשתמשי המערכת, בדיוק כמו לקוחות ושליחים.
פרטים נוספים ↓הסתר ↑
עובדים שכירים מנוהלים עכשיו בנפרד ממשתמשי המערכת, בדיוק כמו לקוחות ושליחים. המנהל שולח הזמנה לאימייל העובד מתוך דף הניהול. העובד מגדיר סיסמה ונכנס דרך /employee/login — עמוד login ייעודי לפורטל עובדים. לאחר הכניסה הוא מגיע לדף נוכחות אישי בלבד, ללא גישה לשאר המערכת. תומך גם בשחזור סיסמה.
- פורטל עובדים עצמאי בכתובת /employee/login — כניסה נפרדת ממשתמשי מערכת
- שדה 'שלח הזמנה לפורטל' בפעולות שורה בדף ניהול עובדים — שולח מייל עם קישור הגדרת סיסמה
- flow הזמנה + קבלת הזמנה + שחזור סיסמה מלא
- הוספת שדות auth ל-Employee: status, passwordHash, inviteToken, passwordResetToken
- EMPLOYEE userType בסשן — בידוד מלא מ-STAFF ו-CUSTOMER
v01.13.000חדשattendanceminorפורטל נוכחות עצמי לשליח שכיר
שליח שכיר (EMPLOYEE_DRIVER) מקבל כעת ממשק ייעודי ומבודד לנוכחות עצמית.
פרטים נוספים ↓הסתר ↑
שליח שכיר (EMPLOYEE_DRIVER) מקבל כעת ממשק ייעודי ומבודד לנוכחות עצמית. עם הכניסה למערכת הוא מופנה אוטומטית לדף נוכחות פשוט שמאפשר החתמת כניסה ויציאה בכפתור אחד, ורואה את היסטוריית המשמרות שלו ב-30 הימים האחרונים. אין גישה לאף חלק אחר במערכת — middleware חוסם את כל הניתובים האחרים. הוספו הרשאות חדשות ATTENDANCE_SELF_VIEW ו-ATTENDANCE_SELF_CLOCK לתפקיד זה.
- דף נוכחות מבודד ללא sidebar — חוויה נקייה ופשוטה
- כפתור כניסה/יציאה בודד עם שעון חי ומשך המשמרת הנוכחית
- טבלת משמרות אחרונות (30 יום) עם שעות וסיכום זמן
- middleware חוסם גישה לכל שאר העמודות — העובד רואה רק את הנוכחות שלו
- הוספו הרשאות ATTENDANCE_SELF_VIEW ו-ATTENDANCE_SELF_CLOCK
v01.12.002שיפורtasksדף משימות עוצב מחדש כלוח Kanban
דף המשימות האישי עוצב מחדש כלוח Kanban עם 4 עמודות (ממתין, בטיפול, הושלם, בוטל).
פרטים נוספים ↓הסתר ↑
דף המשימות האישי עוצב מחדש כלוח Kanban עם 4 עמודות (ממתין, בטיפול, הושלם, בוטל). ניתן לגרור כרטיסיות בין עמודות לעדכון סטטוס. פילטרי תאריך ועדיפות עובדים על כל העמודות. עמודת 'בוטל' מוצגת לצפייה בלבד ללא אפשרות גרירה אליה. שיפורי עיצוב נוספים בצ׳אט inbox: שדה הקלדה שוכתב לשורה אחת — כפתור תבנית Meta כאייקון בתוך שורת ה-input (במקום שורה שלמה נפרדת), בצמוד לבורר אימוג'י ולכפתור שליחה; badges של לא-נקראו/לא-נענו שונו לצבע שחור סולידי (zinc-800); נוסף dot-grid pattern עדין לרקע אזור השיחה; הוסר טקסט כפול 'מחוץ לחלון 24 השעות' שהופיע מתחת לאינפוט (הטקסט כבר קיים ב-placeholder של שדה ההקלדה). תוקן באג קריטי: preferences route דרסה את כל שדות ה-settings שאינם העדפות (whatsappTemplates, messagingChannel וכו') בכל עדכון העדפות. תוקן באג קריטי בפורטל לקוחות: חיפוש גלובלי קרס עם TypeError — sendStatus לא נכלל ב-API של /api/portal/shipments, גרם ל-undefined.toLowerCase() בעת רנדור תוצאות. הוחלף ב-additionalData + getDeliveryStatusBadge בהתאם לשאר הפורטל. תוקנה שגיאת 403 בפורטל: BrandColorInjector ב-root layout קרא ל-useCurrentTenant שניסה לפנות ל-/api/settings/profile גם עבור משתמשי CUSTOMER — הוסף guard שמונע את ה-fetch לגמרי עבור משתמשי פורטל. תוקנה אזהרת גרף בדשבורד פורטל: ResponsiveContainer עם height="100%" קרא -1 לפני שה-layout הסתיים — הוחלף ב-height={256} מפורש.
v01.12.001חדשmessaging/cronחלון שליחה: שעות פעילות, שבת וחגים לפי טננט
עיצוב מחדש של צ׳אט inbox לסגנון שחור-לבן סולידי: הודעות יוצאות עברו מירוק לרקע כהה (zinc-900) עם טקסט לבן; הודעות נכנסות — רקע muted עדין; כפתור שליחה — שחור; כל badges ה-source/window בצבעי ניטרל; מפריד 'הודעות חדשות' —…
פרטים נוספים ↓הסתר ↑
עיצוב מחדש של צ׳אט inbox לסגנון שחור-לבן סולידי: הודעות יוצאות עברו מירוק לרקע כהה (zinc-900) עם טקסט לבן; הודעות נכנסות — רקע muted עדין; כפתור שליחה — שחור; כל badges ה-source/window בצבעי ניטרל; מפריד 'הודעות חדשות' — ניטרל; הצגת שיחה פעילה בסרגל — bg-muted; dot של lא-נקרא ידני — אפור. הצבעים היחידים שנשארו: צבעי אווטר, badge ירוק לא-נקראו, badge amber לא-נענו, צ׳ק כחול READ. הודעות מתוזמנות כעת נשארות בתור כשאינן בחלון הזמן המותר — לא מאבדות ניסיון. כל טננט יכול להגדיר שעות שליחה מותרות ולסמן חסימה בחגים. ה-cron job בודק את החלון לפני כל הודעה; אם השעה מחוץ לטווח, ביום שבת פעיל, או ביום טוב — ה-message נשמר בתור ל-cron הבא. ספריית @hebcal/core משמשת לבדיקת חגי ישראל (מצב ישראל, ימי חג בלבד). תוקן באג ב-AI delivery parser: Claude החזיר JSON עטוף ב-markdown code block (` ```json ``` `) למרות ההנחייה — הוסף strip של העטיפה לפני ה-parse. תוקנה בחירת משלוח ב-AI delivery: במקום לבחור את המשלוח האחרון לפי createdAt, מחפשים כעת את המשלוח שאליו נשלחה ההודעה האחרונה ב-WhatsApp לאותו טלפון — כי הלקוח מגיב לאותה הודעה ספציפית. פערי הפצה: כפתורי שיבוץ/לא משובץ הוחלפו ב-FiltersPopover כללי עם שלוש קטגוריות — שיבוץ שליח (single-select), שליח ספציפי, וסטטוס משלוח. נוספה עמודת סטטוס תפעול לטבלת פערי הפצה. פילטר שיבוץ שליח מאותחל ל"משובץ" ומציג מספרים מעודכנים לפי הסינון הנוכחי. שיפור ביצועים בדף inbox: שאילתת conversations שוכתבה לCTEs — unread_count חושב בנפרד פעם אחת (O(N)) במקום sub-query מתואם לכל שיחה (O(N²)); קריאות DB בpages/messages צומצמו מ-4 סדרתיות ל-2 מקביליות; תדירות polling הופחתה מ-5 שניות ל-15. pagination בסרגל השיחות: API מחזיר 20 שיחות ראשונות (cursor-based), גלילה לתחתית טוענת דף נוסף דרך IntersectionObserver. prefetch on hover: ריחוף מעל שיחה 150ms מתחיל לטעון הודעות ברקע עם cache של 30 שניות — כניסה לשיחה instant אם ה-cache מוכן. ברקודי משלוח בצ׳אט: כל מספר משלוח שמופיע בגוף הודעה הופך ללחיץ — אייקוני העתקה וניווט בריחוף, ולחיצה על הברקוד פותחת drawer עם פרטי המשלוח (זהה לחוויה בטבלאות). סימון כנקרא/לא נקרא: בריחוף על שיחה מוצג כפתור MailIcon שמחליף את השעה — לחיצה מסמנת כנקרא/לא נקרא; לחיצה ימנית על שיחה פותחת תפריט הקשר עם אותן אפשרויות. שיחות מסומנות כ"לא נקראו" מציגות נקודה כחולה במקום badge, ומופיעות בטאב 'לא נקראו'. מצב נשמר ב-localStorage.
v01.12.000חדשmessaging/inboxminorהצגת מדיה נכנסת (תמונות, שמע, וידאו) בצ׳אט
תיקון שתי בעיות בצ׳אט inbox: (1) הודעות יוצאות מטריגרים לא הופיעו — shipment-trigger-processor שלח דרך sendWhatsApp אבל לא קרא ל-recordOutboundMessage, כך שלא נכתב שום דבר ל-WhatsappMessage; נוספה קריאה לאחר כל שליחה מיי…
פרטים נוספים ↓הסתר ↑
תיקון שתי בעיות בצ׳אט inbox: (1) הודעות יוצאות מטריגרים לא הופיעו — shipment-trigger-processor שלח דרך sendWhatsApp אבל לא קרא ל-recordOutboundMessage, כך שלא נכתב שום דבר ל-WhatsappMessage; נוספה קריאה לאחר כל שליחה מיידית. (2) תמונות נכנסות הציגו רק placeholder — גישת Supabase לא עבדה ללא אחסון מוגדר; הוחלפה ב-proxy route: ה-webhook שומר /api/messages/inbox/media/{mediaId} ב-mediaUrl, ה-proxy מביא את הקובץ מ-Meta Graph API עם access token של ה-tenant ומחזירו לדפדפן עם cache לשעה. שיפורים נוספים: הודעת תבנית Meta מציגה גוף מרונדר עם ערכי משתנים אמיתיים; לחיצה על תמונה פותחת מודל מסך-מלא עם כפתור הורדה.
- trigger processor: recordOutboundMessage אחרי כל שליחה מיידית — גם הצלחה וגם כשל
- proxy route: GET /api/messages/inbox/media/[mediaId] — auth דרך session, Meta Graph API
- תמיכה ב-image / audio / voice / video / document / sticker ללא תלות ב-Supabase
- Cache-Control: private, max-age=3600 — הדפדפן לא מוריד שוב לשעה
- Sprint 4b-1 Phase 1+2: POD Screen — Mode A (Camera) עם rule-of-thirds grid + amber focus brackets + top bar (flash/pill/done✓) + shutter + switch-cam + gallery thumb; expo-file-system/legacy + expo-image-manipulator; כפתור StickyActions ב-Visit Detail מנווט ל-/visit/[id]/pod
- Sprint 4b-1 Phase 3+4+5: POD Preview + Summary + Submit — Mode B (preview עם timestamp + delete/save) + Mode C (grid 3 עמודות + empty slots + add slot + note textarea + sticky CTA ירוק); storage cleanup: מחיקת קבצים ב-FileSystem בעת יציאה ומחיקת תמונה; compression: quality 1 → manipulateAsync 0.85 JPEG 1920px
- Sprint 4b-2: POD Real Upload — POST /api/v1/mobile/driver/visits/:id/pod (Zod validation, driver ownership check, base64→Buffer→Supabase Storage, ShipmentImage records); uploadPod() ב-mobile עם onProgress; progress overlay + ActivityIndicator + progress bar ב-Summary; queryClient invalidateQueries אחרי הצלחה; cleanup local files post-upload
v01.11.000חדשpublic/validateminorדפים ציבוריים: עדכון פרטי מסירה ומעקב משלוח
נבנו שני דפים ציבוריים (ללא login) שנפתחים מקישור וואטסאפ.
פרטים נוספים ↓הסתר ↑
נבנו שני דפים ציבוריים (ללא login) שנפתחים מקישור וואטסאפ. /validate/[id]: מאפשר ללקוח לעדכן פרטים חסרים (קומה, דירה, הערות לשליח) — שדות חסרים מסומנים בצהוב, עדכון נשמר ב-DB דרך PATCH. /tracking/[id]: מציג ציר זמן ויזואלי של מצב המשלוח — 4 שלבים (נוצר / עובד במחסן / יצא להפצה / נמסר) עם צבעים דינמיים לפי סטטוס, כולל טיפול בכשל, ביטול ומסירה.
- דף RTL פשוט ונקי — מותאם למובייל, ללא auth
- API route: GET + PATCH /api/public/shipments/[publicId] — גישה רק לפי public_id
- שדות עריכתיים: קומה, דירה, הערות לשליח — עם הדגשה ויזואלית על חסרים
- הגנת whitelist: רק שדות מסירה עריכתיים — שם, טלפון, ברקוד לא נחשפים לעריכה
- /validate הוסף ל-publicRoutes ב-middleware
- Sprint 4a Phase 1+2: Barcode Scanner — expo-camera + expo-haptics, CameraView + animated scan line + L-corners reticle + torch toggle; Permission denied screen עם openSettings; app.json permissions
- דף מעקב /tracking/[id] — ציר זמן ויזואלי עם 4 שלבים, צבעים דינמיים לפי סטטוס (ירוק=נמסר, אדום=כשל/בוטל, סגול=בדרך)
- API route: GET /api/public/shipments/[publicId]/tracking — נתוני מעקב בלבד, ללא חשיפת מידע רגיש
- /tracking הוסף ל-publicRoutes ב-middleware
- Sprint 4a Phase 3+4: חיבור detection — onBarcodeScanned + debounce 1 שניה + freeze לאחר זיהוי + haptic success/error + Alert 3 אפשרויות לברקוד לא מוכר
- כפתורי CTA ב-Meta: תמיכה מלאה בכפתור URL מוטמע בהודעה — הגדרה בדיאלוג ההגשה, שמירה ב-LocalTemplate, שליחה בטריגרים ו-resend עם dynamic suffix מ-public_id/barcode
- public_id נוסף כמשתנה ל-buildVariables — מאפשר שימוש בו כסיומת דינמית בכפתורי URL
- סנכרון לליונוויל מ-/validate: עדכון לקוח בקומה/דירה/הערות מסתנכרן אוטומטית לליונוויל (fire-and-forget); שדות כתובת נשלחים עם prefix destination_* בפורמט native של ליונוויל
- AI auto-reply: לקוח שמגיב בצ'אט עם קומה/דירה/ליד הדלת מקבל עדכון אוטומטי במערכת ובליונוויל + הודעת אישור חוזרת — Claude Haiku מחלץ פרטים מעברית חופשית עם debounce של 60 שניות לצבירת הודעות מרובות
v01.10.001תיקוןmessaging/triggersתיקון: טריגרי משלוח לא הופעלו
שדות ריקים בפרמטרים של תבנית Meta מוצגים כ-*חסר* (מודגש בוואטסאפ) במקום '-'.
פרטים נוספים ↓הסתר ↑
שדות ריקים בפרמטרים של תבנית Meta מוצגים כ-*חסר* (מודגש בוואטסאפ) במקום '-'. קובץ trigger-processor.ts נמחק בהגירה מ-NestJS ולא שוחזר — טריגרי ShipmentSetting מעולם לא הופעלו. שוחזר כ-shipment-trigger-processor.ts ומחובר ל-processTaskDeferred. תוקנו גם resend ו-cron שלא העבירו metaTemplateComponents לתבניות Meta עם פרמטרים. תוקן בנוסף: ספירת מיקודים בטבלת הליקוט כללה משלוחים ממחוזרים — נוסף deletedAt: null ל-baseWhere כדי שיחול גם על nested relation filter ב-db.visit.groupBy. תוקן: טריגרים שולחים תמיד דרך Green-API למרות שנבחרה תבנית Meta — setting.channel נשמר תמיד כ-green-api (ופגם בטופס). התיקון: קריאה ל-loadChannelContext + resolveChannelForTemplate לפי metaTemplateName של התבנית המקושרת, בנפרד לכל recipient. תוקן: buildMetaComponents השתמשה ב-variables map פנימי שהחסיר tracking_url, validation_url ועוד — Meta דחה בשגיאה 131008 על ערכים ריקים. עכשיו משתמש ב-buildVariables מ-template-renderer.ts שכולל את כל המשתנים. נוסף: log מפורט לפני שליחת trigger שמציג channel, metaParamMap, וערכי הפרמטרים — לאבחון מהיר של שגיאות 131008. תוקן: הודעות אוטומטיות מ-cron scheduled-messages לא הופיעו ב-inbox הצ'אט — חסרה קריאה ל-recordOutboundMessage אחרי שליחה מוצלחת.
v01.10.000חדשmobileminorMobile Driver API — היום שלי + פרטי ביקור
Sprint 3a+3b: backend endpoints + מסך Today מלא לאפליקציית השליח.
פרטים נוספים ↓הסתר ↑
Sprint 3a+3b: backend endpoints + מסך Today מלא לאפליקציית השליח. GET /driver/today מחזיר את כל ביקורי היום לפי timezone ישראל, כולל stats, COD batch query, סינון soft-deleted. GET /driver/visits/:id מחזיר פרטים מלאים + timeline + relatedActions עם security isolation. Sprint 3b: TanStack Query setup, API hooks (useToday/useVisit), Tab Navigator עם RouterTabBar wrapper, ומסך Today המלא — FlatList עם React.memo, 6 filter chips client-side, stats bar, loading skeletons, error state, empty state.
- GET /api/v1/mobile/driver/today — visits של היום, order לפי dailyOrder, batch COD query
- GET /api/v1/mobile/driver/visits/:id — פרטים מלאים, timeline, relatedActions
- Security: 403 על visit של driver אחר (לא 404, לא מחשיף קיום)
- Tab Navigator עם custom TabBar (RouterTabBar wrapper) + FAB scan button
- מסך Today: FlatList + React.memo, 6 filter chips, stats bar, pull-to-refresh
- Loading skeletons (5×), error state עם retry, empty state לפי filter
- Seed script מורחב: 8 shipments + visits + 3 COD records + Driver record
- Sprint 3c: Visit Detail Screen — Hero gradient (כחול/ירוק לפי סטטוס), Customer Card עם 4 action buttons, Address Card עם mini-map, Shipment Card (grid + notes), COD Card (amber/green), Timeline Card (TimelineEventCard), Delivery Summary (POD grid), Sticky bottom bar (סרוק/נזק/טעות שיבוץ)
v01.09.001תיקוןmobile/apiMobile Auth — בדיקת revocation ב-/me
תיקון: GET /me לא בדק אם המכשיר נותק לאחר logout.
פרטים נוספים ↓הסתר ↑
תיקון: GET /me לא בדק אם המכשיר נותק לאחר logout. הוספת בדיקת userDevice.revokedAt לפני החזרת המשתמש — עכשיו /me מחזיר 401 DEVICE_REVOKED לאחר logout או revoke.
v01.09.000חדשmobile/apiminorMobile Auth — Full Backend + Mobile Integration
Sprint 2b+2c Phase 1-3: auth מלא לאפליקציית השליחים.
פרטים נוספים ↓הסתר ↑
Sprint 2b+2c Phase 1-3: auth מלא לאפליקציית השליחים. Backend: user_devices, JWT, login+refresh+logout+me endpoints. mobile-auth-middleware.ts לשיתוף בין endpoints. Token rotation ב-refresh (hash comparison). Mobile: device-id.ts, api-client.ts עם fetch אמיתי + timeout. Phase 3: ApiClient (auto-refresh + single-flight), auth-store מחדש (restore אופטימיסטי + verifySession ברקע + silentLogout אידמפוטנטי), login.tsx sessionMessage banner.
- POST /api/v1/mobile/auth/login — timing-safe bcrypt, lock/active/tenant checks
- POST /api/v1/mobile/auth/refresh — token rotation, hash verification, DEVICE_REVOKED check
- POST /api/v1/mobile/auth/logout — revoke device ב-DB
- GET /api/v1/mobile/auth/me — verify token + user data עדכני
- mobile-auth-middleware.ts — Bearer extraction + verifyAccessToken משותף
- ApiClient (lib/api/client.ts) — auto-refresh on 401, single-flight (refreshPromise), dynamic import לauth-store למניעת circular dep
- auth-store.ts — restore אופטימיסטי מ-SecureStore + verifySession ברקע, silentLogout אידמפוטנטי, sessionMessage state
- login.tsx — InfoBanner לsessionMessage (session expired), clearSessionMessage ב-unmount
v01.08.000חדשmobileminorMobile Auth Foundation — Mock Login + Routing
Sprint 2a Phase 1+2+3: הוקמה תשתית Auth מלאה לאפליקציית השליחים.
פרטים נוספים ↓הסתר ↑
Sprint 2a Phase 1+2+3: הוקמה תשתית Auth מלאה לאפליקציית השליחים. types/auth.ts, token-storage.ts (SecureStore), api-client.ts (mock), auth-store.ts (Zustand). Routing guards ב-3 layouts. Phase 3: (auth)/login.tsx — מסך Login עם כרטיס לבן על רקע כחול-בהיר, Email+Password עם keyboard flow מלא (Enter → קפיצה לסיסמה → login), error banner עברית בתוך הכרטיס, KeyboardAvoidingView פר-פלטפורמה, Google button disabled. נוסף autoFocus ל-Input component.
- expo-secure-store — tokens ומשתמש נשמרים מוצפנים; נשארים בין הפעלות
- Zustand store — isLoading: true בהתחלה, restore() קורא ל-SecureStore לפני הצגת UI
- Routing guards — ניתוב אוטומטי לפי auth state ב-3 layouts
- Typed routes — router.d.ts עודכן ידנית עם routes חדשים (יוחלף ב-expo start בעתיד)
v01.07.000חדשmobileminorDesign System Primitives — 10 רכיבי UI לאפליקציית השליחים
נבנו 10 רכיבים אטומיים ב-apps/mobile/components/ui/ כבסיס ל-Design System של Shipnest Mobile.
פרטים נוספים ↓הסתר ↑
נבנו 10 רכיבים אטומיים ב-apps/mobile/components/ui/ כבסיס ל-Design System של Shipnest Mobile. כל הרכיבים עם TypeScript strict, RTL מלא, accessibility (accessibilityRole/State/Label), ו-StyleSheet מבוסס tokens מ-lib/theme.ts. בנוסף: playground מסך לבדיקה חזותית של כל הרכיבים, עם ניווט מהמסך הראשי ב-DEV mode. תוקנו באגי RTL ב-Input (textAlign hardcoded ל-right) וב-Switch (מיקום thumb hardcoded לאפליקציה עברית). הוחל Sprint 1b (Phase 1): EmptyStateCard, KPICard, NotificationCard. הוחל Sprint 1b (Phase 2): CODObligationCard, EarningsSummaryCard. הוחל Sprint 1b (Phase 3): TimelineEventCard (connecting line RTL-safe, 6 event types, isCompleted state), VisitCard (urgent strip, sequence+ETA+badge, COD badge, action buttons עם IconButton) — כל 7 cards מוכנים. הוחל Sprint 1c (Phase 1): MockStatusBar (visual mockup של status bar עם battery/signal), StandardHeader (3-column layout, back+title+rightActions, transparent mode), SearchHeader (back button + SearchInput flex, autoFocus עם setTimeout). הוחל Sprint 1c (Phase 2): ActionsHeader (title + מערך actions גמיש עם badge dots), HomeHeader (Avatar+greeting+date + segmented Driver/Admin control), TransparentHeader (position absolute, glass back button עם shadow, pill title). הוחל Sprint 1c (Phase 3 — Final): TabBar (5 slots, FAB 56×56px עם shadow בולט יוצא 16px מעל ה-bar, slot 3 ריק, badge על profile, useSafeAreaInsets לrespect home indicator).
- lib/theme.ts — כל טוקני העיצוב מ-04-tokens.json כ-TypeScript `as const` עם type inference
- lib/rtl.ts — פונקציות עזר RTL-safe: marginStart/End, absoluteEnd/Start, rtlFlip
- Button: 4 variants × 3 sizes, touch scale animation (Animated.spring 0.97), loading spinner, min 44px touch
- Input: forwardRef, animated border color 200ms, error + focus states, clear button RTL-safe
- PasswordInput: secureTextEntry toggle, textContentType=password לstability iOS keyboard
- Playground ב-app/playground.tsx — כל הרכיבים interactive, גישה מהmenu ב-__DEV__
v01.06.000חדשmobileminorהשקת apps/mobile — Scaffolding אפליקציית שליחים
הוקמה apps/mobile — אפליקציית React Native (Expo) לשליחים בתוך המונורפו.
פרטים נוספים ↓הסתר ↑
הוקמה apps/mobile — אפליקציית React Native (Expo) לשליחים בתוך המונורפו. הבסיס כולל: Expo SDK 54 עם React Native 0.81.5 ו-React 19, Expo Router v6 (file-based routing), NativeWind v4 עם design tokens מלאים מ-04-tokens.json, פונט Heebo נטען דינמית, RTL מוגדר ב-I18nManager, SplashScreen עד לטעינת הפונטים, וtypecheck עובר ללא שגיאות.
- Expo SDK 54 + React Native 0.81.5 + React 19 — stack מעודכן
- NativeWind v4 עם tokens (primary, accent, slate, success, warning, error, background, text)
- RTL force מובנה: I18nManager.forceRTL(true) + android.supportsRtl
- Expo Router v6 file-based routing — מבנה דומה ל-Next.js App Router
- מונורפו: metro.config.js עם watchFolders לpackages/, @workspace/shared בtsconfig
v01.05.002שיפורdistribution-gaps, shipments, importהערת מעקב בדף פרטי משלוח + תיקון עדכון תאריך
הערת המעקב (מפערי הפצה) מופיעה עכשיו גם בדף פרטי המשלוח: ניתן ליצור, לערוך ולמחוק את ההערה ישירות מהדף, וכל שמירה מתועדת בהיסטוריה.
פרטים נוספים ↓הסתר ↑
הערת המעקב (מפערי הפצה) מופיעה עכשיו גם בדף פרטי המשלוח: ניתן ליצור, לערוך ולמחוק את ההערה ישירות מהדף, וכל שמירה מתועדת בהיסטוריה. עמודת 'עדכון הערה' בטבלת פערי ההפצה מתרעננת אוטומטית לאחר שמירה, וה-popover ההיסטוריה טוען מחדש את הרשומות העדכניות. בנוסף, ביבוא משלוחים: שורה שחסר בה טלפון ראשי אבל קיים טלפון נוסף — הטלפון הנוסף מקודם אוטומטית לטלפון הראשי ולא נחסמת כשגויה.
v01.05.001שיפורsettings/updatesעיצוב מחדש של דף עדכונים ושיפורים
דף העדכונים עוצב מחדש עם מראה פרמיום: גרסאות מרכזיות מקבלות כרטיס hero עם glow הנפשה, blob gradients, watermark גרסה ברקע ואייקון זוהר; עדכונים משמעותיים מקבלים אקסנט עבה צבעוני בצד ימין עם gradient עדין; patches כוללים …
פרטים נוספים ↓הסתר ↑
דף העדכונים עוצב מחדש עם מראה פרמיום: גרסאות מרכזיות מקבלות כרטיס hero עם glow הנפשה, blob gradients, watermark גרסה ברקע ואייקון זוהר; עדכונים משמעותיים מקבלים אקסנט עבה צבעוני בצד ימין עם gradient עדין; patches כוללים hover state מלוטש עם scale animation על האייקון. בנוסף תוקן רוחב מלא — הוסרה הגבלת max-w-2xl.
v01.05.000חדשportal, customers, shipments, target-shabbatminorשחזור סיסמה עצמאי לפורטל הלקוחות
משתמשי הפורטל יכולים כעת לאפס את הסיסמה שלהם בעצמם.
פרטים נוספים ↓הסתר ↑
משתמשי הפורטל יכולים כעת לאפס את הסיסמה שלהם בעצמם. נוספו דפי 'שכחת סיסמה?' ו-'איפוס סיסמה' בפורטל, קישור 'שכחת סיסמה?' בדף הכניסה לפורטל, ו-API endpoints תואמים. הטוקן תקף 60 דקות. בנוסף, כשמשתמש פורטל נוצר אוטומטית מהאימייל של הלקוח — נשלח אליו אימייל הזמנה. נוסף פילטר 'סוכן' במצבת הלקוחות — ניתן לסנן לפי סוכן ספציפי או להציג רק לקוחות ללא שיוך. בטולבר בחירה מרובה של משלוחים הוסר כפתור 'העתקה בלי כתובת' — נותר רק כפתור 'העתקה' שמעתיק תמיד עם כתובת. בסנכרון מליונוויל נוסף טוסט מעקב התקדמות חי (X / סה"כ משלוחים) שמתעדכן אחרי כל batch ומוחלף בטוסט הסופי בסיום. נוספה מערכת תוויות למשלוחים — תוויות צבעוניות דינמיות לסינון וארגון ביעד שבת ובדף המשלוח הבודד.
- דף 'שכחת סיסמה?' ייעודי לפורטל הלקוחות
- קישור מהיר בדף הכניסה לפורטל
- אימייל הזמנה אוטומטי גם בעת auto-provisioning ראשוני
- פילטר סוכן במצבת לקוחות — לפי סוכן ספציפי או 'ללא שיוך'
- הסרת דשבורד פיננסי (לא פעיל); כפתור סנכרון מליונוויל הועבר לתפריט פעולות הטבלה עם אייקון ליונוויל
- טולבר בחירה מרובה עוצב מחדש — בר שורה עם כפתורי outline, ספירה וצבעי primary במקום floating dock
- עמודת סוכן בטבלת לקוחות עם עריכה אינליין — Popover + Command לבחירה/חיפוש סוכן ישירות מהתא
- מערכת תוויות: תוויות צבעוניות per-tenant עם יצירה/מחיקה מהפופאובר עצמו
- סינון לפי תוויות בדף יעד שבת — כפתורי פילטר צבעוניים עם ספירות
- הקצאת תווית בבחירה מרובה מהטולבר, ועריכה בדף המשלוח הבודד
v01.04.000שיפורimportminorיבוא משלוחים ללא הגבלת כמות + תיקון UX עריכת שורות
הוסרה ההגבלה של 500 משלוחים ביבוא — המערכת מפצלת אוטומטית לאצוות ברקע.
פרטים נוספים ↓הסתר ↑
הוסרה ההגבלה של 500 משלוחים ביבוא — המערכת מפצלת אוטומטית לאצוות ברקע. בנוסף: תוקן באג שגרם לשורה לקפוץ מהטאב 'שגויות' לטאב 'תקינות' תוך כדי הקלדה — עכשיו הטאב מתעדכן רק בעת יציאה מהתא (blur). תוקן באג במיפוי עמודות AI שגרם לאבד שורות מעבר ל-500 בקבצים גדולים — עכשיו כל השורות עוברות מיפוי. הוסרה חסימת שורות בגלל 'עיר לא מוכרת' — גילוי עיר לא מזוהה ממשיך להוצג כאזהרה חזותית (גבול כתום) אך לא מונע יבוא. תוקנו שלוש בעיות UX: תאים ריקים עם מקף מ-Excel ('-') לא מוצגים יותר כ'-' — מטופלים כריקים; עריכת הגדרות ייבוא (תאריך/דחיפות/פרשות/הערה) נפתחת בחלון קופץ ייעודי מבלי לאבד שינויים בתצוגה המקדימה; בסרגל ההגדרות מוצגות עכשיו גם פרשות יעד.
- ניתן לייבא אלפי משלוחים בפעולה אחת ללא הגבלה
- פיצול אוטומטי לאצוות ברקע — שקוף למשתמש
- שורה לא קופצת טאב תוך כדי הקלדה — רק אחרי יציאה מהתא
- מיפוי AI כעת מכסה את כל שורות הקובץ, לא רק 500 הראשונות
- שורות עם עיר לא מוכרת ניתנות לייבוא — האזהרה הכתומה עדיין מוצגת
- תאים ריקים עם מקף מ-Excel מטופלים כריקים — לא גורמים ל'-1' בעת עריכה
- עריכת הגדרות ייבוא בחלון קופץ — ללא אובדן עבודה בתצוגה המקדימה
- פרשות יעד מוצגות בסרגל ההגדרות בשלב התצוגה המקדימה
- תוקן: הערת יעד לא נשלחת יותר לליונוויל פעמיים — הפרדה נקייה בין destination_notes ל-notes
- תוקן: אצווה לא ממשיכה בשקט לאצווה הבאה אם השרת נכשל — BATCH_SIZE הוקטן ל-150 שורות ויש זיהוי timeout
- שיפור: ייבא מחדש מההיסטוריה טוען רק שורות שנכשלו (לא הכל) — כפתור מציג ספירה ואזהרה ל-timed_out
- שיפור: אחרי ייבוא מחדש מוצלח, יבוא המקורי מסומן אוטומטית עם הערת 'הושלם ע״י ייבוא חוזר' ומוצגת בירוק בהיסטוריה
- תיקון AI: טקסט שיורי בכתובת (שם משפחה, הוראות מסירה) מועבר עכשיו לשדה הערת יעד במקום להימחק
- שיפור AI: זיהוי וקיזום קידומת סוג ישוב (מושב/קיבוץ/כפר/ישוב) משם העיר לפני חיפוש התאמה
- שיפור AI: נרמול טלפון — פורמט בינלאומי (+972), מקפים/רווחים, שני טלפונים בתא
- שיפור AI: הסרת קידומת רחוב/שד' משדה הכתובת, פיצול מספר דבוק לשם הרחוב
- שיפור AI: המרת אות לטינית במספר בניין לעברית (10a→10א), ניקוי סכום COD מסמל מטבע
- שיפור: בורר תאריכים בהיסטוריית פעולות הוחלף ל-DateRangeFilter הסטנדרטי (עם פריסטים וכפתור לוח שנה); סלקט הפעולות תוקן לגובה 7 — תואם את שאר הפקדים בסרגל
- שיפור UX: טופס יצירת משימה — עיצוב מחודש עם sections, PlainFieldLabel ואייקונים; תאריך יעד מפוצל לשדות תאריך+שעה נפרדים; dropdown חיפוש ישות מעוצב כ-combobox עם border רך ו-shadow
- פערי הפצה: עמודת 'עדכון הערה' מציגה תאריך עדכון + אייקון שעון שפותח היסטוריית הערות מלאה (מה נכתב, מי ערך, מתי)
- שיפור UX: דף הייבוא מכסה עכשיו את מלוא גובה המסך — אין חלל ריק מתחת לכרטיסיות ההגדרות
- פיצ׳ר: אפשרות להגדיר כתובת מוצא (עיר / רחוב / מס׳) בהגדרות הייבוא — מועברת לליונוויל כנקודת איסוף לכל המשלוחים בפעולה
v01.03.001שיפורinbox, messagesשדרוג ממשק WhatsApp Inbox
שדרוג מקיף של דף ה-Inbox להיות דומה יותר ל-WhatsApp Web: אווטארים צבעוניים לפי האש של מספר הטלפון, מפרידי תאריכים בין הודעות, מפריד הודעות חדשות, הצגת מדיה (תמונה/אודיו/וידאו/מסמך) ישירות בבועה, textarea שמתרחב אוטומטית,…
פרטים נוספים ↓הסתר ↑
שדרוג מקיף של דף ה-Inbox להיות דומה יותר ל-WhatsApp Web: אווטארים צבעוניים לפי האש של מספר הטלפון, מפרידי תאריכים בין הודעות, מפריד הודעות חדשות, הצגת מדיה (תמונה/אודיו/וידאו/מסמך) ישירות בבועה, textarea שמתרחב אוטומטית, בורר emoji, פאנל פרטי לקוח בלחיצה על האווטאר, כפתור גלילה לתחתית עם מונה הודעות ממתינות, סינון שיחות הכל/לא נקרא, סמל סטטוס הודעה אחרונה ברשימת השיחות, עדכון כותרת הדפדפן עם מספר ההודעות שלא נקראו, והתראות דסקטופ עבור שיחות לא פעילות. בנוסף: שם הנמען נשלף אוטומטית מהמשלוח האחרון אם אין לקוח מקושר, ותווית 'שולח' מציגה את שם השולח של המשלוח בכותרת השיחה.
v01.03.000חדשportal, customersminorשליחת אימייל הזמנה אוטומטית לפורטל הלקוחות
בעת הוספת משתמש חדש לפורטל הלקוחות, המערכת שולחת אוטומטית אימייל הזמנה עם קישור ייחודי להגדרת סיסמה.
פרטים נוספים ↓הסתר ↑
בעת הוספת משתמש חדש לפורטל הלקוחות, המערכת שולחת אוטומטית אימייל הזמנה עם קישור ייחודי להגדרת סיסמה. האימייל נשלח גם בעת חידוש קישור הזמנה שפג תוקפו. הודעת ה-toast ועיצוב הדיאלוג עודכנו בהתאם.
- אימייל הזמנה אוטומטי עם קישור ייחודי ותוקף
- שליחה מחודשת בעת חידוש טוקן
- fallback ידני — הקישור ממשיך להיות מוצג ב-UI
v01.02.011שיפורmanagement, bulk-history, distribution-gapsעיצוב מחדש של דף היסטוריית פעולות — פריסת טבלה סטנדרטית
דף היסטוריית הפעולות עוצב מחדש בהתאם לדפוס הטבלאות הקיים במערכת: סרגל עליון (PageToolbar) עם פילטרים, טבלה מלאת-רוחב עם כותרת דביקה וגלילה פנימית, סרגל תחתון לנאביגציה, עמודת פעולות דביקה בקצה, ורספונסיביות מלאה.
פרטים נוספים ↓הסתר ↑
דף היסטוריית הפעולות עוצב מחדש בהתאם לדפוס הטבלאות הקיים במערכת: סרגל עליון (PageToolbar) עם פילטרים, טבלה מלאת-רוחב עם כותרת דביקה וגלילה פנימית, סרגל תחתון לנאביגציה, עמודת פעולות דביקה בקצה, ורספונסיביות מלאה. הוסרה עטיפת SettingsShell וכותרת הדף. בנוסף, נוספה עמודת הערת מעקב לטבלת פערי ההפצה — נציגי שירות יכולים לרשום הערה על כל פער (לחיצה על אייקון עיפרון פותחת popover לעריכה), ההערה נשמרת בין ימים ומוצגת לכל משתמשי הטנאנט.
v01.02.010שיפורmessages, inbox, shipments, recycle-bin, customers, distribution-gapsאינבוקס רספונסיבי למובייל
דף הצ'אט עבר לתצוגה רספונסיבית: במובייל מוצגת רשימת שיחות בלבד, ולחיצה על שיחה פותחת אותה במסך מלא עם כפתור חזרה.
פרטים נוספים ↓הסתר ↑
דף הצ'אט עבר לתצוגה רספונסיבית: במובייל מוצגת רשימת שיחות בלבד, ולחיצה על שיחה פותחת אותה במסך מלא עם כפתור חזרה. בדסקטופ השתנה הממשק בדיוק כמו קודם. בנוסף, הורחב הצגת מספר חבילות: בבר בחירת משלוחים ("X משלוחים נבחרו"), בכותרת דיאלוג משלוחי לקוח, בסל המיחזור (כותרת ובר תחתון). כמו כן, אוחד מנגנון הסנכרון מליונוויל: כל הטבלאות משתמשות כעת בסנכרון מאוחד דרך `/api/sync-shipment-status` הכולל מעקב התקדמות, מודל לטיפול במשלוחים שנמחקו מליונוויל, ניסיון חוזר לנכשלים, ודיווח על עדכוני שליח.
v01.02.009חדשmessages, inbox, shipments, picking, distribution-gaps, target-express, target-shabbatכפתור שיחה חדשה באינבוקס
נוסף כפתור + בסרגל השיחות באינבוקס המאפשר פתיחת שיחת WhatsApp חדשה עם כל מספר טלפון, ללא צורך שהלקוח ייזום קודם.
פרטים נוספים ↓הסתר ↑
נוסף כפתור + בסרגל השיחות באינבוקס המאפשר פתיחת שיחת WhatsApp חדשה עם כל מספר טלפון, ללא צורך שהלקוח ייזום קודם. בנוסף, בכל מקום שמוצג סיכום מספר משלוחים (בר תחתון של טבלאות) מוצג כעת גם סה"כ חבילות בסוגריים — למשל: 500 משלוחים (521 חבילות). עודכן בדפי: משלוחים, ליקוט, פערי הפצה, יעד אקספרס, יעד שבת.
v01.02.008שיפורbulk-operations, managementשיפור דיאלוג פרטי פעולה ב-bulk history
דיאלוג הפרטים מציג כעת ברקודים של המשלוחים המעורבים, אזור המקור (מאיזה עמוד בוצעה הפעולה), ערכים שהוחלו (metadata) לעומת ערכים קודמים (snapshot) — במקום JSON גולמי אחד.
פרטים נוספים ↓הסתר ↑
דיאלוג הפרטים מציג כעת ברקודים של המשלוחים המעורבים, אזור המקור (מאיזה עמוד בוצעה הפעולה), ערכים שהוחלו (metadata) לעומת ערכים קודמים (snapshot) — במקום JSON גולמי אחד. כל נתיבי ה-bulk מעדכנים את ה-snapshot לכלול barcode לצד שדות השינוי.
v01.02.007שיפורbulk-operations, picking, shipmentsשילוב מלא של כל נתיבי ה-bulk עם מערכת ההיסטוריה
כל פעולות ה-batch במערכת מחוברות כעת למערכת היסטוריית הפעולות: ייבוד יעד שבת, שיבוץ שליח, סימון ליקוט/ביטול ליקוט, שינוי קטגוריית ליקוט, הסרה מרשימת ליקוט, עדכון פריטי ליקוט (כולל שחזור order items מלא), שיבוץ סוכן ללקוח…
פרטים נוספים ↓הסתר ↑
כל פעולות ה-batch במערכת מחוברות כעת למערכת היסטוריית הפעולות: ייבוד יעד שבת, שיבוץ שליח, סימון ליקוט/ביטול ליקוט, שינוי קטגוריית ליקוט, הסרה מרשימת ליקוט, עדכון פריטי ליקוט (כולל שחזור order items מלא), שיבוץ סוכן ללקוח, ותשלום מרובה לעובדים יומיים. נוסף גם סוג פעולה חדש UPDATE_PICKING_ITEMS עם שחזור מלא של order items. בנוסף, שיפורי ביצועים: קריאות ה-DB לסוכן וללקוח בשיוך לקוח לסוכן מקביליות; בדיקת ייחודיות אימייל ווידוא טננט ביצירת משתמש (admin) מקביליות.
v01.02.006חדשmanagement, bulk-operationsminorהיסטוריית פעולות batch עם ביטול נקודתי
מערכת חדשה לרישום ומעקב אחר פעולות batch (פעולות על בחירה מרובה): מחיקה, שחזור, שיבוץ שליח, קביעת יעד, שינוי סטטוס ועוד.
פרטים נוספים ↓הסתר ↑
מערכת חדשה לרישום ומעקב אחר פעולות batch (פעולות על בחירה מרובה): מחיקה, שחזור, שיבוץ שליח, קביעת יעד, שינוי סטטוס ועוד. כל פעולה מוקלטת עם snapshot של המצב הקודם, ובעל החברה יכול לבטל כל פעולה בנפרד — גם אם בוצעו פעולות נוספות אחריה. הדף נגיש מקבוצת ניהול בסידבר (OWNER בלבד). תוקן: המרת driverId ל-number בביטול ASSIGN_DRIVER (גרם לכשל בילד).
- רישום אוטומטי של כל פעולת batch עם snapshot מלא
- ביטול נקודתי — מבטל פעולה ספציפית ללא תלות בסדר הכרונולוגי
- דף היסטוריה עם סינון לפי סוג פעולה וטווח תאריכים
- דיאלוג אישור לפני ביטול עם הסבר על השפעת הדריסה
- הרשאות נפרדות: VIEW ו-REVERT — OWNER בלבד
v01.02.005שיפורnavigation, settingsיומן פעילות הועבר לקבוצת ניהול בסידבר
קישור יומן הפעילות עבר מקבוצת הגדרות לקבוצת ניהול בסידבר — נגיש לבעלים בלבד.
פרטים נוספים ↓הסתר ↑
קישור יומן הפעילות עבר מקבוצת הגדרות לקבוצת ניהול בסידבר — נגיש לבעלים בלבד. זאת בהמשך להעברת הלוגים הטכניים לקונטרול פאנל, כחלק מסידור מחדש של אזורי ניהול ומעקב. בנוסף, שולבו ייעולי ביצועים נוספים: analytics נהגים — טעינת שמות הנהגים ופירוט הביקורים מקביליים (Promise.all); דשבורד סוכן — שאילתות לידים מקביליות לטעינת מזהי לקוחות; הסרת console.log אוטומטית בבילד פרודקשן.
v01.02.003שיפורadmin, debug-logs, securityלוגים טכניים הועברו לקונטרול פאנל
דף הלוגים הטכניים (debug logs) הועבר מממשק הטננט לקונטרול פאנל, תחת /admin/debug-logs.
פרטים נוספים ↓הסתר ↑
דף הלוגים הטכניים (debug logs) הועבר מממשק הטננט לקונטרול פאנל, תחת /admin/debug-logs. כמו כן, נוסף אבטחה ל-API: קריאות GET ו-DELETE ל-/api/debug-log מוגנות כעת ברמת PLATFORM_ADMIN/SYSTEM_DEVELOPER בלבד. POST נשאר פתוח לכתיבה פנימית. הדף הוסר מהסידבר של הטננט.
v01.02.002שיפורshipments-import, attendance, webhooksמדריך עמודות Excel — דיאלוג מקובץ ונקי
רשימת העמודות הנתמכות בייבוא עוצבה מחדש: במקום רשימה שטוחה ומבולבלת, הרשימה עברה לדיאלוג ייעודי מאחורי כפתור 'עמודות נתמכות'.
פרטים נוספים ↓הסתר ↑
רשימת העמודות הנתמכות בייבוא עוצבה מחדש: במקום רשימה שטוחה ומבולבלת, הרשימה עברה לדיאלוג ייעודי מאחורי כפתור 'עמודות נתמכות'. הדיאלוג מקבץ את השדות לפי קטגוריות (פרטי נמען, כתובת, פרטי הזמנה, הערות), מציג תגי חובה/אופציונלי, תיאור קצר לכל שדה, ושמות חלופיים בגופן mono. בנוסף, שופרו ביצועי מסד הנתונים: שאילתות validation במחלקות הפכו למקביליות (Promise.all), מאחסן החגים בלוח השנה עבר לשאילתת batch אחת במקום N+1, ו-webhook dispatch כעת טוען subscription בשאילתה הראשונה ומייתר re-fetch לכל delivery.
v01.02.001תיקוןsettingsתיקון דף עדכונים — שגיאת forwardRef
דף עדכונים ושיפורים קרס בשל העברת רכיב Lucide (forwardRef) כ-prop מ-Server Component ל-Client Component.
פרטים נוספים ↓הסתר ↑
דף עדכונים ושיפורים קרס בשל העברת רכיב Lucide (forwardRef) כ-prop מ-Server Component ל-Client Component. תוקן עם הוספת 'use client'.
v01.02.000חדשshipments-importminorשיפור מקיף להיסטוריית יבוא משלוחים
הוספת אפשרות הורדת קובץ Excel מהיסטוריית יבוא ישן (כולל תיקוני שגיאות שבוצעו לפני הייבוא), כפתור ייבוא מחדש שטוען את הקובץ כולו חזרה לאשף הייבוא, ופילטרים מהירים (חיפוש חופשי, טווח תאריכים, סטטוס).
פרטים נוספים ↓הסתר ↑
הוספת אפשרות הורדת קובץ Excel מהיסטוריית יבוא ישן (כולל תיקוני שגיאות שבוצעו לפני הייבוא), כפתור ייבוא מחדש שטוען את הקובץ כולו חזרה לאשף הייבוא, ופילטרים מהירים (חיפוש חופשי, טווח תאריכים, סטטוס). עיצוב מחודש של פאנל ההיסטוריה — כרטיסיות ברורות עם נתוני סטטיסטיקה ופעולות ייעודיות לכל ייבוא.
- הורדת Excel מתוך היסטוריית ייבוא — כולל תיקוני AI שבוצעו לפני הייבוא
- כפתור 'ייבא שוב' שמטעין את שורות הייבוא הישן חזרה לאשף
- פילטרים: חיפוש חופשי, טווח תאריכים (היום/7/30 ימים/הכל), סטטוס
- עיצוב מחודש: כרטיסיות עם מידע ברור ופעולות נגישות
- תמיכה מלאה בפורטל לקוחות
v01.01.015תיקוןtasksתיקון חלון המשימות במובייל
חלון המשימות הצידי (AdminTaskBellButton) יצא מגבולות המסך במכשירים ניידים בשל רוחב קבוע של 460px.
פרטים נוספים ↓הסתר ↑
חלון המשימות הצידי (AdminTaskBellButton) יצא מגבולות המסך במכשירים ניידים בשל רוחב קבוע של 460px. תוקן ל-w-full max-w-115 — רספונסיבי מלא עד מקסימום 460px.
v01.01.014שיפורcasual-tripsשיפורים במסך נסיעות מזדמנות
תוקנה כתובת שגויה בדף פרטי הנסיעה לביקורי איסוף; badge סוג הביקור עכשיו בעברית; הוסף כפתור 'העתק לינק' ו'שלח WhatsApp' בדף הפרטים; ניתן להוסיף משלוחים לנסיעה פעילה; תוקנה ניווט עמודים מעבר לעמוד 5; ב-BUSINESS_PICKUP כתוב…
פרטים נוספים ↓הסתר ↑
תוקנה כתובת שגויה בדף פרטי הנסיעה לביקורי איסוף; badge סוג הביקור עכשיו בעברית; הוסף כפתור 'העתק לינק' ו'שלח WhatsApp' בדף הפרטים; ניתן להוסיף משלוחים לנסיעה פעילה; תוקנה ניווט עמודים מעבר לעמוד 5; ב-BUSINESS_PICKUP כתובת יעד כעת אופציונלית.
v01.01.013חדשcasual-tripsיצירת משלוח חדש מתוך מסך הנסיעות הזמניות
נוסף מצב 'משלוח חדש' שמאפשר ליצור משלוח ב-Lionwheel וטיול בפעולה אחת, ישירות ממסך הנסיעות הזמניות.
v01.01.012תיקוןuiתיקון לחיצה על Combobox בתוך Drawer
תוקנה בעיה שגרמה ל-Combobox לא להגיב ללחיצות כאשר הוא רץ בתוך Vaul Drawer.
v01.01.011תיקוןcasual-tripsהצגת כתובת איסוף בעמוד השליח
תוקנה בעיה שגרמה לכתובת האיסוף להיעלם בעמוד השליח בנסיעות זמניות.
v01.01.010תיקוןdriversשחזור נהג זמני בחיפוש שיבוץ
תוקנה בעיה שהסתירה נהגים זמניים מרשימת השיבוץ בעקבות כפילות שנפתרה ברמת ה-DB.
v01.01.009חדשmapsכרטיס מידע על מסמני מסלול במפה
לחיצה על מסמן מסלול בעמוד הנהג פותחת כרטיס מידע מפורט עם פרטי העצירה.
v01.01.008שיפורtasksminorעיצוב מחדש מלא של פאנל המשימות
פאנל המשימות עוצב מחדש מהיסוד: כותרת גרדיאנט, מסנני תאריך ועדיפות, רשת 8px עקבית, פאנל רחב יותר ומצב ריק משופר.
פרטים נוספים ↓הסתר ↑
פאנל המשימות עוצב מחדש מהיסוד: כותרת גרדיאנט, מסנני תאריך ועדיפות, רשת 8px עקבית, פאנל רחב יותר ומצב ריק משופר.
- כותרת גרדיאנט עם מידע על המשימה הפתוחה
- סינון לפי תאריך יעד ורמת עדיפות
- עיצוב עקבי על בסיס רשת 8px
- מצב ריק מעוצב עם הנחיה לפעולה
v01.01.007שיפורalertsעיצוב מחדש של כרטיס שגיאת מיון
פריסת כרטיס שגיאת המיון עוצבה מחדש לנראות ובהירות טובות יותר.
v01.01.006ייעולcleanupייעול Dry-Run בניקוי — ספירה מיידית מה-DB
ה-dry-run של כלי הניקוי עובר כעת ספירה מיידית מה-DB ללא קריאות ל-Lionwheel, ובלי timeout.
v01.01.005חדשdistribution-gapsסף פערי חלוקה ברמת Tenant
נוספה אפשרות להגדיר ברמת ה-Tenant ערכי ברירת מחדל לפערי חלוקה ולסף קריטי.
v01.01.004תיקוןimportשיפור תיקון כתובות AI
תיקון AI לכתובות בודק כעת גם שדה כתובת לעיר מוסתרת, שולח את כל כינויי הישוב ומנרמל שם קנוני בעת יישום.
v01.01.003חדשcod-trackingאירועי COD משוקפים להיסטוריית משלוח
אירועי ביקורת של מעקב גוביינא משוקפים כעת להיסטוריית פעולות המשלוח.
v01.01.002תיקוןimportפאנל פעילות אחרונה ממלא גובה זמין
תוקנה בעיה שגרמה לפאנל הפעילות האחרונה שלא לגדול לאורך המלא בזמן ייבוא.
v01.01.001שיפורmapsאיחוד עיצוב מסמנים ושיפור UX פופאפ במפה
עיצוב המסמנים במפה אוחד ו-UX הפופאפ שופר לחוויה עקבית יותר.
v01.01.000חדשplatformmajorהשקת Shipnest — מעבר לתשתית ייצור מלאה
המערכת עברה ריברנד מלא מ-send-whatsapp ל-Shipnest ועלתה לאוויר בדומיין shipnest.io.
פרטים נוספים ↓הסתר ↑
המערכת עברה ריברנד מלא מ-send-whatsapp ל-Shipnest ועלתה לאוויר בדומיין shipnest.io. הועברה כל התשתית ל-Vercel, Namecheap ו-Cloudflare. מהגרסה הזו כל ה-backend רץ כ-Next.js API routes בלבד — ה-NestJS הישן הוסר לחלוטין.
- דומיין ייצור: shipnest.io (Namecheap + Cloudflare + Vercel)
- מעבר מלא ל-Next.js API routes — ללא NestJS
- ריברנד מלא: לוגו, שם, צבעים
- Multi-tenancy יציב עם הצפנת סודות AES-256-GCM
- Public REST API עם bearer token ו-rate limiting
- אינטגרציות: Lionwheel, Summit, WhatsApp Cloud API