rairo commited on
Commit
12984e4
·
verified ·
1 Parent(s): ba899a9

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +40 -82
main.py CHANGED
@@ -762,8 +762,8 @@ def admin_remove_member_from_org(org_id, member_uid):
762
  @app.route('/api/admin/dashboard/stats', methods=['GET'])
763
  def get_admin_dashboard_stats():
764
  """
765
- Retrieves complete global statistics, including separate Top 5 leaderboards
766
- for each currency found in the system.
767
  """
768
  try:
769
  verify_admin_and_get_uid(request.headers.get('Authorization'))
@@ -772,52 +772,54 @@ def get_admin_dashboard_stats():
772
  all_users_docs = list(db.collection('users').stream())
773
  all_orgs_docs = list(db.collection('organizations').stream())
774
 
775
- # Log initial data collection
776
- logging.info(f"Admin Dashboard: Retrieved {len(all_users_docs)} users and {len(all_orgs_docs)} organizations")
777
-
778
- # Data structures for aggregation
779
- user_sales_data = {}
780
- global_item_revenue = {} # Will now be nested: {item: {currency: total}}
781
- global_expense_totals = {} # Will now be nested: {category: {currency: total}}
782
- phone_to_user_map = {}
783
  global_sales_rev_by_curr, global_cogs_by_curr, global_expenses_by_curr = {}, {}, {}
784
 
785
- # --- First Pass: Get user info ---
786
  pending_approvals, approved_users, admin_count = 0, 0, 0
787
  approved_phone_numbers = []
 
788
  for doc in all_users_docs:
789
  user_data = doc.to_dict()
790
- phone = user_data.get('phone')
791
- if user_data.get('phoneStatus') == 'pending':
792
- pending_approvals += 1
793
- elif user_data.get('phoneStatus') == 'approved' and phone:
794
- approved_users += 1
795
- approved_phone_numbers.append(phone)
796
- phone_to_user_map[phone] = {
797
- 'displayName': user_data.get('displayName', 'N/A'), 'uid': user_data.get('uid'),
798
- 'defaultCurrency': user_data.get('defaultCurrency', 'USD')
799
- }
800
- if user_data.get('isAdmin', False):
801
- admin_count += 1
802
-
803
- user_stats = {'total': len(all_users_docs), 'admins': admin_count, 'approvedForBot': approved_users, 'pendingApproval': pending_approvals}
 
 
 
 
 
 
 
 
 
 
 
 
 
804
  org_stats = {'total': len(all_orgs_docs)}
805
 
806
- # Log user processing results
807
- logging.info(f"Admin Dashboard: User stats - Total: {user_stats['total']}, Admins: {user_stats['admins']}, Approved: {user_stats['approvedForBot']}, Pending: {user_stats['pendingApproval']}")
808
-
809
- # --- Second Pass: Aggregate all financial data ---
810
  sales_count = 0
811
  for phone in approved_phone_numbers:
812
  try:
813
  bot_data_id = phone.lstrip('+')
814
  bot_user_ref = db.collection('users').document(bot_data_id)
 
815
  user_sales_data[phone] = {'total_revenue_by_currency': {}, 'item_sales': {}}
816
  last_seen_currency_code = normalize_currency_code(phone_to_user_map.get(phone, {}).get('defaultCurrency'), 'USD')
817
 
818
- user_sales_count = 0
819
- user_expenses_count = 0
820
-
821
  for sale_doc in bot_user_ref.collection('sales').stream():
822
  details = sale_doc.to_dict().get('details', {})
823
  currency_code = normalize_currency_code(details.get('currency'), last_seen_currency_code)
@@ -829,7 +831,6 @@ def get_admin_dashboard_stats():
829
  global_sales_rev_by_curr[currency_code] = global_sales_rev_by_curr.get(currency_code, 0) + sale_revenue
830
  global_cogs_by_curr[currency_code] = global_cogs_by_curr.get(currency_code, 0) + (cost * quantity)
831
  sales_count += 1
832
- user_sales_count += 1
833
 
