@marcos_feitoza/personal-finance-backen-trades-assets 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [1.0.2](https://github.com/MarcosOps/personal-finance-backend-trades-assets/compare/v1.0.1...v1.0.2) (2025-10-17)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * invest working ([d0ca897](https://github.com/MarcosOps/personal-finance-backend-trades-assets/commit/d0ca897cf8018aeecd2c10d037d94e987e241a58))
7
+
8
+ ## [1.0.1](https://github.com/MarcosOps/personal-finance-backend-trades-assets/compare/v1.0.0...v1.0.1) (2025-09-24)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * update docker ([267efb1](https://github.com/MarcosOps/personal-finance-backend-trades-assets/commit/267efb11d839175803c7aa1866da0585ed4659f9))
14
+
1
15
  # 1.0.0 (2025-09-19)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcos_feitoza/personal-finance-backen-trades-assets",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
File without changes
@@ -5,6 +5,7 @@ from personal_finance_shared.database import get_db
5
5
  import logging
6
6
  import requests
7
7
  import os
8
+ import httpx
8
9
 
9
10
  logging.basicConfig(level=logging.INFO)
10
11
  logger = logging.getLogger(__name__)
@@ -14,39 +15,34 @@ router = APIRouter(
14
15
  tags=["trades"],
15
16
  )
16
17
 
17
- MARKET_DATA_SERVICE_URL = os.getenv("MARKET_DATA_SERVICE_URL", "http://personal-finance-backend-market-data:8000")
18
+ MARKET_DATA_SERVICE_URL = os.getenv("MARKET_DATA_SERVICE_URL", "http://personal-finance-backend-market-data.app.svc.cluster.local:8000")
19
+ BALANCE_SERVICE_URL = os.getenv("BALANCE_SERVICE_URL", "http://personal-finance-backend-balance-service.app.svc.cluster.local:8000")
18
20
 
19
21
  def _get_asset_details_from_service(symbol: str) -> dict:
20
22
  """Fetches asset details from the market-data service."""
21
23
  try:
22
24
  url = f"{MARKET_DATA_SERVICE_URL}/api/market-data/details/{symbol.upper()}"
23
25
  logger.info(f"Fetching details from: {url}")
24
- response = requests.post(url, timeout=10) # Using POST as per the new endpoint
25
- response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
26
+ response = requests.post(url, timeout=10)
27
+ response.raise_for_status()
26
28
  return response.json()
27
29
  except requests.exceptions.RequestException as e:
28
30
  logger.error(f"Error calling market-data service for {symbol}: {e}")
29
31
  return {}
30
32
 
31
-
32
-
33
33
  @router.post("/", response_model=schemas.TradeResponse)
34
- def create_trade(trade: schemas.TradeCreate, db: Session = Depends(get_db)):
34
+ async def create_trade(trade: schemas.TradeCreate, db: Session = Depends(get_db)):
35
35
  trade_symbol = trade.symbol.upper()
36
36
  logger.info(f"Processing trade for symbol: {trade_symbol}")
37
37
 
38
- # Check if asset exists with the provided symbol or its canonical variations
39
38
  db_asset = db.query(models.Asset).filter(models.Asset.symbol == trade_symbol).first()
40
39
  if not db_asset and '.' not in trade_symbol:
41
40
  db_asset = db.query(models.Asset).filter(models.Asset.symbol == f"{trade_symbol}.TO").first()
42
41
 
43
42
  if not db_asset:
44
43
  logger.info(f"Asset with symbol {trade_symbol} not found. Fetching details...")
45
-
46
44
  asset_details = _get_asset_details_from_service(trade_symbol)
47
45
  canonical_symbol = asset_details.get("canonical_symbol", trade_symbol)
48
-
49
- # Double-check if an asset with the canonical symbol already exists
50
46
  db_asset = db.query(models.Asset).filter(models.Asset.symbol == canonical_symbol).first()
51
47
 
52
48
  if not db_asset:
@@ -66,27 +62,30 @@ def create_trade(trade: schemas.TradeCreate, db: Session = Depends(get_db)):
66
62
  else:
67
63
  logger.info(f"Found existing asset with ID: {db_asset.id}")
68
64
 
69
- # --- Balance Validation for 'buy' trades ---
70
65
  if trade.trade_type == 'buy':
71
66
  investment_account_name = trade.investment_account
72
67
  trade_cost = trade.shares * trade.price
73
-
74
- current_balance = crud.get_investment_account_balance(db=db, account_name=investment_account_name)
75
- logger.info(f"Calculated cash balance for '{investment_account_name}' is {current_balance}")
76
-
77
- if current_balance < trade_cost:
68
+ current_balance = 0
69
+ try:
70
+ async with httpx.AsyncClient() as client:
71
+ response = await client.get(f"{BALANCE_SERVICE_URL}/api/balance/{investment_account_name}")
72
+ response.raise_for_status()
73
+ data = response.json()
74
+ current_balance = data['balance']
75
+ logger.info(f"Calculated cash balance for '{investment_account_name}' is {current_balance}")
76
+ except Exception as e:
77
+ logger.error(f"Could not retrieve balance for validation: {e}")
78
+
79
+ if float(current_balance) < float(trade_cost):
78
80
  logger.warning(f"Insufficient funds in '{investment_account_name}'. Balance: {current_balance}, Required: {trade_cost}")
79
81
  raise HTTPException(
80
82
  status_code=400,
81
83
  detail=f"Insufficient cash balance in '{investment_account_name}' to complete trade."
82
84
  )
83
- # --- End Validation Logic ---
84
85
 
85
- # Create the trade record, linking it to the asset via asset_id
86
86
  trade_data = trade.dict(exclude={'symbol', 'name', 'asset_type', 'industry'})
87
87
  db_trade = models.Trade(**trade_data, asset_id=db_asset.id)
88
88
 
89
- # Log for stock purchase/sale
90
89
  if db_trade.trade_type == 'buy':
91
90
  logger.info(f"STOCK PURCHASE: Bought {db_trade.shares} shares of {trade_symbol} at ${db_trade.price:.2f} each.")
92
91
  elif db_trade.trade_type == 'sell':
@@ -111,4 +110,4 @@ def read_trades(
111
110
 
112
111
  trades = query.order_by(models.Trade.date.desc()).offset(skip).limit(limit).all()
113
112
  logger.info(f"Found {len(trades)} trades")
114
- return trades
113
+ return trades
package/requirements.txt CHANGED
@@ -2,5 +2,5 @@ psycopg2-binary
2
2
  sqlalchemy
3
3
  alembic
4
4
  python-dotenv
5
- -e ./shared-library
5
+ -e ./personal-finance-backend-shared
6
6
  requests