|
1 | 1 | package web |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "encoding/json" |
4 | 5 | "html/template" |
5 | 6 | "net/http" |
6 | 7 | "time" |
@@ -168,3 +169,103 @@ func (s *Server) handleAPITransactions(w http.ResponseWriter, r *http.Request) { |
168 | 169 |
|
169 | 170 | s.sendJSONSuccess(w, response) |
170 | 171 | } |
| 172 | + |
| 173 | +// handleAPICategories returns available categories based on transaction type |
| 174 | +func (s *Server) handleAPICategories(w http.ResponseWriter, r *http.Request) { |
| 175 | + user := client.GetUserFromContext(r.Context()) |
| 176 | + if user == nil { |
| 177 | + s.sendJSONError(w, "Unauthorized", http.StatusUnauthorized) |
| 178 | + return |
| 179 | + } |
| 180 | + |
| 181 | + txType := r.URL.Query().Get("type") |
| 182 | + |
| 183 | + var categories []string |
| 184 | + switch txType { |
| 185 | + case string(model.TypeIncome): |
| 186 | + categories = model.GetIncomeCategories() |
| 187 | + case string(model.TypeExpense): |
| 188 | + categories = model.GetExpenseCategories() |
| 189 | + default: |
| 190 | + s.sendJSONError(w, "Invalid transaction type", http.StatusBadRequest) |
| 191 | + return |
| 192 | + } |
| 193 | + |
| 194 | + s.sendJSONSuccess(w, map[string]any{ |
| 195 | + "categories": categories, |
| 196 | + }) |
| 197 | +} |
| 198 | + |
| 199 | +// handleAPICreateTransaction creates a new transaction |
| 200 | +func (s *Server) handleAPICreateTransaction(w http.ResponseWriter, r *http.Request) { |
| 201 | + if r.Method != http.MethodPost { |
| 202 | + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) |
| 203 | + return |
| 204 | + } |
| 205 | + |
| 206 | + user := client.GetUserFromContext(r.Context()) |
| 207 | + if user == nil { |
| 208 | + s.sendJSONError(w, "Unauthorized", http.StatusUnauthorized) |
| 209 | + return |
| 210 | + } |
| 211 | + |
| 212 | + var req struct { |
| 213 | + Type string `json:"type"` |
| 214 | + Category string `json:"category"` |
| 215 | + Amount float64 `json:"amount"` |
| 216 | + Description string `json:"description"` |
| 217 | + Date string `json:"date"` |
| 218 | + } |
| 219 | + |
| 220 | + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { |
| 221 | + s.sendJSONError(w, "Invalid request", http.StatusBadRequest) |
| 222 | + return |
| 223 | + } |
| 224 | + |
| 225 | + // Validate type |
| 226 | + if req.Type != string(model.TypeIncome) && req.Type != string(model.TypeExpense) { |
| 227 | + s.sendJSONError(w, "Invalid transaction type", http.StatusBadRequest) |
| 228 | + return |
| 229 | + } |
| 230 | + |
| 231 | + // Validate category |
| 232 | + if !model.IsValidTransactionCategory(req.Category) { |
| 233 | + s.sendJSONError(w, "Invalid category", http.StatusBadRequest) |
| 234 | + return |
| 235 | + } |
| 236 | + |
| 237 | + // Validate amount |
| 238 | + if req.Amount <= 0 { |
| 239 | + s.sendJSONError(w, "Amount must be greater than 0", http.StatusBadRequest) |
| 240 | + return |
| 241 | + } |
| 242 | + |
| 243 | + // Parse date |
| 244 | + date, err := time.Parse("2006-01-02", req.Date) |
| 245 | + if err != nil { |
| 246 | + s.sendJSONError(w, "Invalid date format", http.StatusBadRequest) |
| 247 | + return |
| 248 | + } |
| 249 | + |
| 250 | + // Create transaction |
| 251 | + transaction := model.Transaction{ |
| 252 | + TgID: user.TgID, |
| 253 | + Type: model.TransactionType(req.Type), |
| 254 | + Category: model.TransactionCategory(req.Category), |
| 255 | + Amount: req.Amount, |
| 256 | + Description: req.Description, |
| 257 | + Date: date, |
| 258 | + Currency: model.CurrencyEUR, // Default to EUR |
| 259 | + } |
| 260 | + |
| 261 | + err = s.repositories.Transactions.Add(transaction) |
| 262 | + if err != nil { |
| 263 | + s.logger.Errorf("Failed to create transaction: %v", err) |
| 264 | + s.sendJSONError(w, "Failed to create transaction", http.StatusInternalServerError) |
| 265 | + return |
| 266 | + } |
| 267 | + |
| 268 | + s.sendJSONSuccess(w, map[string]any{ |
| 269 | + "message": "Transaction created successfully", |
| 270 | + }) |
| 271 | +} |
0 commit comments