package handlers import ( "aggios-app/backend/internal/api/middleware" "aggios-app/backend/internal/domain" "aggios-app/backend/internal/repository" "encoding/json" "log" "net/http" "time" "github.com/google/uuid" "github.com/gorilla/mux" ) type ERPHandler struct { repo *repository.ERPRepository } func NewERPHandler(repo *repository.ERPRepository) *ERPHandler { return &ERPHandler{repo: repo} } // ==================== FINANCE ==================== func (h *ERPHandler) CreateFinancialCategory(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) var cat domain.FinancialCategory if err := json.NewDecoder(r.Body).Decode(&cat); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } cat.ID = uuid.New() cat.TenantID, _ = uuid.Parse(tenantID) cat.IsActive = true if err := h.repo.CreateFinancialCategory(&cat); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(cat) } func (h *ERPHandler) GetFinancialCategories(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) cats, err := h.repo.GetFinancialCategoriesByTenant(tenantID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(cats) } func (h *ERPHandler) CreateBankAccount(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) var acc domain.BankAccount if err := json.NewDecoder(r.Body).Decode(&acc); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } acc.ID = uuid.New() acc.TenantID, _ = uuid.Parse(tenantID) acc.IsActive = true if err := h.repo.CreateBankAccount(&acc); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(acc) } func (h *ERPHandler) GetBankAccounts(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) accs, err := h.repo.GetBankAccountsByTenant(tenantID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(accs) } func (h *ERPHandler) CreateTransaction(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) userID, _ := r.Context().Value(middleware.UserIDKey).(string) var t domain.FinancialTransaction if err := json.NewDecoder(r.Body).Decode(&t); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } t.ID = uuid.New() t.TenantID, _ = uuid.Parse(tenantID) t.CreatedBy, _ = uuid.Parse(userID) if err := h.repo.CreateTransaction(&t); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(t) } func (h *ERPHandler) GetTransactions(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) txs, err := h.repo.GetTransactionsByTenant(tenantID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(txs) } // ==================== PRODUCTS ==================== func (h *ERPHandler) CreateProduct(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) var p domain.Product if err := json.NewDecoder(r.Body).Decode(&p); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } p.ID = uuid.New() p.TenantID, _ = uuid.Parse(tenantID) p.IsActive = true if err := h.repo.CreateProduct(&p); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(p) } func (h *ERPHandler) GetProducts(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) products, err := h.repo.GetProductsByTenant(tenantID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(products) } // ==================== ORDERS ==================== type createOrderRequest struct { Order domain.Order `json:"order"` Items []domain.OrderItem `json:"items"` } func (h *ERPHandler) CreateOrder(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) userID, _ := r.Context().Value(middleware.UserIDKey).(string) var req createOrderRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } req.Order.ID = uuid.New() req.Order.TenantID, _ = uuid.Parse(tenantID) req.Order.CreatedBy, _ = uuid.Parse(userID) if req.Order.Status == "" { req.Order.Status = "draft" } for i := range req.Items { req.Items[i].ID = uuid.New() req.Items[i].OrderID = req.Order.ID req.Items[i].CreatedAt = time.Now() } if err := h.repo.CreateOrder(&req.Order, req.Items); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(req.Order) } func (h *ERPHandler) GetOrders(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) orders, err := h.repo.GetOrdersByTenant(tenantID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(orders) } // ==================== ENTITIES ==================== func (h *ERPHandler) CreateEntity(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) var e domain.Entity if err := json.NewDecoder(r.Body).Decode(&e); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } e.ID = uuid.New() e.TenantID, _ = uuid.Parse(tenantID) if e.Status == "" { e.Status = "active" } if err := h.repo.CreateEntity(&e); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(e) } func (h *ERPHandler) GetEntities(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) entityType := r.URL.Query().Get("type") // customer or supplier entities, err := h.repo.GetEntitiesByTenant(tenantID, entityType) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(entities) } func (h *ERPHandler) UpdateTransaction(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] id, err := uuid.Parse(idStr) if err != nil { http.Error(w, "invalid id", http.StatusBadRequest) return } var t domain.FinancialTransaction if err := json.NewDecoder(r.Body).Decode(&t); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } t.ID = id t.TenantID, _ = uuid.Parse(tenantID) if err := h.repo.UpdateTransaction(&t); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) DeleteTransaction(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] if err := h.repo.DeleteTransaction(idStr, tenantID); err != nil { log.Printf("❌ Error deleting transaction: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) UpdateEntity(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] id, err := uuid.Parse(idStr) if err != nil { http.Error(w, "invalid id", http.StatusBadRequest) return } var e domain.Entity if err := json.NewDecoder(r.Body).Decode(&e); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } e.ID = id e.TenantID, _ = uuid.Parse(tenantID) if err := h.repo.UpdateEntity(&e); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) DeleteEntity(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] if err := h.repo.DeleteEntity(idStr, tenantID); err != nil { log.Printf("❌ Error deleting entity: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) UpdateProduct(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] id, err := uuid.Parse(idStr) if err != nil { http.Error(w, "invalid id", http.StatusBadRequest) return } var p domain.Product if err := json.NewDecoder(r.Body).Decode(&p); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } p.ID = id p.TenantID, _ = uuid.Parse(tenantID) if err := h.repo.UpdateProduct(&p); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) DeleteProduct(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] if err := h.repo.DeleteProduct(idStr, tenantID); err != nil { log.Printf("❌ Error deleting product: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) UpdateBankAccount(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] id, err := uuid.Parse(idStr) if err != nil { http.Error(w, "invalid id", http.StatusBadRequest) return } var a domain.BankAccount if err := json.NewDecoder(r.Body).Decode(&a); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } a.ID = id a.TenantID, _ = uuid.Parse(tenantID) if err := h.repo.UpdateBankAccount(&a); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) DeleteBankAccount(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] if err := h.repo.DeleteBankAccount(idStr, tenantID); err != nil { log.Printf("❌ Error deleting bank account: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *ERPHandler) DeleteOrder(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) idStr := mux.Vars(r)["id"] if err := h.repo.DeleteOrder(idStr, tenantID); err != nil { log.Printf("❌ Error deleting order: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) }