rairo commited on
Commit
7f3cb6f
·
verified ·
1 Parent(s): f333001

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +77 -15
main.py CHANGED
@@ -749,60 +749,114 @@ def admin_remove_member_from_org(org_id, member_uid):
749
  @app.route('/api/admin/dashboard/stats', methods=['GET'])
750
  def get_admin_dashboard_stats():
751
  """
752
- Retrieves global statistics for the admin dashboard with correct profit calculation.
753
- **FIXED**: Multiplies price and cost by quantity for accurate financial totals.
754
  """
755
  try:
756
  verify_admin_and_get_uid(request.headers.get('Authorization'))
757
 
 
758
  all_users_docs = list(db.collection('users').stream())
759
  all_orgs_docs = list(db.collection('organizations').stream())
760
 
 
 
 
 
 
 
 
761
  pending_approvals, approved_users, admin_count = 0, 0, 0
762
  approved_phone_numbers = []
763
 
764
  for doc in all_users_docs:
765
  user_data = doc.to_dict()
 
766
  if user_data.get('phoneStatus') == 'pending':
767
  pending_approvals += 1
768
- elif user_data.get('phoneStatus') == 'approved':
769
  approved_users += 1
770
- if user_data.get('phone'):
771
- approved_phone_numbers.append(user_data.get('phone'))
 
 
 
772
  if user_data.get('isAdmin', False):
773
  admin_count += 1
774
 
775
- user_stats = {
776
- 'total': len(all_users_docs), 'admins': admin_count,
777
- 'approvedForBot': approved_users, 'pendingApproval': pending_approvals,
778
- }
779
  org_stats = {'total': len(all_orgs_docs)}
780
 
781
- # --- THE FIX IS HERE ---
782
  total_sales_revenue, total_cogs, total_expenses, sales_count = 0, 0, 0, 0
783
 
784
  for phone in approved_phone_numbers:
785
  try:
786
  bot_data_id = phone.lstrip('+')
787
  bot_user_ref = db.collection('users').document(bot_data_id)
 
 
 
788
 
 
789
  sales_docs = bot_user_ref.collection('sales').stream()
790
  for sale_doc in sales_docs:
791
  details = sale_doc.to_dict().get('details', {})
792
  quantity = int(details.get('quantity', 1))
793
  price = float(details.get('price', 0))
794
  cost = float(details.get('cost', 0))
 
 
795
 
796
- total_sales_revenue += price * quantity
 
797
  total_cogs += cost * quantity
798
  sales_count += 1
799
-
 
 
 
 
 
 
800
  expenses_docs = bot_user_ref.collection('expenses').stream()
801
- total_expenses += sum(float(doc.to_dict().get('details', {}).get('amount', 0)) for doc in expenses_docs)
 
 
 
 
 
 
 
802
  except Exception as e:
803
  logging.error(f"Admin stats: Could not process data for phone {phone}. Error: {e}")
804
  continue
805
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
806
  gross_profit = total_sales_revenue - total_cogs
807
  net_profit = gross_profit - total_expenses
808
 
@@ -813,9 +867,17 @@ def get_admin_dashboard_stats():
813
  'totalNetProfit': round(net_profit, 2),
814
  'totalSalesCount': sales_count,
815
  }
816
- # --- END OF FIX ---
817
 
818
- return jsonify({'userStats': user_stats, 'organizationStats': org_stats, 'systemStats': system_stats}), 200
 
 
 
 
 
 
 
 
 
819
 
820
  except PermissionError as e:
821
  return jsonify({'error': str(e)}), 403
 
749
  @app.route('/api/admin/dashboard/stats', methods=['GET'])
750
  def get_admin_dashboard_stats():
751
  """
752
+ Retrieves global statistics for the admin dashboard, including leaderboards
753
+ for top users, items, and expenses.
754
  """
755
  try:
756
  verify_admin_and_get_uid(request.headers.get('Authorization'))
757
 
758
+ # --- Initialization ---
759
  all_users_docs = list(db.collection('users').stream())
760
  all_orgs_docs = list(db.collection('organizations').stream())
761
 
762
+ # Data structures for leaderboards
763
+ user_sales_data = {} # {phone: {'total_revenue': X, 'item_sales': {item: revenue}}}
764
+ global_item_revenue = {} # {item_name: total_revenue}
765
+ global_expense_totals = {} # {category: total_amount}
766
+ phone_to_user_map = {} # Helper to get user info from phone
767
+
768
+ # --- First Pass: Get user info and list of approved phones ---
769
  pending_approvals, approved_users, admin_count = 0, 0, 0
770
  approved_phone_numbers = []
771
 
772
  for doc in all_users_docs:
773
  user_data = doc.to_dict()
774
+ phone = user_data.get('phone')
775
  if user_data.get('phoneStatus') == 'pending':
776
  pending_approvals += 1
777
+ elif user_data.get('phoneStatus') == 'approved' and phone:
778
  approved_users += 1
