lokesh341 commited on
Commit
3d4b58a
·
verified ·
1 Parent(s): dadf90e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -213
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, request, Response, jsonify, render_template_string
2
  from pydantic import BaseModel
3
  from reportlab.lib.pagesizes import letter
4
  from reportlab.pdfgen import canvas
@@ -6,7 +6,6 @@ import base64
6
  import os
7
  import logging
8
  import traceback
9
- import html # For escaping special characters
10
  from datetime import datetime
11
  from simple_salesforce import Salesforce
12
 
@@ -241,227 +240,44 @@ def get_dashboard():
241
 
242
  # Sort vendor logs by final score for leaderboard
243
  sorted_logs = sorted(vendor_logs, key=lambda x: x['scores']['finalScore'], reverse=True)
244
- top_logs = sorted_logs[:5] # Top 5 for leaderboard
245
  top_performing_logs = sorted_logs[:4] # Top 4 for "Top Performing Vendors" section
246
- alert_logs = [log for log in vendor_logs if determine_alert_flag(log['scores']['finalScore'], vendor_logs)]
247
 
248
- # HTML content for the dashboard
249
- html_content = """
250
- <!DOCTYPE html>
251
- <html>
252
- <head>
253
- <title>Subcontractor Performance Score App</title>
254
- <style>
255
- body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f7fa; }
256
- h1, h2 { color: #333; }
257
- .container { max-width: 1200px; margin: 0 auto; }
258
- .summary-cards { display: flex; gap: 20px; margin-bottom: 20px; }
259
- .card { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); flex: 1; text-align: center; }
260
- .card h3 { margin: 0 0 10px; color: #555; }
261
- .card p { margin: 0; font-size: 24px; color: #333; }
262
- .leaderboard, .alerts, .top-performers, .reports { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px; }
263
- table { width: 100%; border-collapse: collapse; }
264
- th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
265
- th { background-color: #f2f2f2; }
266
- .status-good { background: #e6f4ea; color: #2e7d32; padding: 5px 10px; border-radius: 12px; display: inline-block; }
267
- .status-alert { background: #fff3e0; color: #ef6c00; padding: 5px 10px; border-radius: 12px; display: inline-block; }
268
- .trend-up { color: green; }
269
- .trend-down { color: red; }
270
- .trend-flat { color: gray; }
271
- .score-circle { display: inline-block; width: 40px; height: 40px; line-height: 40px; text-align: center; border-radius: 50%; background: #e0e0e0; margin-right: 5px; }
272
- .reports-section { display: flex; gap: 20px; }
273
- .reports-section > div { flex: 1; }
274
- .checkbox-label { margin-right: 20px; }
275
- .btn { background: #1976d2; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; }
276
- .btn:hover { background: #1565c0; }
277
- </style>
278
- </head>
279
- <body>
280
- <div class="container">
281
- <h1>Vendor Performance Dashboard</h1>
282
- <p>Monitor and manage subcontractor performance across projects</p>
283
-
284
- <!-- Summary Cards -->
285
- <div class="summary-cards">
286
- <div class="card">
287
- <h3>Total Vendors</h3>
288
- <p>{total_vendors}</p>
289
- <small>+2 in last month</small>
290
- </div>
291
- <div class="card">
292
- <h3>Performance Alerts</h3>
293
- <p>{performance_alerts}</p>
294
- <small>{percent_alerts}% of vendors</small>
295
- </div>
296
- <div class="card">
297
- <h3>Top Performers</h3>
298
- <p>{top_performers}</p>
299
- <small>{percent_top}% of vendors</small>
300
- </div>
301
- <div class="card">
302
- <h3>Improving Vendors</h3>
303
- <p>{improving_vendors}</p>
304
- <small>{percent_improving}% of vendors</small>
305
- </div>
306
- </div>
307
 
308
- <!-- Leaderboard -->
309
- <div class="leaderboard">
310
- <h2>Vendor Leaderboard</h2>
311
- <p>Top performing subcontractors this month</p>
312
- <table>
313
- <tr>
314
- <th>Rank</th>
315
- <th>Vendor</th>
316
- <th>Score</th>
317
- <th>Trend</th>
318
- <th>Status</th>
319
- </tr>
320
- """.format(
321
  total_vendors=total_vendors,
322
  performance_alerts=performance_alerts,
323
  percent_alerts=round(performance_alerts/total_vendors*100, 1) if total_vendors else 0,
324
  top_performers=top_performers,
325
  percent_top=round(top_performers/total_vendors*100, 1) if total_vendors else 0,
326
  improving_vendors=improving_vendors,
327
- percent_improving=round(improving_vendors/total_vendors*100, 1) if total_vendors else 0
 
 
 
 
 
328
  )
