LogicGoInfotechSpaces commited on
Commit
caeed61
·
1 Parent(s): 32daeaa

Use budgets (createdBy) as primary source for recommendations

Browse files
Files changed (1) hide show
  1. app/smart_recommendation.py +43 -33
app/smart_recommendation.py CHANGED
@@ -36,33 +36,34 @@ class SmartBudgetRecommender:
36
  Returns:
37
  List of budget recommendations for each category
38
  """
39
- # Get past expenses (last 6 months for better accuracy)
40
- end_date = datetime(year, month, 1) - timedelta(days=1)
41
- start_date = end_date - timedelta(days=180) # ~6 months
42
-
43
- expenses = list(
44
- self.db.expenses.find(
45
- {
46
- "user_id": user_id,
47
- "date": {"$gte": start_date, "$lte": end_date},
48
- "type": "expense",
49
- }
 
 
 
 
 
50
  )
51
- )
52
 
53
- recommendations: List[BudgetRecommendation] = []
 
54
 
55
- if expenses:
56
  # Group expenses by category and calculate monthly averages
57
  category_data = self._calculate_category_statistics(
58
  expenses, start_date, end_date
59
  )
60
- else:
61
- # No expenses found: fallback to existing budgets for this period
62
- category_data = self._get_category_stats_from_budgets(user_id, month, year)
63
- if not category_data:
64
- return []
65
 
 
 
66
  for category, data in category_data.items():
67
  avg_expense = data["average_monthly"]
68
  confidence = self._calculate_confidence(data)
@@ -249,17 +250,16 @@ class SmartBudgetRecommender:
249
  self, user_id: str, month: int, year: int
250
  ) -> Dict:
251
  """
252
- Fallback source when there are no expenses:
253
- use existing budgets for the requested month/year as the 'average' spend.
 
 
254
  """
255
  budgets = list(
256
  self.db.budgets.find(
257
  {
258
- "user_id": user_id,
259
- "period": {"$in": ["monthly", "MONTHLY"]},
260
- "start_date": {
261
- "$lte": datetime(year, month, 28)
262
- }, # loosely within month
263
  }
264
  )
265
  )
@@ -269,26 +269,36 @@ class SmartBudgetRecommender:
269
 
270
  result: Dict[str, Dict] = {}
271
  for b in budgets:
272
- category = b.get("category", "Uncategorized")
273
- amount = float(b.get("amount", 0))
 
 
 
 
 
 
 
 
 
 
274
  if category not in result:
275
  result[category] = {
276
- "average_monthly": amount,
277
- "total": amount,
278
  "count": 1,
279
  "months_analyzed": 1,
280
  "std_dev": 0.0,
281
- "monthly_values": [amount],
282
  }
283
  else:
284
  # If multiple budgets per category, average them
285
- result[category]["total"] += amount
286
  result[category]["count"] += 1
287
  result[category]["months_analyzed"] = result[category]["count"]
288
  result[category]["average_monthly"] = (
289
  result[category]["total"] / result[category]["count"]
290
  )
291
- result[category]["monthly_values"].append(amount)
292
 
293
  return result
294
 
 
36
  Returns:
37
  List of budget recommendations for each category
38
  """
39
+ # 1) Try to build stats from existing budgets for this user (createdBy)
40
+ category_data = self._get_category_stats_from_budgets(user_id, month, year)
41
+
42
+ # 2) If there are no budgets, fall back to expenses history
43
+ if not category_data:
44
+ end_date = datetime(year, month, 1) - timedelta(days=1)
45
+ start_date = end_date - timedelta(days=180) # ~6 months
46
+
47
+ expenses = list(
48
+ self.db.expenses.find(
49
+ {
50
+ "user_id": user_id,
51
+ "date": {"$gte": start_date, "$lte": end_date},
52
+ "type": "expense",
53
+ }
54
+ )
55
  )
 
56
 
57
+ if not expenses:
58
+ return []
59
 
 
60
  # Group expenses by category and calculate monthly averages
61
  category_data = self._calculate_category_statistics(
62
  expenses, start_date, end_date
63
  )
 
 
 
 
 
64
 
65
+ recommendations: List[BudgetRecommendation] = []
66
+
67
  for category, data in category_data.items():
68
  avg_expense = data["average_monthly"]
69
  confidence = self._calculate_confidence(data)
 
250
  self, user_id: str, month: int, year: int
251
  ) -> Dict:
252
  """
253
+ Build category stats from existing budgets for this user.
254
+
255
+ We treat each budget document (e.g. \"Office Maintenance\", \"LOGICGO\")
256
+ as a spending category and derive an \"average\" from its amounts.
257
  """
258
  budgets = list(
259
  self.db.budgets.find(
260
  {
261
+ "createdBy": user_id,
262
+ "status": "OPEN",
 
 
 
263
  }
264
  )
265
  )
 
269
 
270
  result: Dict[str, Dict] = {}
271
  for b in budgets:
272
+ # Use budget \"name\" as category label
273
+ category = b.get("name", "Uncategorized")
274
+
275
+ # Derive a base amount from WalletSync fields
276
+ max_amount = float(b.get("maxAmount", 0) or 0)
277
+ spend_amount = float(b.get("spendAmount", 0) or 0)
278
+
279
+ # If there is recorded spend, use that as \"average\"; otherwise maxAmount
280
+ base_amount = spend_amount if spend_amount > 0 else max_amount
281
+ if base_amount <= 0:
282
+ continue
283
+
284
  if category not in result:
285
  result[category] = {
286
+ "average_monthly": base_amount,
287
+ "total": base_amount,
288
  "count": 1,
289
  "months_analyzed": 1,
290
  "std_dev": 0.0,
291
+ "monthly_values": [base_amount],
292
  }
293
  else:
294
  # If multiple budgets per category, average them
295
+ result[category]["total"] += base_amount
296
  result[category]["count"] += 1
297
  result[category]["months_analyzed"] = result[category]["count"]
298
  result[category]["average_monthly"] = (
299
  result[category]["total"] / result[category]["count"]
300
  )
301
+ result[category]["monthly_values"].append(base_amount)
302
 
303
  return result
304