Subversion Repositories SmartDukaan

Rev

Rev 37775 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 37775 Rev 37864
Line 2342... Line 2342...
2342
        Loading…
2342
        Loading…
2343
      </div>
2343
      </div>
2344
    </div>
2344
    </div>
2345
  </div>
2345
  </div>
2346
 
2346
 
2347
  <!-- Partner Billing Count -->
2347
  <!-- Partner Billing Count — unchanged, always current month MTD -->
2348
  <div class="sectionlabel">Partner Billing Count <span
2348
  <div class="sectionlabel">Partner Billing Count <span
2349
          style="color:var(--soft);font-weight:600;text-transform:none;letter-spacing:0;margin-left:6px">(Targeted partners only &middot; bucketed by MTD ₹)</span>
2349
          style="color:var(--soft);font-weight:600;text-transform:none;letter-spacing:0;margin-left:6px">(Targeted partners only &middot; bucketed by MTD ₹)</span>
2350
  </div>
2350
  </div>
2351
  <div class="card">
2351
  <div class="card">
2352
    <div class="card-hd">
2352
    <div class="card-hd">
Line 2363... Line 2363...
2363
        Loading&hellip;
2363
        Loading&hellip;
2364
      </div>
2364
      </div>
2365
    </div>
2365
    </div>
2366
  </div>
2366
  </div>
2367
 
2367
 
2368
  <!-- RBM Performance Dashboard (MTD) — extracted from /indent/today_po_rbm without any backend change -->
2368
  <!-- RBM Performance Dashboard — JSON-driven, supports historical months via /rbm-drr/performance?month=YYYY-MM -->
2369
  <div class="sectionlabel">RBM Performance Dashboard (MTD)</div>
2369
  <div class="sectionlabel">RBM Performance Dashboard</div>
2370
  <div class="card">
2370
  <div class="card">
2371
    <div class="card-hd">
2371
    <div class="card-hd">
2372
      <div>
2372
      <div>
2373
        <h2>Composite MTD Ranking</h2>
2373
        <h2>Composite MTD Ranking</h2>
2374
        <p class="desc">Rank of RBMs by weighted score across Talk Time (10%) + MTD Achievement (55%) + Aging (2%) +
2374
        <p class="desc">Rank of RBMs by weighted score across Talk Time (10%) + MTD Achievement (55%) + Aging (2%) +
2375
          &gt;1L Partners (29%) + Rating (2%) + Partners Rated (2%).</p>
2375
          &gt;1L Partners (29%) + Rating (2%) + Partners Rated (2%).
-
 
2376
          <span style="color:var(--soft)"
-
 
2377
                title="Aging denominator uses today's warehouse aging snapshot — for past months aging% is approximate.">Aging denominator is a live snapshot.</span>
-
 
2378
        </p>
-
 
2379
      </div>
-
 
2380
      <div style="display:flex;align-items:center;gap:10px">
-
 
2381
        <select id="rdrrMonthPicker" class="ctl" style="min-width:170px;height:30px;padding:4px 10px"
-
 
2382
                title="Pick a month to view that month's ranking"></select>
-
 
2383
        <span class="badge-period" id="rdrrPerfMonth">MTD</span>
2376
      </div>
2384
      </div>
2377
      <span class="badge-period" id="rdrrPerfMonth">MTD</span>
-
 
2378
    </div>
2385
    </div>
2379
    <div id="rdrrPerfWrap">
2386
    <div id="rdrrPerfWrap">
2380
      <div class="loading">
2387
      <div class="loading">
2381
        <div class="spinner"></div>
2388
        <div class="spinner"></div>
2382
        Loading&hellip;
2389
        Loading&hellip;
Line 3552... Line 3559...
3552
              .replace(/"/g, "&quot;").replace(/'/g, "&#39;");
3559
              .replace(/"/g, "&quot;").replace(/'/g, "&#39;");
3553
    }
3560
    }
3554
 
3561
 
3555
    $("#rdrrPmCategory").on("change", loadPurchaseMilestones);
3562
    $("#rdrrPmCategory").on("change", loadPurchaseMilestones);
3556
 
3563
 
3557
    // ------------------------- RBM Performance Dashboard (MTD) -------------------------
3564
    // ------------------------- Month picker + RBM Performance Dashboard -------------------------
3558
    // No dedicated backend endpoint exists — the perf-dashboard table is only rendered
3565
    // The Composite MTD Ranking card now reads /rbm-drr/performance?month=YYYY-MM so historical
-
 
3566
    // months can be viewed. Partner Billing Count re-fetches /rbm-drr/extras?month=YYYY-MM.
3559
    // inline in /indent/today_po_rbm. We fetch that page and extract just the table.
3567
    // Aging/Billing extras aging bits are unaffected by the month picker — they stay driven by
-
 
3568
    // the top-of-page date range.
-
 