329
-
330
- for idx, log in enumerate(top_logs, 1):
331
- scores = log['scores']
332
- alert_flag = determine_alert_flag(scores['finalScore'], vendor_logs)
333
- trend = "trend-up" if scores['finalScore'] >= 90 else "trend-down" if scores['finalScore'] < 70 else "trend-flat"
334
- status_class = "status-good" if not alert_flag else "status-alert"
335
- status_text = "Good" if not alert_flag else "Alert"
336
- vendor_name = html.escape(log['vendorLogName'])
337
- html_content += f"""
338
- <tr>
339
- <td>#{idx}</td>
340
- <td>{vendor_name}</td>
341
- <td>{scores['finalScore']}</td>
342
- <td class="{trend}">{"↗" if trend == "trend-up" else "↘" if trend == "trend-down" else "—"}</td>
343
- <td><span class="{status_class}">{status_text}</span></td>
344
- </tr>
345
- """
346
-
347
- html_content += """
348
- </table>
349
- </div>
350
-
351
- <!-- Performance Alerts -->
352
- <div class="alerts">
353
- <h2>Performance Alerts</h2>
354
- <p>Vendors requiring attention</p>
355
- """
356
-
357
- if alert_logs:
358
- for log in alert_logs[:3]: # Show up to 3 alerts
359
- scores = log['scores']
360
- vendor_name = html.escape(log['vendorLogName'])
361
- html_content += f"""
362
- <div style="margin-bottom: 10px;">
363
- <span style="color: #ef6c00;">⚠️ {vendor_name}</span> - Overall: {scores['finalScore']}
364
- <br>Quality: {scores['qualityScore']} | Timeliness: {scores['timelinessScore']}
365
- <a href="#" style="margin-left: 10px; color: #1976d2;">Review</a>
366
- </div>
367
- """
368
- else:
369
- html_content += "<p>No vendors require attention at this time.</p>"
370
-
371
- html_content += """
372
- </div>
373
-
374
- <!-- Top Performing Vendors -->
375
- <div class="top-performers">
376
- <h2>Top Performing Vendors</h2>
377
- <p>Vendors with the highest performance scores this month</p>
378
- <div style="display: flex; gap: 20px; flex-wrap: wrap;">
379
- """
380
-
381
- for log in top_performing_logs:
382
- scores = log['scores']
383
- vendor_name = html.escape(log['vendorLogName'])
384
- html_content += f"""
385
- <div style="flex: 1; min-width: 200px;">
386
- <p>{vendor_name}<br><small>Last updated: 5/1/2025</small></p>
387
- <span class="score-circle" style="background: #e0e0e0;">{scores['finalScore']}</span> Overall
388
- <span class="score-circle" style="background: #e0e0e0;">{scores['qualityScore']}</span> Quality
389
- <span class="score-circle" style="background: #e0e0e0;">{scores['timelinessScore']}</span> Time
390
- <span class="score-circle" style="background: #e0e0e0;">{scores['safetyScore']}</span> Safety
391
- <span class="score-circle" style="background: #e0e0e0;">{scores['communicationScore']}</span> Comm
392
- </div>
393
- """
394
-
395
- html_content += """
396
- </div>
397
- </div>
398
-
399
- <!-- Reports & Certifications -->
400
- <div class="reports">
401
- <h2>Reports & Certifications</h2>
402
- <p>Generate and manage vendor performance reports</p>
403
- <div class="reports-section">
404
- <div>
405
- <h3>Generate Vendor Report</h3>
406
- <div style="margin-bottom: 10px;">
407
- <label>Select Vendor</label><br>
408
- <select style="width: 100%; padding: 8px; margin-top: 5px;">
409
- <option>Choose a vendor</option>
410
- """
411
-
412
- for log in vendor_logs:
413
- vendor_name = html.escape(log['vendorLogName'])
414
- html_content += f"""
415
- <option>{vendor_name}</option>
416
- """
417
-
418
- html_content += """
419
- </select>
420
- </div>
421
- <div style="margin-bottom: 10px;">
422
- <label>Report Month</label><br>
423
- <input type="text" value="May, 2025" readonly style="width: 100%; padding: 8px; margin-top: 5px;">
424
- </div>
425
- <div style="margin-bottom: 10px;">
426
- <label>Include in Report</label><br>
427
- <label class="checkbox-label"><input type="checkbox" checked> Quality Metrics</label>
428
- <label class="checkbox-label"><input type="checkbox" checked> Timeliness</label>
429
- <label class="checkbox-label"><input type="checkbox" checked> Safety Record</label>
430
- <label class="checkbox-label"><input type="checkbox" checked> Communication</label>
431
- <label class="checkbox-label"><input type="checkbox" checked> Incidents</label>
432
- <label class="checkbox-label"><input type="checkbox" checked> Recommendations</label>
433
- </div>
434
- <button class="btn">Generate Report</button>
435
- </div>
436
- <div>
437
- <h3>Recent Reports</h3>
438
- """
439
-
440
- for log in sorted_logs[:5]: # Show recent 5 reports
441
- vendor_name = html.escape(log['vendorLogName'])
442
- html_content += f"""
443
- <div style="margin-bottom: 10px;">
444
- 📄 {vendor_name} - Monthly Performance
445
- <span style="float: right;">
446
- <small>5/1/2025</small>
447
- <a href="#" style="margin-left: 10px;">⬇</a>
448
- </span>
449
- </div>
450
- """
451
-
452
- html_content += """
453
- <small>Last report generated: 3 hours ago</small>
454
- <br>
455
- <a href="#" style="color: #1976d2;">View All Reports</a>
456
- </div>
457
- </div>
458
- </div>
459
- </div>
460
- </body>
461
- </html>
462
- """
463
- # Return the HTML response with proper encoding
464
- return Response(html_content, mimetype='text/html; charset=utf-8')
465
  except Exception as e:
466
  error_trace = traceback.format_exc()
467
  logger.error(f"Error in / endpoint: {str(e)}\nStack trace:\n{error_trace}")
 
1
+ from flask import Flask, request, Response, jsonify, render_template
2
  from pydantic import BaseModel
3
  from reportlab.lib.pagesizes import letter
4
  from reportlab.pdfgen import canvas
 
6
  import os
7
  import logging
8
  import traceback
 
9
  from datetime import datetime
10
  from simple_salesforce import Salesforce
11
 
 
240
 
241
  # Sort vendor logs by final score for leaderboard
242
  sorted_logs = sorted(vendor_logs, key=lambda x: x['scores']['finalScore'], reverse=True)
243
+ top_logs_data = sorted_logs[:5] # Top 5 for leaderboard
244
  top_performing_logs = sorted_logs[:4] # Top 4 for "Top Performing Vendors" section
245
+ alert_logs = [log for log in vendor_logs if determine_alert_flag(log['scores']['finalScore'], vendor_logs)][:3]
246
 
247
+ # Prepare data for the leaderboard
248
+ top_logs = []
249
+ for idx, log in enumerate(top_logs_data, 1):
250
+ scores = log['scores']
251
+ alert_flag = determine_alert_flag(scores['finalScore'], vendor_logs)
252
+ trend = "trend-up" if scores['finalScore'] >= 90 else "trend-down" if scores['finalScore'] < 70 else "trend-flat"
253
+ trend_symbol = "↗" if trend == "trend-up" else "↘" if trend == "trend-down" else "—"
254
+ status_class = "status-good" if not alert_flag else "status-alert"
255
+ status_text = "Good" if not alert_flag else "Alert"
256
+ top_logs.append({
257
+ 'idx': idx,
258
+ 'vendorLogName': log['vendorLogName'],
259
+ 'scores': scores,
260
+ 'trend': trend,
261
+ 'trend_symbol': trend_symbol,
262
+ 'status_class': status_class,
263
+ 'status_text': status_text
264
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
+ # Render the template with the data
267
+ return render_template('dashboard.html',
 
 
 
 
 
 
 
 
 
 
 
268
  total_vendors=total_vendors,
269
  performance_alerts=performance_alerts,
270
  percent_alerts=round(performance_alerts/total_vendors*100, 1) if total_vendors else 0,
271
  top_performers=top_performers,
272
  percent_top=round(top_performers/total_vendors*100, 1) if total_vendors else 0,
273
  improving_vendors=improving_vendors,
274
+ percent_improving=round(improving_vendors/total_vendors*100, 1) if total_vendors else 0,
275
+ top_logs=top_logs,
276
+ alert_logs=alert_logs,
277
+ top_performing_logs=top_performing_logs,
278
+ vendor_logs=vendor_logs,
279
+ sorted_logs=sorted_logs
280
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  except Exception as e:
282
  error_trace = traceback.format_exc()
283
  logger.error(f"Error in / endpoint: {str(e)}\nStack trace:\n{error_trace}")