834
  user_sales_data[phone]['total_revenue_by_currency'][currency_code] = user_sales_data[phone]['total_revenue_by_currency'].get(currency_code, 0) + sale_revenue
835
 
@@ -846,54 +847,28 @@ def get_admin_dashboard_stats():
846
  global_expenses_by_curr[currency_code] = global_expenses_by_curr.get(currency_code, 0) + amount
847
  if category not in global_expense_totals: global_expense_totals[category] = {}
848
  global_expense_totals[category][currency_code] = global_expense_totals[category].get(currency_code, 0) + amount
849
- user_expenses_count += 1
850
-
851
- # Log per-user processing results
852
- if user_sales_count > 0 or user_expenses_count > 0:
853
- logging.info(f"Admin Dashboard: User {phone} - Sales: {user_sales_count}, Expenses: {user_expenses_count}")
854
-
855
  except Exception as e:
856
  logging.error(f"Admin stats: Could not process data for phone {phone}. Error: {e}")
857
  continue
858
 
859
- # Log financial aggregation results
860
- logging.info(f"Admin Dashboard: Financial aggregation - Total sales: {sales_count}, Currencies found: {list(set(global_sales_rev_by_curr.keys()) | set(global_expenses_by_curr.keys()))}")
861
- logging.info(f"Admin Dashboard: Revenue by currency: {global_sales_rev_by_curr}")
862
- logging.info(f"Admin Dashboard: Expenses by currency: {global_expenses_by_curr}")
863
-
864
  # --- Post-Processing: Generate Leaderboards For Each Currency ---
865
  all_currencies = set(global_sales_rev_by_curr.keys()) | set(global_expenses_by_curr.keys())
866
 
867
- leaderboards = {
868
- 'topUsersByRevenue': {},
869
- 'topSellingItems': {},
870
- 'topExpenses': {}
871
- }
872
 
873
  for currency in all_currencies:
874
- # Rank Users for this currency
875
  users_in_curr = [(phone, data['total_revenue_by_currency'].get(currency, 0)) for phone, data in user_sales_data.items() if data['total_revenue_by_currency'].get(currency, 0) > 0]
876
  sorted_users = sorted(users_in_curr, key=lambda item: item[1], reverse=True)
877
- leaderboards['topUsersByRevenue'][currency] = [{
878
- 'displayName': phone_to_user_map.get(phone, {}).get('displayName'),
879
- 'uid': phone_to_user_map.get(phone, {}).get('uid'),
880
- 'totalRevenue': round(revenue, 2)
881
- } for phone, revenue in sorted_users[:5]]
882
 
883
- # Rank Items for this currency
884
  items_in_curr = [(name, totals.get(currency, 0)) for name, totals in global_item_revenue.items() if totals.get(currency, 0) > 0]
885
  sorted_items = sorted(items_in_curr, key=lambda item: item[1], reverse=True)
886
  leaderboards['topSellingItems'][currency] = [{'item': name, 'totalRevenue': round(revenue, 2)} for name, revenue in sorted_items[:5]]
887
 
888
- # Rank Expenses for this currency
889
  expenses_in_curr = [(name, totals.get(currency, 0)) for name, totals in global_expense_totals.items() if totals.get(currency, 0) > 0]
890
  sorted_expenses = sorted(expenses_in_curr, key=lambda item: item[1], reverse=True)
891
  leaderboards['topExpenses'][currency] = [{'category': name, 'totalAmount': round(amount, 2)} for name, amount in sorted_expenses[:5]]
892
 
893
- # Log leaderboard generation results
894
- for currency in all_currencies:
895
- logging.info(f"Admin Dashboard: Leaderboard for {currency} - Top users: {len(leaderboards['topUsersByRevenue'][currency])}, Top items: {len(leaderboards['topSellingItems'][currency])}, Top expenses: {len(leaderboards['topExpenses'][currency])}")
896
-
897
  # --- Final Assembly ---
898
  global_net_profit_by_curr = {}
899
  for curr in all_currencies:
@@ -910,29 +885,12 @@ def get_admin_dashboard_stats():
910
  'totalSalesCount': sales_count,