3569
 
-
 
3570
    function fmtSeconds(sec) {
-
 
3571
      sec = Math.max(0, Math.round(Number(sec) || 0));
-
 
3572
      var h = Math.floor(sec / 3600);
-
 
3573
      var m = Math.floor((sec % 3600) / 60);
-
 
3574
      if (h > 0) return h + "h " + m + "m";
-
 
3575
      return m + "m";
-
 
3576
    }
-
 
3577
 
-
 
3578
    function pctCell(pct) {
-
 
3579
      var p = Number(pct) || 0;
-
 
3580
      return p.toFixed(1) + "%";
-
 
3581
    }
-
 
3582
 
-
 
3583
    function renderPerformance(data) {
-
 
3584
      var rows = data.rows || [];
-
 
3585
      $("#rdrrPerfMonth").text(data.monthLabel || 'MTD');
-
 
3586
      if (rows.length === 0) {
-
 
3587
        $("#rdrrPerfWrap").html('<div class="empty"><div class="ei">📊</div>No performance dashboard data for this month.</div>');
-
 
3588
        return;
-
 
3589
      }
-
 
3590
      var html = ['<div style="overflow-x:auto"><table class="xtable" id="rdrrPerfTable"><thead><tr>',
-
 
3591
        '<th style="width:48px">Rank</th>',
-
 
3592
        '<th>RBM</th>',
-
 
3593
        '<th class="num">Partners</th>',
-
 
3594
        '<th class="num" title="Talk time / expected (10%)">Talk Time<br><small>(10%)</small></th>',
-
 
3595
        '<th class="num" title="MTD achieved / monthly target (55%)">MTD Achievement<br><small>(55%)</small></th>',
-
 
3596
        '<th class="num" title="Aging sold / warehouse aging stock. Denominator is a live snapshot (2%).">15-Day Aging<br><small>(2%)</small></th>',
-
 
3597
        '<th class="num" title="Partners who crossed ₹1L this month (29%)">&gt;1L Partners<br><small>(29%)</small></th>',
-
 
3598
        '<th class="num" title="Average partner rating (2%)">Avg Rating<br><small>(2%)</small></th>',
-
 
3599
        '<th class="num" title="Partners who rated / total partners (2%)">Partners Rated<br><small>(2%)</small></th>',
-
 
3600
        '<th class="num g-total">Score</th>',
-
 
3601
        '</tr></thead><tbody>'];
-
 
3602
      rows.forEach(function (r) {
-
 
3603
        var rankCell;
-
 
3604
        if (r.rank === 1) rankCell = '<img src="/resources/images/king.png" style="width:28px" title="Rank 1">';
-
 
3605
        else if (r.rank === 2) rankCell = '<img src="/resources/images/trophy-cup.png" style="width:24px" title="Rank 2">';
-
 
3606
        else if (r.rank === 3) rankCell = '<img src="/resources/images/bronze-medal.png" style="width:24px" title="Rank 3">';
-
 
3607
        else rankCell = String(r.rank);
-
 
3608
        html.push('<tr>' +
-
 
3609
                '<td class="num">' + rankCell + '</td>' +
-
 
3610
                '<td class="rbm-nm">' + escapeHtml(r.rbmName || '-') + '</td>' +
-
 
3611
                '<td class="num">' + (Number(r.partnerCount) || 0) + '</td>' +
-
 
3612
                '<td class="num">' + fmtSeconds(r.talkSeconds) + '<br><small style="color:var(--soft)">' + pctCell(r.talkPct) + '</small></td>' +
-
 
3613
                '<td class="num">' + pctCell(r.drrAchvPct) + '</td>' +
-
 
3614
                '<td class="num">' + formatIndian(r.agingUnitsSold) + '<br><small style="color:var(--soft)">' + pctCell(r.agingPct) + '</small></td>' +
-
 
3615
                '<td class="num">' + (Number(r.above1LPartnerCount) || 0) + '<br><small style="color:var(--soft)">' + pctCell(r.above1LPct) + '</small></td>' +
3560
    // Trade-off: heavier request (server re-runs full page prep). Consider adding a
3616
                '<td class="num">' + (Number(r.partnerRating) || 0).toFixed(2) + '</td>' +
3561
    // /rbm-drr/performance fragment endpoint later if this becomes a hot path.
3617
                '<td class="num">' + (Number(r.ratingPartnerCount) || 0) + '</td>' +
-
 
3618
                '<td class="num g-total">' + (Number(r.compositeScore) || 0).toFixed(1) + '</td>' +
-
 
3619
                '</tr>');
-
 
3620
      });
-
 
3621
      html.push('</tbody></table></div>');
-
 
3622
      $("#rdrrPerfWrap").html(html.join(""));
-
 
3623
    }
-
 
3624
 
