Files
boc/backend/service/sales.go
T
Bernt e5623d2f84 feat: integrate Grafana dashboards into BOC DashboardPage
- Add Infrastructure Health section with CPU/Memory/Disk panels
- Add Service Status section with PM2/Docker panels
- Create GrafanaPanel component for iframe embedding
- Build passes successfully
2026-07-29 19:03:06 +00:00

79 lines
1.9 KiB
Go

package service
import (
"context"
"database/sql"
"fmt"
"boc/repository"
)
// SalesService handles business logic for sales operations
type SalesService struct {
repo *repository.SalesRepository
db *sql.DB
}
func NewSalesService(db *sql.DB) *SalesService {
return &SalesService{
repo: repository.NewSalesRepository(db),
db: db,
}
}
// ListDeals returns all deals filtered by status
func (s *SalesService) ListDeals(ctx context.Context, status string) ([]repository.Deal, error) {
return s.repo.ListDeals(ctx, status)
}
// GetDeal returns a single deal by ID
func (s *SalesService) GetDeal(ctx context.Context, id string) (*repository.Deal, error) {
return s.repo.GetDeal(ctx, id)
}
// CreateDeal creates a new deal with validation
func (s *SalesService) CreateDeal(ctx context.Context, d *repository.Deal) error {
if d.Name == "" {
return fmt.Errorf("deal name is required")
}
if d.CustomerID == "" {
return fmt.Errorf("customer ID is required")
}
if d.Value <= 0 {
return fmt.Errorf("deal value must be positive")
}
if d.Status == "" {
d.Status = "open"
}
if d.Stage == "" {
d.Stage = "discovery"
}
if d.Currency == "" {
d.Currency = "USD"
}
return s.repo.CreateDeal(ctx, d)
}
// UpdateDeal updates an existing deal
func (s *SalesService) UpdateDeal(ctx context.Context, id string, d *repository.Deal) error {
if d.Name == "" {
return fmt.Errorf("deal name is required")
}
return s.repo.UpdateDeal(ctx, id, d)
}
// ListProducts returns all active products
func (s *SalesService) ListProducts(ctx context.Context) ([]repository.Product, error) {
return s.repo.ListProducts(ctx)
}
// GetMRR calculates monthly recurring revenue
func (s *SalesService) GetMRR(ctx context.Context) (float64, error) {
return s.repo.GetMRR(ctx)
}
// GetARR calculates annual recurring revenue
func (s *SalesService) GetARR(ctx context.Context) (float64, error) {
return s.repo.GetARR(ctx)
}