• דף הבית
    • אינדקס קישורים
    • פוסטים אחרונים
    • משתמשים
    • חיפוש בהגדרות המתקדמות
    • חיפוש גוגל בפורום
    • ניהול המערכת
    • ניהול המערכת - שרת private
    • הרשמה
    • התחברות
    1. דף הבית
    2. BEN ZION
    3. פוסטים
    B
    מחובר
    • פרופיל
    • עוקב אחרי 2
    • עוקבים 1
    • נושאים 82
    • פוסטים 609
    • קבוצות 0

    פוסטים

    פוסטים אחרונים הגבוה ביותר שנוי במחלוקת
    • RE: חסימת שיחות מעל 10 ספרות למערכת

      @מערכוני שזה לא מס' חסום כל מס' טלפון מזוהה יכנס אני חושב שמס אם סיומת חריגה נקרא לא מזוהה אבל אין לי איך לבדוק אם יש לך איך לבדוק תעדכן

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: חסימת שיחות מעל 10 ספרות למערכת

      @מערכוני ההגדרה הזאת גורמת שכל טלפון יוכל להכנס אם הוא מזוהה

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: חסימת שיחות מעל 10 ספרות למערכת

      @מערכוני אני חושב אולי שאם יהיה כניסה לפי ID שכל טלפון מזוהה נכנס אז אולי לא יוכל תבדוק

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: חסימת שיחות מעל 10 ספרות למערכת

      @מערכוני אתה רוצה שיוכלו לחייג רק ממספר נייח ??

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: הפניה מ SIP למחשב ללא יחידות עזרה!

      @לימוד-בתורת-מרן אתה משתמש בימות המשיח או iptel?

      פורסם בטלפונים ומערכות SIP
      B
      BEN ZION
    • RE: פילטר הפניה עם API

      @אביי-ורבא אתה משתמש כשלוחה? או כהטמעה בכל מודול?
      לפי התיעוד GOTO זה רק כמודול בפני עצמו,
      כהטמעה ניתן להחזיר רק

      OK = ממשיך מיד לשלוחה בצורה רגילה

      NO = יוצא מהשלוחה עם הודעה M1102 אין לכם הרשאת גישה לתיקיה זו

      Out = יוצא מהשלוחה ללא הודעה

      פורסם בפורום מפתחים API
      B
      BEN ZION
    • RE: עזרה דחופה - “מודול סליקה של נדרים פלוס לא שולח POST ל-URL”

      @יחחיאל תבקש מנדרים לשלוח וובהוק לURL שלך חוץ מזה יכול להיות שהאתר שלך חוסם קבל POST

      פורסם בפורום מפתחים API
      B
      BEN ZION
    • RE: שיחות פעילה 📱📲☎️📞למרות שלא.. עזרה !

      @לימוד-בתורת-מרן נראה לי שכבר כתבו על זה שהוא לא מדוייק ומשאיר לפעמים שיחות אבל החברת תקשורת שלך לא קשורה לימות המשיח רק מה שחייגת תחוייב

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: הודעת מערכת M1103 בקול הרובוט

      @לימוד-בתורת-מרן שלח לי
      @גמיל.כום

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: הודעת מערכת M1103 בקול הרובוט

      @לימוד-בתורת-מרן זה טעות, תיצור לבד בפנקס רשימות

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: הודעת מערכת M1103 בקול הרובוט

      @לימוד-בתורת-מרן זה לא אמור להגימר בסיומת ini צריך ככה M1103.tts

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: הודעת מערכת M1103 בקול הרובוט

      @לימוד-בתורת-מרן לכאורה אין סיבה לתקלה איזה הודעה זו? אני ינסה אצלי לבדוק

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: הודעת מערכת M1103 בקול הרובוט

      @לימוד-בתורת-מרן את מה להקריא כתבת ב INI או TTS? בדקת שאין קובץ שמע באותו שם?

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: השנה ההתרמה שלכם תראה אחרת!!!

      @בוס הקוד אתה שם אותו בשרת שלך מבקש מנדרים לשלוח וובהוק לURL והקוד מעביר למערכת של ימות עשיתי את זה אם בינה תתן לה את זה ותגיד לה להחליף מהערות ל קטגוריה או מה שאתה רוצה

      פורסם בעזרה הדדית למשתמשים מתקדמים
      B
      BEN ZION
    • RE: פוסט מסודר לנותני שירות בניית מערכות בתשלום

      @m0548520998 הפוסט הזה נועד לנושא ספציפי ניתן לפתוח נושא חדש עיין פה למידע על צינתוקים

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: הפניה לקו אחר

      @מושקה בפשטות אין דרך רק אם API אולי הבעיה בהפניה ממערכת שאין זיהוי של המערכת שהפנתה זה פנימי בתוך ימות ממילא אתה לא יכול להגדיר ניתוב לפי איזה מס' הפנה

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: השנה ההתרמה שלכם תראה אחרת!!!

      @אa מי שרוצה כתבתי קוד PHP שמקבל וובהוק מנדרים ומוסיף למערכת בהערות צריך לכתוב את שם המתרים

      <?php
      // הגדרות API
      $token = "{token}"; 
      $api_url = "https://www.call2all.co.il/ym/api/";
      
      // נתיבים
      $path_names = 'ivr2:Points/EnterIDValName.ini';
      $path_total = 'ivr2:Points/points_total.ymgr';
      $path_log   = 'ivr2:Points/manual_log.ini';
      
      // קבצי דיבוג מקומיים בשרת ה-PHP
      $debug_file = 'debug_webhook.log';
      $unassigned_csv = 'unassigned_donations.csv';
      
      // 1. קבלת הנתונים ושמירה לדיבוג ראשוני
      $json_data = file_get_contents('php://input');
      $data = json_decode($json_data, true);
      
      // רישום כל כניסה לקובץ דיבוג כדי שלא יאבד כלום
      $timestamp_log = date("Y-m-d H:i:s");
      file_put_contents($debug_file, "[$timestamp_log] Raw Data: " . $json_data . PHP_EOL, FILE_APPEND);
      
      if (!$data) die("No data received");
      
      $comment_name = trim($data['Comments'] ?? '');
      $amount = floatval($data['Amount'] ?? 0);
      
      function call_yemot($method, $path, $token, $contents = null) {
          global $api_url;
          $url = $api_url . $method . "?token=" . $token . "&what=" . $path;
          if ($contents !== null) $url .= "&contents=" . urlencode($contents);
          $res = file_get_contents($url);
          return json_decode($res, true);
      }
      
      // 2. חיפוש גמיש (Fuzzy Matching)
      $fundraiser_id = null;
      $best_score = -1;
      $res_names = call_yemot('GetTextFile', $path_names, $token);
      
      if (isset($res_names['contents']) && !empty($comment_name)) {
          $lines = explode("\n", $res_names['contents']);
          foreach ($lines as $line) {
              $parts = explode('=', $line);
              if (count($parts) === 2) {
                  $current_id = trim($parts[0]);
                  $current_name = trim($parts[1]);
      
                  // חישוב דמיון
                  similar_text($comment_name, $current_name, $percent);
                  
                  if ($percent > $best_score) {
                      $best_score = $percent;
                      $fundraiser_id = $current_id;
                  }
              }
          }
      }
      
      // 3. ביצוע עדכון או שמירה ל-CSV במקרה של כישלון
      // הורדתי את הסף ל-50% בגלל תארים כמו "הרב" ו"שליט"א"
      if ($fundraiser_id && $best_score > 50) {
          
          // א. עדכון YMGR
          $res_total = call_yemot('GetTextFile', $path_total, $token);
          $t_lines = explode("\n", trim($res_total['contents'] ?? ""));
          $found = false;
          foreach ($t_lines as &$line) {
              if (strpos($line, "EnterId#$fundraiser_id") !== false) {
                  $found = true;
                  preg_match('/PointsTotalAll#([\d.]+)/', $line, $matches);
                  $new_val = (isset($matches[1]) ? floatval($matches[1]) : 0) + $amount;
                  $line = preg_replace('/PointsTotalAll#[\d.]+/', "PointsTotalAll#$new_val", $line);
                  $line = preg_replace('/PointsTotal#[\d.]+/', "PointsTotal#$new_val", $line);
              }
          }
          if (!$found) $t_lines[] = "EnterId#{$fundraiser_id}%PointsTotalAll#{$amount}%PointsTotal#{$amount}";
          call_yemot('UploadTextFile', $path_total, $token, implode("\n", $t_lines));
      
          // ב. רישום ללוג ה-HTML
          $res_log = call_yemot('GetTextFile', $path_log, $token);
          $time_ms = round(microtime(true) * 1000);
          $time_hi = date("H:i");
          $new_entry = "{$time_ms}|{$fundraiser_id}|{$amount}|{$time_hi}";
          call_yemot('UploadTextFile', $path_log, $token, $new_entry . "\n" . ($res_log['contents'] ?? ""));
      
          file_put_contents($debug_file, "[$timestamp_log] SUCCESS: Matched $comment_name to ID $fundraiser_id ($best_score%)" . PHP_EOL, FILE_APPEND);
          echo "Success";
      
      } else {
          // שמירה ל-CSV עבור תרומות שלא זוהו
          $is_new = !file_exists($unassigned_csv);
          $fp = fopen($unassigned_csv, 'a');
          if ($is_new) {
              fputs($fp, chr(0xEF) . chr(0xBB) . chr(0xBF)); // BOM לעברית
              fputcsv($fp, ['תאריך', 'שם מהערה', 'סכום', 'טלפון', 'אחוז התאמה הכי קרוב']);
          }
          fputcsv($fp, [$timestamp_log, $comment_name, $amount, $data['Phone'] ?? '', $best_score . "%"]);
          fclose($fp);
      
          file_put_contents($debug_file, "[$timestamp_log] FAILED: No match for $comment_name (Best: $best_score%)" . PHP_EOL, FILE_APPEND);
          echo "Saved to CSV";
      }
      

      מי שרוצה שידרגתי את שתי הקודים כך שיש גם יעד אישי לכל מתרים
      מסך ניהול

      <!DOCTYPE html>
      <html lang="he" dir="rtl">
      <head>
      <meta charset="UTF-8">
      <title>מנהל קמפיין - Points Sync</title>
      <style>
      :root { --primary: #0ea5e9; --success: #22c55e; --bg: #0f172a; --card: #1e293b; --border: #334155; --gold: #f59e0b; }
      body { background: var(--bg); color: #f1f5f9; font-family: system-ui, sans-serif; margin: 0; padding: 20px; text-align: right; }
      .manual-entry-box { max-width: 600px; margin: 50px auto; background: var(--card); padding: 30px; border-radius: 20px; box-shadow: 0 10px 25px rgba(0,0,0,0.3); border: 1px solid var(--border); }
      h1 { text-align: center; color: var(--primary); }
      label { display: block; margin-top: 15px; font-weight: bold; }
      input { width: 100%; padding: 15px; margin: 10px 0; border-radius: 10px; border: 1px solid var(--border); background: #0f172a; color: white; font-size: 1.2rem; box-sizing: border-box; }
      .main-btn { background: var(--success); color: white; border: none; padding: 15px; border-radius: 10px; cursor: pointer; font-weight: bold; width: 100%; font-size: 1.1rem; margin-top: 20px; transition: 0.3s; }
      .main-btn:hover { filter: brightness(1.1); transform: translateY(-2px); }
      .settings-trigger { position: fixed; top: 20px; left: 20px; background: #334155; color: white; border: none; padding: 12px 20px; border-radius: 50px; cursor: pointer; font-weight: bold; display: flex; align-items: center; gap: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
      .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); z-index: 1000; backdrop-filter: blur(5px); }
      .modal-content { background: var(--card); width: 90%; max-width: 800px; margin: 40px auto; border-radius: 20px; padding: 25px; border: 1px solid var(--border); position: relative; max-height: 85vh; overflow-y: auto; }
      .close-btn { position: absolute; top: 15px; right: 20px; font-size: 1.5rem; cursor: pointer; }
      .tabs { display: flex; gap: 5px; border-bottom: 2px solid var(--border); margin-bottom: 20px; }
      .tab-btn { background: none; border: none; color: #8b949e; padding: 10px 15px; cursor: pointer; font-size: 0.95rem; }
      .tab-btn.active { color: var(--primary); border-bottom: 2px solid var(--primary); font-weight: bold; }
      .tab-pane { display: none; }
      .tab-pane.active { display: block; }
      .log-list { background: #0f172a; padding: 10px; border-radius: 8px; max-height: 350px; overflow-y: auto; }
      .log-item { display: flex; justify-content: space-between; padding: 12px; border-bottom: 1px solid var(--border); align-items: center; }
      .log-item label { display: flex; align-items: center; cursor: pointer; width: 100%; gap: 15px; }
      .badge { font-size: 0.75rem; padding: 3px 8px; border-radius: 5px; color: white; font-weight: bold; }
      .badge-manual { background: var(--primary); }
      .badge-phone { background: var(--success); }
      .status { margin-top: 15px; font-size: 0.9rem; text-align: center; font-weight: bold; }
      </style>
      </head>
      <body>
      
      <button class="settings-trigger" onclick="openModal()"><span>⚙️</span> הגדרות קמפיין</button>
      
      <div class="manual-entry-box">
      <h1>💰 הזנת תרומה ידנית</h1>
      <label>מספר אישי של המתרים:</label>
      <input type="number" id="manualId" placeholder="למשל 215" autofocus>
      <label>סכום התרומה (₪):</label>
      <input type="number" id="manualAmount" placeholder="0.00">
      <button class="main-btn" onclick="executeManualDonation()">✅ אשר והוסף למערכת</button>
      <div id="mainStatus" class="status"></div>
      </div>
      
      <div id="settingsModal" class="modal">
      <div class="modal-content">
      <span class="close-btn" onclick="closeModal()">✖️</span>
      <h2 style="border-bottom: 1px solid var(--border); padding-bottom: 10px;">⚙️ ניהול והגדרות</h2>
      <div class="tabs">
      <button class="tab-btn active" onclick="switchTab(event, 'tabNames')">👥 שמות ויעדים</button>
      <button class="tab-btn" onclick="switchTab(event, 'tabGoal')">📈 יעד ותאריך</button>
      <button class="tab-btn" onclick="switchTab(event, 'tabTotals')">📊 עריכת סכומים</button>
      <button class="tab-btn" onclick="switchTab(event, 'tabLogs')">🗑️ מחיקת לוג</button>
      </div>
      
          <div id="tabNames" class="tab-pane active">
              <div style="display:flex; gap:10px;">
                  <input type="text" id="editId" placeholder="מספר אישי">
                  <button onclick="findUser()" style="width:100px; background:var(--primary); border:none; border-radius:8px; color:white; cursor:pointer;">חפש</button>
              </div>
              <input type="text" id="editName" placeholder="שם המתרים">
              <input type="number" id="editGoal" placeholder="יעד אישי (₪) - אופציונלי">
              <button class="main-btn" style="background:var(--primary)" onclick="saveUser()">שמור פרטים ויעד</button>
          </div>
       
          <div id="tabGoal" class="tab-pane">
              <label>יעד הקמפיין הכולל (₪):</label><input type="number" id="goalVal">
              <label>תאריך ושעת סיום:</label><input type="datetime-local" id="dateVal">
              <button class="main-btn" onclick="saveConfig()">🔄 עדכן יעד ותאריך</button>
              <hr style="border:0; border-top:1px solid var(--border); margin:25px 0;">
              <label style="color:var(--gold)">מפתח אבטחה (Token) API:</label>
              <input type="password" id="tokenInput" placeholder="הכנס טוקן חדש">
              <button class="main-btn" style="background:#6366f1" onclick="updateToken()">🔄 עדכן מפתח Token</button>
          </div>
       
          <div id="tabTotals" class="tab-pane"><div id="totalsList" class="log-list">טוען נתונים...</div></div>
          <div id="tabLogs" class="tab-pane">
              <div id="logsList" class="log-list">טוען לוג פעולות מהשרת...</div>
              <button class="main-btn" style="background:#ef4444" onclick="deleteLogs()">❌ מחק פעולות וסנכרן שרת</button>
          </div>
          <div id="modalStatus" class="status"></div>
      </div>
      </div>
      
      <script>
      let CURRENT_TOKEN = localStorage.getItem('campaign_token') || 'YOUR_TOKEN_HERE';
      let nameMap = {};
      let goalMap = {};
      
      // נתיבים בשרת - הכל בתיקיית Points
      const PATH_TOTAL = 'ivr2:Points/points_total.ymgr';
      const PATH_PHONE_LOG = 'ivr2:Points/points_log.2026-02.ymgr';
      const PATH_MANUAL_LOG = 'ivr2:Points/manual_log.ini';
      const PATH_CONFIG = 'ivr2:Points/config.ini';
      const PATH_NAMES = 'ivr2:Points/EnterIDValName.ini';
      const PATH_GOALS = 'ivr2:Points/EnterIDGoal.ini';
       
      document.getElementById('tokenInput').value = CURRENT_TOKEN;
       
      function updateToken() {
          const newToken = document.getElementById('tokenInput').value.trim();
          if(!newToken) return alert("נא להזין טוקן");
          CURRENT_TOKEN = newToken;
          localStorage.setItem('campaign_token', newToken);
          alert("הטוקן עודכן במחשב זה!");
          location.reload();
      }
       
      function openModal() { document.getElementById('settingsModal').style.display = 'block'; }
      function closeModal() { document.getElementById('settingsModal').style.display = 'none'; }
       
      async function callApi(cmd, path, content = "") {
          let url = `https://www.call2all.co.il/ym/api/${cmd}?token=${CURRENT_TOKEN}&what=${path}`;
          if(content) url += `&contents=${encodeURIComponent(content)}`;
          return fetch(url).then(r => r.json());
      }
       
      async function switchTab(e, id) {
          document.querySelectorAll('.tab-pane, .tab-btn').forEach(el => el.classList.remove('active'));
          document.getElementById(id).classList.add('active');
          e.currentTarget.classList.add('active');
          await fetchNames();
          if(id === 'tabGoal') loadCurrentConfig();
          if(id === 'tabTotals') fetchTotals();
          if(id === 'tabLogs') fetchLogs();
      }
       
      async function fetchNames() {
          const [resNames, resGoals] = await Promise.all([
              callApi('GetTextFile', PATH_NAMES),
              callApi('GetTextFile', PATH_GOALS)
          ]);
          
          nameMap = {}; 
          goalMap = {};
          
          if (resNames.contents) {
              resNames.contents.split(/[\r\n]+/).forEach(line => {
                  const parts = line.split('=');
                  if (parts.length === 2) nameMap[parts[0].trim()] = parts[1].trim();
              });
          }
          if (resGoals.contents) {
              resGoals.contents.split(/[\r\n]+/).forEach(line => {
                  const parts = line.split('=');
                  if (parts.length === 2) goalMap[parts[0].trim()] = parseFloat(parts[1].trim());
              });
          }
      }
      
      async function findUser() {
          const id = document.getElementById('editId').value;
          if (!id) return alert("נא להזין מספר אישי");
          await fetchNames();
          document.getElementById('editName').value = nameMap[id] || "";
          document.getElementById('editGoal').value = goalMap[id] || "";
      }
      
      async function saveUser() {
          const id = document.getElementById('editId').value;
          const name = document.getElementById('editName').value;
          const goal = document.getElementById('editGoal').value;
          
          if (!id) return alert("חובה להזין מספר אישי");
      
          let [resNames, resGoals] = await Promise.all([
              callApi('GetTextFile', PATH_NAMES),
              callApi('GetTextFile', PATH_GOALS)
          ]);
      
          let linesNames = (resNames.contents || "").split('\n').filter(l => l.trim() && !l.startsWith(`${id}=`));
          if (name) linesNames.push(`${id}=${name}`);
      
          let linesGoals = (resGoals.contents || "").split('\n').filter(l => l.trim() && !l.startsWith(`${id}=`));
          if (goal) linesGoals.push(`${id}=${goal}`);
      
          await Promise.all([
              callApi('UploadTextFile', PATH_NAMES, linesNames.join('\n')),
              callApi('UploadTextFile', PATH_GOALS, linesGoals.join('\n'))
          ]);
      
          alert("פרטי המתרים והיעד האישי עודכנו בהצלחה!");
          await fetchNames();
      }
       
      async function executeManualDonation() {
          const id = document.getElementById('manualId').value;
          const amt = parseFloat(document.getElementById('manualAmount').value);
          if(!id || !amt) return alert("מלא מספר וסכום");
          document.getElementById('mainStatus').innerText = "⏳ מעדכן שרת...";
       
          let resT = await callApi('GetTextFile', PATH_TOTAL);
          let tLines = (resT.contents || "").trim().split('\n');
          let found = false;
          let updatedT = tLines.map(l => {
              if(l.includes(`EnterId#${id}`)) {
                  found = true;
                  let old = parseFloat((l.match(/PointsTotalAll#([\d.]+)/) || [0,0])[1]);
                  let sum = old + amt;
                  return l.replace(/PointsTotalAll#[\d.]+/, `PointsTotalAll#${sum}`).replace(/PointsTotal#[\d.]+/, `PointsTotal#${sum}`);
              }
              return l;
          });
          if(!found) updatedT.push(`EnterId#${id}%PointsTotalAll#${amt}%PointsTotal#${amt}`);
          
          let resL = await callApi('GetTextFile', PATH_MANUAL_LOG);
          let currentManualLog = resL.contents || "";
          const timeStr = new Date().toLocaleTimeString('he-IL', {hour:'2-digit', minute:'2-digit'});
          const newEntry = `${Date.now()}|${id}|${amt}|${timeStr}`;
          const updatedManualLog = newEntry + "\n" + currentManualLog;
       
          await Promise.all([
              callApi('UploadTextFile', PATH_TOTAL, updatedT.join('\n')),
              callApi('UploadTextFile', PATH_MANUAL_LOG, updatedManualLog)
          ]);
       
          document.getElementById('mainStatus').innerText = "✅ נרשם וסונכרן לשרת!";
          document.getElementById('manualAmount').value = "";
      }
       
      async function fetchLogs() {
          let [resPhone, resManual] = await Promise.all([
              callApi('GetTextFile', PATH_PHONE_LOG),
              callApi('GetTextFile', PATH_MANUAL_LOG)
          ]);
       
          let allEntries = [];
          const todayStr = new Date().toISOString().split('T')[0];
       
          if (resPhone.contents) {
              resPhone.contents.trim().split('\n').forEach(l => {
                  let id = (l.match(/id#(\d+)/) || [])[1];
                  let pts = (l.match(/Points#(\d+)/) || [])[1];
                  let timeM = (l.match(/(\d{2}:\d{2})/) || [""])[0];
                  if (id) allEntries.push({id, pts, time: timeM, type: 'phone', fullLine: l, ts: timeM ? new Date(`${todayStr}T${timeM}:00`).getTime() : 0});
              });
          }
       
          if (resManual.contents) {
              resManual.contents.trim().split('\n').forEach(l => {
                  let [ts, id, amt, time] = l.split('|');
                  if (id) allEntries.push({id, pts: amt, time, type: 'manual', fullLine: l, ts: parseInt(ts)});
              });
          }
       
          allEntries.sort((a, b) => b.ts - a.ts);
       
          let html = allEntries.map(entry => {
              let name = nameMap[entry.id] || entry.id;
              return `<div class="log-item"><label><input type="checkbox" class="log-cb" data-id="${entry.id}" data-amt="${entry.pts}" data-type="${entry.type}" data-line="${entry.fullLine}"><span><span class="badge ${entry.type === 'manual' ? 'badge-manual' : 'badge-phone'}">${entry.type === 'manual' ? 'ידני' : 'טלפון'}</span> [${entry.time}] <b>${name}</b> - ₪${entry.pts}</span></label></div>`;
          }).join('');
          document.getElementById('logsList').innerHTML = html || "אין היסטוריה.";
      }
       
      async function deleteLogs() {
          const checkboxes = document.querySelectorAll('.log-cb:checked');
          if (checkboxes.length === 0) return alert("בחר פעולות");
          if (!confirm("זה ימחק את השורות מכל המחשבים ויקזז סכומים. המשך?")) return;
       
          document.getElementById('modalStatus').innerText = "⏳ מסנכרן שרת...";
          let [resP, resM, resT] = await Promise.all([
              callApi('GetTextFile', PATH_PHONE_LOG),
              callApi('GetTextFile', PATH_MANUAL_LOG),
              callApi('GetTextFile', PATH_TOTAL)
          ]);
       
          let phoneLines = resP.contents ? resP.contents.trim().split('\n') : [];
          let manualLines = resM.contents ? resM.contents.trim().split('\n') : [];
          let totalLines = resT.contents ? resT.contents.trim().split('\n') : [];
       
          checkboxes.forEach(cb => {
              const id = cb.getAttribute('data-id'), amt = parseFloat(cb.getAttribute('data-amt')), type = cb.getAttribute('data-type'), line = cb.getAttribute('data-line');
              if (type === 'phone') phoneLines = phoneLines.filter(l => l !== line);
              else manualLines = manualLines.filter(l => l !== line);
       
              totalLines = totalLines.map(tL => {
                  if(tL.includes(`EnterId#${id}`)) {
                      let old = parseFloat((tL.match(/PointsTotalAll#([\d.]+)/) || [0,0])[1]);
                      let sum = Math.max(0, old - amt);
                      return tL.replace(/PointsTotalAll#[\d.]+/, `PointsTotalAll#${sum}`).replace(/PointsTotal#[\d.]+/, `PointsTotal#${sum}`);
                  } return tL;
              });
          });
       
          await Promise.all([
              callApi('UploadTextFile', PATH_PHONE_LOG, phoneLines.join('\n')),
              callApi('UploadTextFile', PATH_MANUAL_LOG, manualLines.join('\n')),
              callApi('UploadTextFile', PATH_TOTAL, totalLines.join('\n'))
          ]);
          
          document.getElementById('modalStatus').innerText = "✅ הסנכרון הושלם בכל המחשבים!";
          fetchLogs();
      }
       
      async function loadCurrentConfig() {
          const res = await callApi('GetTextFile', PATH_CONFIG);
          if(res.contents) {
              const goal = (res.contents.match(/goal=(.*)/) || [])[1];
              const date = (res.contents.match(/date=(.*)/) || [])[1];
              if(goal) document.getElementById('goalVal').value = goal;
              if(date) document.getElementById('dateVal').value = date;
          }
      }
      async function saveConfig() {
          const content = `goal=${document.getElementById('goalVal').value}\ndate=${document.getElementById('dateVal').value}`;
          await callApi('UploadTextFile', PATH_CONFIG, content);
          alert("עודכן בשרת!");
      }
      async function fetchTotals() {
          let res = await callApi('GetTextFile', PATH_TOTAL);
          if(!res.contents) return;
          let html = res.contents.trim().split('\n').map(l => {
              let id = (l.match(/EnterId#(\d+)/) || [])[1];
              let val = (l.match(/PointsTotalAll#([\d.]+)/) || [])[1];
              if(!id) return '';
              let name = nameMap[id] || id;
              return `<div class="log-item"><span><b>${name}</b> (${id})</span><div style="display:flex; gap:5px;"><input type="number" id="inp-${id}" value="${val}" style="width:110px;"><button onclick="updateTotal('${id}')" style="background:var(--primary); color:white; border:none; padding:8px 12px; border-radius:8px; cursor:pointer;">עדכן</button></div></div>`;
          }).join('');
          document.getElementById('totalsList').innerHTML = html;
      }
      async function updateTotal(id) {
          const newVal = document.getElementById(`inp-${id}`).value;
          let res = await callApi('GetTextFile', PATH_TOTAL);
          let updated = res.contents.trim().split('\n').map(l => l.includes(`EnterId#${id}`) ? l.replace(/PointsTotalAll#[\d.]+/, `PointsTotalAll#${newVal}`).replace(/PointsTotal#[\d.]+/, `PointsTotal#${newVal}`) : l);
          await callApi('UploadTextFile', PATH_TOTAL, updated.join('\n'));
          alert("סכום עודכן בשרת!");
      }
      </script>
      </body>
      </html>
      

      מסך התרמה

      <!DOCTYPE html>
      <html lang="he" dir="rtl">
      <head>
      <meta charset="UTF-8">
      <title>מערכת התרמה LIVE - Points Sync</title>
      <style>
      :root { --accent: #0ea5e9; --gold: #fbbf24; --bg: #020617; }
      body { background: var(--bg); color: #f8fafc; font-family: system-ui, sans-serif; margin: 0; padding: 10px; overflow: hidden; }
      .container { display: grid; grid-template-columns: 320px 1fr 320px; gap: 15px; height: 95vh; }
      .card { background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255,255,255,0.1); border-radius: 20px; padding: 15px; backdrop-filter: blur(10px); display: flex; flex-direction: column; overflow: hidden; }
      .center-card { display: flex; flex-direction: column; justify-content: space-between; align-items: center; text-align: center; padding: 40px 20px; }
      h2 { font-size: 1.3rem; border-bottom: 2px solid var(--accent); padding-bottom: 8px; margin: 0 0 10px 0; color: white; text-align: center; }
      
          .countdown-timer { display: flex; gap: 15px; margin-bottom: 20px; }
          .time-unit { background: rgba(14, 165, 233, 0.2); padding: 10px 15px; border-radius: 12px; border: 1px solid var(--accent); min-width: 60px; }
          .time-num { display: block; font-size: 2rem; font-weight: bold; color: white; }
          .time-label { font-size: 0.8rem; opacity: 0.7; }
       
          .total-amount { font-size: 8rem; font-weight: 900; color: var(--accent); text-shadow: 0 0 30px rgba(14, 165, 233, 0.4); margin: 10px 0; line-height: 1; }
          
          .progress-wrapper { width: 90%; }
          .progress-bg { background: #1e293b; height: 40px; border-radius: 50px; border: 2px solid #334155; overflow: hidden; position: relative; }
          .progress-fill { height: 100%; background: linear-gradient(90deg, #0ea5e9, #22d3ee); width: 0%; transition: width 2s; }
          
          .list-box { flex-grow: 1; overflow: hidden; display: flex; flex-direction: column; padding-right: 5px; }
          .item { display: flex; flex-direction: column; align-items: stretch; padding: 10px; background: rgba(255,255,255,0.05); margin-bottom: 8px; border-radius: 10px; border-right: 4px solid var(--accent); flex-shrink: 0; transition: all 0.5s; }
          .item-header { display: flex; justify-content: space-between; align-items: center; }
          .item-info { display: flex; flex-direction: column; }
          .item-name { font-weight: bold; font-size: 1.1rem; display: flex; align-items: center; gap: 6px; }
          .item-time { font-size: 0.8rem; color: #94a3b8; font-weight: bold; }
          .item-val { font-weight: 900; color: var(--gold); font-size: 1.3rem; }
          
          .badge { font-size: 0.6rem; padding: 2px 5px; border-radius: 4px; font-weight: bold; }
          .badge-manual { background: #0ea5e9; color: white; }
          .badge-phone { background: #22c55e; color: white; }
       
          .live-dot { height: 10px; width: 10px; background: #ef4444; border-radius: 50%; display: inline-block; margin-left: 8px; animation: pulse 1s infinite; }
          @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
      
          /* עיצוב לאנימציה של הגעה ליעד */
          @keyframes goldGlow {
              0% { box-shadow: 0 0 5px rgba(251, 191, 36, 0.2); border-color: rgba(251, 191, 36, 0.5); }
              50% { box-shadow: 0 0 20px rgba(251, 191, 36, 0.8); border-color: rgba(251, 191, 36, 1); }
              100% { box-shadow: 0 0 5px rgba(251, 191, 36, 0.2); border-color: rgba(251, 191, 36, 0.5); }
          }
          .goal-reached {
              animation: goldGlow 2s infinite;
              background: rgba(251, 191, 36, 0.1) !important;
              border-right-color: var(--gold) !important;
          }
          .goal-badge {
              background: var(--gold); color: black; font-size: 0.75rem; padding: 2px 8px; border-radius: 12px; font-weight: bold; margin-right: 10px; display: inline-block;
          }
      </style>
      </head>
      <body>
      
      <div class="container">
      <div class="card">
      <h2>🏆 מובילים</h2>
      <div id="leaderboard" class="list-box" style="overflow-y: auto;"></div>
      </div>
      
      <div class="card center-card">
          <div>
              <div style="margin-bottom: 10px; font-size: 1.2rem; font-weight: bold;"><span class="live-dot"></span>הקמפיין מסתיים בעוד:</div>
              <div id="countdown" class="countdown-timer">
                  <div class="time-unit"><span id="days" class="time-num">00</span><span class="time-label">ימים</span></div>
                  <div class="time-unit"><span id="hours" class="time-num">00</span><span class="time-label">שעות</span></div>
                  <div class="time-unit"><span id="minutes" class="time-num">00</span><span class="time-label">דקות</span></div>
                  <div class="time-unit"><span id="seconds" class="time-num">00</span><span class="time-label">שניות</span></div>
              </div>
          </div>
       
          <div>
              <h1 style="margin:0; font-size: 1.8rem; opacity: 0.9;">סך הכל נאסף:</h1>
              <div id="main-total" class="total-amount">₪0</div>
          </div>
       
          <div class="progress-wrapper">
              <div class="progress-bg"><div id="progress-bar" class="progress-fill"></div></div>
              <div id="percent-label" style="font-size: 3rem; color: var(--gold); font-weight: bold; margin-top: 10px;">0%</div>
              <div id="goal-text" style="font-size: 1.5rem; opacity: 0.6;">מחשב נתונים...</div>
          </div>
      </div>
       
      <div class="card">
          <h2>🔔 תרומות אחרונות</h2>
          <div id="recent-log" class="list-box" style="overflow-y: auto;"></div>
      </div>
      </div>
      
      <script>
      // הגדרות שלוחה - הכל תחת תיקיית Points
      const TOKEN = 'WU1BUElL.apik_MmtjfW7MhNRZGw4h--R54Q.zPUwopxRh5JxRpUutkWFKUhyDWtLfvYwWKQ30PTuXZw';
      const PATH_TOTAL = 'ivr2:Points/points_total.ymgr';
      const PATH_PHONE_LOG = 'ivr2:Points/points_log.2026-02.ymgr';
      const PATH_MANUAL_LOG = 'ivr2:Points/manual_log.ini';
      const PATH_CONFIG = 'ivr2:Points/config.ini';
      const PATH_NAMES = 'ivr2:Points/EnterIDValName.ini';
      const PATH_GOALS = 'ivr2:Points/EnterIDGoal.ini';
      
      let GOAL = 500000;
      let DEADLINE = new Date(); 
      let nameMap = {};
      let goalMap = {};
       
      function updateCountdown() {
          const now = new Date();
          const diff = DEADLINE - now;
          if (diff <= 0) {
              document.querySelectorAll('.time-num').forEach(el => el.innerText = "00");
              return;
          }
          document.getElementById('days').innerText = String(Math.floor(diff / (1000 * 60 * 60 * 24))).padStart(2, '0');
          document.getElementById('hours').innerText = String(Math.floor((diff / (1000 * 60 * 60)) % 24)).padStart(2, '0');
          document.getElementById('minutes').innerText = String(Math.floor((diff / 1000 / 60) % 60)).padStart(2, '0');
          document.getElementById('seconds').innerText = String(Math.floor((diff / 1000) % 60)).padStart(2, '0');
      }
       
      async function update() {
          try {
              const [resTotal, resLogPhone, resNames, resConfig, resLogManual, resGoals] = await Promise.all([
                  fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_TOTAL}`).then(r => r.json()),
                  fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_PHONE_LOG}`).then(r => r.json()),
                  fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_NAMES}`).then(r => r.json()),
                  fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_CONFIG}`).then(r => r.json()),
                  fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_MANUAL_LOG}`).then(r => r.json()),
                  fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_GOALS}`).then(r => r.json())
              ]);
       
              if (resConfig.contents) {
                  const g = resConfig.contents.match(/goal=(.*)/);
                  const d = resConfig.contents.match(/date=(.*)/);
                  if (g) {
                      GOAL = parseFloat(g[1]);
                      document.getElementById('goal-text').innerText = `מתוך יעד של ${GOAL.toLocaleString()} ₪`;
                  }
                  if (d) DEADLINE = new Date(d[1]);
              }
       
              if (resNames.contents) {
                  resNames.contents.split(/[\r\n]+/).forEach(line => {
                      const parts = line.split('=');
                      if (parts.length === 2) nameMap[parts[0].trim()] = parts[1].trim();
                  });
              }
      
              if (resGoals.contents) {
                  goalMap = {};
                  resGoals.contents.split(/[\r\n]+/).forEach(line => {
                      const parts = line.split('=');
                      if (parts.length === 2) goalMap[parts[0].trim()] = parseFloat(parts[1].trim());
                  });
              }
       
              if (resTotal.contents) {
                  const lines = resTotal.contents.trim().split(/[\r\n]+/);
                  let totalSum = 0; let users = [];
                  lines.forEach(l => {
                      const idMatch = l.match(/EnterId#(\d+)/);
                      const scoreMatch = l.match(/PointsTotalAll#([\d.]+)/);
                      if (idMatch && scoreMatch) {
                          const val = parseFloat(scoreMatch[1]);
                          totalSum += val;
                          users.push({id: idMatch[1], val: val});
                      }
                  });
                  document.getElementById('main-total').innerText = '₪' + totalSum.toLocaleString();
                  document.getElementById('progress-bar').style.width = Math.min((totalSum/GOAL)*100, 100) + '%';
                  document.getElementById('percent-label').innerText = ((totalSum/GOAL)*100).toFixed(1) + '%';
                  
                  users.sort((a,b) => b.val - a.val);
                  
                  document.getElementById('leaderboard').innerHTML = users.map((u,i) => {
                      const personalGoal = goalMap[u.id];
                      let goalHtml = '';
                      let reachedClass = '';
                      let goalBadgeHtml = '';
                      
                      if (personalGoal && personalGoal > 0) {
                          const rawPct = (u.val / personalGoal) * 100;
                          const pct = Math.min(rawPct, 100).toFixed(0);
                          
                          if (rawPct >= 100) {
                              reachedClass = 'goal-reached';
                              goalBadgeHtml = `<span class="goal-badge">הגיע ליעד! 👑</span>`;
                          }
      
                          goalHtml = `
                              <div style="font-size: 0.8rem; color: #94a3b8; display: flex; align-items: center; gap: 8px; margin-top: 8px;">
                                  <div style="background: rgba(255,255,255,0.1); height: 6px; flex-grow: 1; border-radius: 5px; overflow: hidden;">
                                      <div style="background: var(--gold); height: 100%; width: ${pct}%; transition: width 1s;"></div>
                                  </div>
                                  <span style="min-width: 40px; text-align: left; font-weight: bold; color: ${rawPct >= 100 ? 'var(--gold)' : 'inherit'}">${pct}%</span>
                              </div>
                          `;
                      }
      
                      return `
                          <div class="item ${reachedClass}">
                              <div class="item-header">
                                  <span class="item-name"><b>${i+1}.</b> ${nameMap[u.id] || u.id} ${goalBadgeHtml}</span>
                                  <span style="color:var(--accent); font-weight:bold;">₪${u.val.toLocaleString()}</span>
                              </div>
                              ${goalHtml}
                          </div>
                      `;
                  }).join('');
              }
       
              let allItems = [];
              const todayStr = new Date().toISOString().split('T')[0];
       
              if (resLogPhone.contents) {
                  resLogPhone.contents.trim().split(/[\r\n]+/).forEach((line, idx) => {
                      const idM = line.match(/id#(\d+)/);
                      const ptM = line.match(/Points#(\d+)/);
                      const timeM = line.match(/(\d{2}:\d{2})/);
                      if (idM && ptM) {
                          let ts = timeM ? new Date(`${todayStr}T${timeM[1]}:00`).getTime() : (Date.now() - 500000);
                          allItems.push({ id: idM[1], amount: ptM[1], type: 'phone', timestamp: ts, timeStr: timeM ? timeM[1] : "--:--" });
                      }
                  });
              }
       
              if (resLogManual.contents) {
                  resLogManual.contents.trim().split('\n').forEach(l => {
                      let [ts, id, amt, time] = l.split('|');
                      if (id) allItems.push({ id, amount: amt, type: 'manual', timestamp: parseInt(ts), timeStr: time });
                  });
              }
       
              allItems.sort((a, b) => b.timestamp - a.timestamp);
       
              document.getElementById('recent-log').innerHTML = allItems.map(item => `
                  <div class="item" style="flex-direction: row; justify-content: space-between; align-items: center;">
                      <div class="item-info">
                          <span class="item-name">
                              <span class="badge ${item.type === 'manual' ? 'badge-manual' : 'badge-phone'}">${item.type === 'manual' ? 'ידני' : 'טלפון'}</span>
                              ${nameMap[item.id] || 'מתרים ' + item.id}
                          </span>
                          <span class="item-time">${item.timeStr}</span>
                      </div>
                      <span class="item-val">₪${parseFloat(item.amount).toLocaleString()}</span>
                  </div>
              `).join('');
       
          } catch (e) { console.error("Update Error:", e); }
      }
       
      setInterval(updateCountdown, 1000);
      setInterval(update, 5000);
      updateCountdown();
      update();
      </script>
      </body>
      </html>
      

      קרדיט ל @אa על הפיתוח המועיל

      פורסם בעזרה הדדית למשתמשים מתקדמים
      B
      BEN ZION
    • RE: הקשת 2 ספרות

      @יעקב-1 אצלי בהגדרות השלוחה מוגדר ככה זה עובר אוטומטי

      api_000=date,no,,2,1,Number,yes,yes,,,3,Ok,null,,no
      
      
      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION
    • RE: חיבור sip trunk אפשרי?

      @מחפש כתב בחיבור sip trunk אפשרי?:

      לreetelai

      מה זה השירות הזה?
      אם זה סוג של חייגן SIP תפתח חשבון ויש לך שם כתובת שרת סימסה ושם משתמש
      צילום מסך 2026-02-24 104851.png

      פורסם בטלפונים ומערכות SIP
      B
      BEN ZION
    • RE: הפניה לקו אחר

      @מושקה הקו האחר הוא קו ספציפי?

      פורסם בשאלות ועזרה הדדית
      B
      BEN ZION