911
  }
912
 
913
- # Log final response data structure
914
- response_data = {
915
- 'userStats': user_stats,
916
- 'organizationStats': org_stats,
917
- 'systemStats': system_stats,
918
- 'leaderboards': leaderboards
919
- }
920
-
921
- logging.info(f"Admin Dashboard: Final response structure - userStats keys: {list(user_stats.keys())}, systemStats keys: {list(system_stats.keys())}, leaderboards keys: {list(leaderboards.keys())}")
922
- logging.info(f"Admin Dashboard: System stats summary - Total currencies: {len(all_currencies)}, Net profit by currency: {global_net_profit_by_curr}")
923
-
924
- # Log the complete response data
925
- logging.info(f"Admin Dashboard: Complete response data: {response_data}")
926
-
927
- # Log response data size for debugging
928
- import json
929
- response_size = len(json.dumps(response_data))
930
- logging.info(f"Admin Dashboard: Response data size: {response_size} bytes")
931
-
932
- return jsonify(response_data), 200
933
 
934
  except PermissionError as e:
935
- logging.error(f"Admin Dashboard: Permission denied - {e}")
936
  return jsonify({'error': str(e)}), 403
937
  except Exception as e:
938
  logging.error(f"Admin failed to fetch dashboard stats: {e}", exc_info=True)
 
762
  @app.route('/api/admin/dashboard/stats', methods=['GET'])
763
  def get_admin_dashboard_stats():
764
  """
765
+ Retrieves complete global statistics, including an accurate total user count
766
+ and separate Top 5 leaderboards for each currency.
767
  """
768
  try:
769
  verify_admin_and_get_uid(request.headers.get('Authorization'))
 
772
  all_users_docs = list(db.collection('users').stream())
773
  all_orgs_docs = list(db.collection('organizations').stream())
774
 
775
+ user_sales_data, global_item_revenue, global_expense_totals, phone_to_user_map = {}, {}, {}, {}
 
 
 
 
 
 
 
776
  global_sales_rev_by_curr, global_cogs_by_curr, global_expenses_by_curr = {}, {}, {}
777
 
778
+ # --- First Pass: Process all documents to gather stats and approved phones ---
779
  pending_approvals, approved_users, admin_count = 0, 0, 0
780
  approved_phone_numbers = []
781
+
782
  for doc in all_users_docs:
783
  user_data = doc.to_dict()
784
+ # This check ensures we only process documents that are actual user profiles
785
+ if user_data.get('email'):
786
+ phone = user_data.get('phone')
787
+ if user_data.get('phoneStatus') == 'pending':
788
+ pending_approvals += 1
789
+ elif user_data.get('phoneStatus') == 'approved' and phone:
790
+ approved_users += 1
791
+ approved_phone_numbers.append(phone)
792
+ phone_to_user_map[phone] = {
793
+ 'displayName': user_data.get('displayName', 'N/A'), 'uid': user_data.get('uid'),
794
+ 'defaultCurrency': user_data.get('defaultCurrency', 'USD')
795
+ }
796
+ if user_data.get('isAdmin', False):
797
+ admin_count += 1
798
+
799
+ # --- THE FIX IS HERE: Create a filtered list of only user profiles for an accurate count ---
800
+ user_profile_docs = [doc for doc in all_users_docs if doc.to_dict().get('email')]
801
+
802
+ # Assemble the accurate user stats
803
+ user_stats = {
804
+ 'total': len(user_profile_docs), # Use the length of the filtered list
805
+ 'admins': admin_count,
806
+ 'approvedForBot': approved_users,
807
+ 'pendingApproval': pending_approvals
808
+ }
809
+ # --- END OF FIX ---
810
+
811
  org_stats = {'total': len(all_orgs_docs)}
812
 
813
+ # --- Second Pass: Aggregate financial data from bot documents ---
 
 
 
814
  sales_count = 0
815
  for phone in approved_phone_numbers:
816
  try:
817
  bot_data_id = phone.lstrip('+')
818
  bot_user_ref = db.collection('users').document(bot_data_id)