3562
    function loadPerformanceDashboard() {
3625
    function loadPerformance(monthKey) {
3563
      $("#rdrrPerfWrap").html('<div class="loading"><div class="spinner"></div>Loading&hellip;</div>');
3626
      $("#rdrrPerfWrap").html('<div class="loading"><div class="spinner"></div>Loading&hellip;</div>');
-
 
3627
      var qs = monthKey ? ("?month=" + encodeURIComponent(monthKey)) : "";
-
 
3628
      fetch("/rbm-drr/performance" + qs, {credentials: "same-origin"})
3564
      $.ajax({
3629
              .then(function (r) {
-
 
3630
                return r.json().then(function (b) {
3565
        url: "/indent/today_po_rbm",
3631
                  return {ok: r.ok, body: b};
3566
        type: "GET",
3632
                });
3567
        dataType: "html",
3633
              })
3568
        success: function (fullHtml) {
3634
              .then(function (res) {
3569
          var doc = new DOMParser().parseFromString(fullHtml, "text/html");
3635
                if (!res.ok) {
-
 
3636
                  $("#rdrrPerfWrap").html('<div class="empty">' + escapeHtml(res.body && res.body.error ? res.body.error : "Failed to load.") + '</div>');
-
 
3637
                  return;
-
 
3638
                }
3570
          var tbl = doc.querySelector("#performance-dashboard-table");
3639
                renderPerformance(res.body);
3571
          if (!tbl) {
3640
              })
-
 
3641
              .catch(function (e) {
3572
            $("#rdrrPerfWrap").html('<div class="empty"><div class="ei">📊</div>No performance dashboard data available yet.</div>');
3642
                $("#rdrrPerfWrap").html('<div class="empty">Failed to load: ' + (e && e.message ? e.message : "network error") + '</div>');
3573
            return;
3643
              });
3574
          }
3644
    }
-
 
3645
 
3575
          // Fix any relative image paths (e.g. king.png / trophy-cup.png) to be root-relative.
3646
    // Note: variable is named `sel` without the leading dollar on purpose.
3576
          tbl.querySelectorAll("img").forEach(function (im) {
3647
    // Velocity would parse a leading-dollar name as a template reference and
3577
            var src = im.getAttribute("src") || "";
3648
    // choke on the embedded strings in the body.
-
 
3649
    function populateMonthPicker() {
3578
            if (src.indexOf("resources/") !== -1 && src.charAt(0) !== "/") {
3650
      var sel = $("#rdrrMonthPicker");
3579
              im.setAttribute("src", "/" + src.replace(/^\.\.\/+/, ""));
3651
      if (sel.length === 0 || sel.data("populated")) return;
3580
            }
3652
      var now = new Date();
3581
          });
3653
      var opts = [];
-
 
3654
      for (var i = 0; i < 6; i++) {
3582
          $("#rdrrPerfWrap").empty().append(tbl);
3655
        var d = new Date(now.getFullYear(), now.getMonth() - i, 1);
3583
        },
3656
        var y = d.getFullYear();
-
 
3657
        var m = String(d.getMonth() + 1).padStart(2, "0");
3584
        error: function () {
3658
        var key = y + "-" + m;
-
 
3659
        var label = d.toLocaleString("en-US", {month: "long", year: "numeric"}) + (i === 0 ? " (current)" : "");
3585
          $("#rdrrPerfWrap").html('<div class="empty">Failed to load performance dashboard.</div>');
3660
        opts.push('<option value="' + key + '">' + label + '</option>');
3586
        }
3661
      }
-
 
3662
      sel.html(opts.join(""));
-
 
3663
      sel.data("populated", true);
-
 
3664
      sel.on("change", function () {
-
 
3665
        loadPerformance($(this).val());
3587
      });
3666
      });
3588
    }
3667
    }
3589
 
3668
 
3590
    // ------------------------- RBM Call Target iframe -------------------------
3669
    // ------------------------- RBM Call Target iframe -------------------------
3591
    // The /indent/rbm_call_target endpoint returns a Velocity FRAGMENT (no <html>,
3670
    // The /indent/rbm_call_target endpoint returns a Velocity FRAGMENT (no <html>,
Line 3860... Line 3939...
3860
      }
3939
      }
3861
    });
3940
    });
3862
 
3941
 
3863
    // initial load
3942
    // initial load
3864
    loadFilterOptions();
3943
    loadFilterOptions();
-
 
3944
    populateMonthPicker();
3865
    load();
3945
    load();
3866
    loadPurchaseMilestones();
3946
    loadPurchaseMilestones();
3867
    loadPerformanceDashboard();
3947
    loadPerformance($("#rdrrMonthPicker").val() || null);
3868
    loadCallTargetIframe();
3948
    loadCallTargetIframe();
3869
  })();
3949
  })();
3870
</script>
3950
</script>
3871
</body>
3951
</body>
3872
</html>
3952
</html>