779
+ approved_phone_numbers.append(phone)
780
+ phone_to_user_map[phone] = {
781
+ 'displayName': user_data.get('displayName', 'N/A'),
782
+ 'uid': user_data.get('uid')
783
+ }
784
  if user_data.get('isAdmin', False):
785
  admin_count += 1
786
 
787
+ user_stats = {'total': len(all_users_docs), 'admins': admin_count, 'approvedForBot': approved_users, 'pendingApproval': pending_approvals}
 
 
 
788
  org_stats = {'total': len(all_orgs_docs)}
789
 
790
+ # --- Second Pass: Aggregate financial data for all approved users ---
791
  total_sales_revenue, total_cogs, total_expenses, sales_count = 0, 0, 0, 0
792
 
793
  for phone in approved_phone_numbers:
794
  try:
795
  bot_data_id = phone.lstrip('+')
796
  bot_user_ref = db.collection('users').document(bot_data_id)
797
+
798
+ # Initialize user's entry for leaderboard tracking
799
+ user_sales_data[phone] = {'total_revenue': 0, 'item_sales': {}}
800
 
801
+ # Process Sales
802
  sales_docs = bot_user_ref.collection('sales').stream()
803
  for sale_doc in sales_docs:
804
  details = sale_doc.to_dict().get('details', {})
805
  quantity = int(details.get('quantity', 1))
806
  price = float(details.get('price', 0))
807
  cost = float(details.get('cost', 0))
808
+ item_name = details.get('item', 'Unknown Item')
809
+ sale_revenue = price * quantity
810
 
811
+ # Aggregate for global system stats
812
+ total_sales_revenue += sale_revenue
813
  total_cogs += cost * quantity
814
  sales_count += 1
815
+
816
+ # Aggregate for leaderboards
817
+ user_sales_data[phone]['total_revenue'] += sale_revenue
818
+ user_sales_data[phone]['item_sales'][item_name] = user_sales_data[phone]['item_sales'].get(item_name, 0) + sale_revenue
819
+ global_item_revenue[item_name] = global_item_revenue.get(item_name, 0) + sale_revenue
820
+
821
+ # Process Expenses
822
  expenses_docs = bot_user_ref.collection('expenses').stream()
823
+ for expense_doc in expenses_docs:
824
+ details = expense_doc.to_dict().get('details', {})
825
+ amount = float(details.get('amount', 0))
826
+ category = details.get('category', 'Uncategorized')
827
+
828
+ total_expenses += amount
829
+ global_expense_totals[category] = global_expense_totals.get(category, 0) + amount
830
+
831
  except Exception as e:
832
  logging.error(f"Admin stats: Could not process data for phone {phone}. Error: {e}")
833
  continue
834
 
835
+ # --- Post-Processing: Calculate and Rank Leaderboards ---
836
+
837
+ # Rank Top Users by Revenue
838
+ sorted_users = sorted(user_sales_data.items(), key=lambda item: item[1]['total_revenue'], reverse=True)
839
+ top_users_by_revenue = []
840
+ for phone, data in sorted_users[:5]:
841
+ user_info = phone_to_user_map.get(phone, {})
842
+ # Find this user's top selling item
843
+ top_item = max(data['item_sales'], key=data['item_sales'].get) if data['item_sales'] else 'N/A'
844
+ top_users_by_revenue.append({
845
+ 'displayName': user_info.get('displayName'),
846
+ 'uid': user_info.get('uid'),
847
+ 'totalRevenue': round(data['total_revenue'], 2),
848
+ 'topSellingItem': top_item
849
+ })
850
+
851
+ # Rank Top Selling Items Globally
852
+ sorted_items = sorted(global_item_revenue.items(), key=lambda item: item[1], reverse=True)
853
+ top_selling_items = [{'item': name, 'totalRevenue': round(revenue, 2)} for name, revenue in sorted_items[:5]]
854
+
855
+ # Rank Top Expenses Globally
856
+ sorted_expenses = sorted(global_expense_totals.items(), key=lambda item: item[1], reverse=True)
857
+ top_expenses = [{'category': name, 'totalAmount': round(amount, 2)} for name, amount in sorted_expenses[:5]]
858
+
859
+ # --- Final Assembly ---
860
  gross_profit = total_sales_revenue - total_cogs
861
  net_profit = gross_profit - total_expenses
862
 
 
867
  'totalNetProfit': round(net_profit, 2),
868
  'totalSalesCount': sales_count,
869
  }
 
870
 
871
+ return jsonify({
872
+ 'userStats': user_stats,
873
+ 'organizationStats': org_stats,
874
+ 'systemStats': system_stats,
875
+ 'leaderboards': { # Add the new leaderboards to the response
876
+ 'topUsersByRevenue': top_users_by_revenue,
877
+ 'topSellingItems': top_selling_items,
878
+ 'topExpenses': top_expenses
879
+ }
880
+ }), 200
881
 
882
  except PermissionError as e:
883
  return jsonify({'error': str(e)}), 403