819
+
820
  user_sales_data[phone] = {'total_revenue_by_currency': {}, 'item_sales': {}}
821
  last_seen_currency_code = normalize_currency_code(phone_to_user_map.get(phone, {}).get('defaultCurrency'), 'USD')
822
 
 
 
 
823
  for sale_doc in bot_user_ref.collection('sales').stream():
824
  details = sale_doc.to_dict().get('details', {})
825
  currency_code = normalize_currency_code(details.get('currency'), last_seen_currency_code)
 
831
  global_sales_rev_by_curr[currency_code] = global_sales_rev_by_curr.get(currency_code, 0) + sale_revenue
832
  global_cogs_by_curr[currency_code] = global_cogs_by_curr.get(currency_code, 0) + (cost * quantity)
833
  sales_count += 1
 
834
 
835
  user_sales_data[phone]['total_revenue_by_currency'][currency_code] = user_sales_data[phone]['total_revenue_by_currency'].get(currency_code, 0) + sale_revenue
836
 
 
847
  global_expenses_by_curr[currency_code] = global_expenses_by_curr.get(currency_code, 0) + amount
848
  if category not in global_expense_totals: global_expense_totals[category] = {}
849
  global_expense_totals[category][currency_code] = global_expense_totals[category].get(currency_code, 0) + amount
 
 
 
 
 
 
850
  except Exception as e:
851
  logging.error(f"Admin stats: Could not process data for phone {phone}. Error: {e}")
852
  continue
853
 
 
 
 
 
 
854
  # --- Post-Processing: Generate Leaderboards For Each Currency ---
855
  all_currencies = set(global_sales_rev_by_curr.keys()) | set(global_expenses_by_curr.keys())
856
 
857
+ leaderboards = {'topUsersByRevenue': {}, 'topSellingItems': {}, 'topExpenses': {}}
 
 
 
 
858
 
859
  for currency in all_currencies:
 
860
  users_in_curr = [(phone, data['total_revenue_by_currency'].get(currency, 0)) for phone, data in user_sales_data.items() if data['total_revenue_by_currency'].get(currency, 0) > 0]
861
  sorted_users = sorted(users_in_curr, key=lambda item: item[1], reverse=True)
862
+ leaderboards['topUsersByRevenue'][currency] = [{'displayName': phone_to_user_map.get(phone, {}).get('displayName'), 'uid': phone_to_user_map.get(phone, {}).get('uid'), 'totalRevenue': round(revenue, 2)} for phone, revenue in sorted_users[:5]]
 
 
 
 
863
 
 
864
  items_in_curr = [(name, totals.get(currency, 0)) for name, totals in global_item_revenue.items() if totals.get(currency, 0) > 0]
865
  sorted_items = sorted(items_in_curr, key=lambda item: item[1], reverse=True)
866
  leaderboards['topSellingItems'][currency] = [{'item': name, 'totalRevenue': round(revenue, 2)} for name, revenue in sorted_items[:5]]
867
 
 
868
  expenses_in_curr = [(name, totals.get(currency, 0)) for name, totals in global_expense_totals.items() if totals.get(currency, 0) > 0]
869
  sorted_expenses = sorted(expenses_in_curr, key=lambda item: item[1], reverse=True)
870
  leaderboards['topExpenses'][currency] = [{'category': name, 'totalAmount': round(amount, 2)} for name, amount in sorted_expenses[:5]]
871
 
 
 
 
 
872
  # --- Final Assembly ---
873
  global_net_profit_by_curr = {}
874
  for curr in all_currencies:
 
885
  'totalSalesCount': sales_count,
886
  }
887
 
888
+ return jsonify({
889
+ 'userStats': user_stats, 'organizationStats': org_stats,
890
+ 'systemStats': system_stats, 'leaderboards': leaderboards
891
+ }), 200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892
 
893
  except PermissionError as e:
 
894
  return jsonify({'error': str(e)}), 403
895
  except Exception as e:
896
  logging.error(f"Admin failed to fetch dashboard stats: {e}", exc_info=True)