turash/bugulma/backend/internal/service/resource_flow_service.go

212 lines
6.1 KiB
Go

package service
import (
"bugulma/backend/internal/domain"
"context"
"encoding/json"
"time"
"github.com/google/uuid"
"gorm.io/datatypes"
)
// Context keys for extracting user/org info from context
type contextKey string
const (
userIDKey contextKey = "user_id"
orgIDKey contextKey = "org_id"
)
// getUserFromContext extracts user ID from context
func getUserFromContext(ctx context.Context) string {
if userID, ok := ctx.Value(userIDKey).(string); ok {
return userID
}
return "system" // Default fallback
}
// getOrgFromContext extracts organization ID from context
func getOrgFromContext(ctx context.Context) string {
if orgID, ok := ctx.Value(orgIDKey).(string); ok {
return orgID
}
return "" // Will be determined from entity
}
// ResourceFlowService handles business logic for resource flows
type ResourceFlowService struct {
repo domain.ResourceFlowRepository
eventBus domain.EventBus
}
// NewResourceFlowService creates a new resource flow service
func NewResourceFlowService(repo domain.ResourceFlowRepository, eventBus domain.EventBus) *ResourceFlowService {
return &ResourceFlowService{
repo: repo,
eventBus: eventBus,
}
}
// CreateResourceFlowRequest represents the request to create a resource flow
type CreateResourceFlowRequest struct {
OrganizationID string
SiteID string
Direction domain.ResourceDirection
Type domain.ResourceType
Quality domain.Quality
Quantity domain.Quantity
TimeProfile domain.TimeProfile
EconomicData domain.EconomicData
Constraints domain.Constraints
ServiceDetails domain.ServiceDetails
PrecisionLevel domain.PrecisionLevel
SourceType domain.SourceType
}
// Create creates a new resource flow
func (s *ResourceFlowService) Create(ctx context.Context, req CreateResourceFlowRequest) (*domain.ResourceFlow, error) {
qualityJSON, _ := json.Marshal(req.Quality)
quantityJSON, _ := json.Marshal(req.Quantity)
timeProfileJSON, _ := json.Marshal(req.TimeProfile)
economicDataJSON, _ := json.Marshal(req.EconomicData)
constraintsJSON, _ := json.Marshal(req.Constraints)
serviceDetailsJSON, _ := json.Marshal(req.ServiceDetails)
rf := &domain.ResourceFlow{
ID: uuid.New().String(),
OrganizationID: req.OrganizationID,
SiteID: req.SiteID,
Direction: req.Direction,
Type: req.Type,
Quality: datatypes.JSON(qualityJSON),
Quantity: datatypes.JSON(quantityJSON),
TimeProfile: datatypes.JSON(timeProfileJSON),
EconomicData: datatypes.JSON(economicDataJSON),
Constraints: datatypes.JSON(constraintsJSON),
ServiceDetails: datatypes.JSON(serviceDetailsJSON),
PrecisionLevel: req.PrecisionLevel,
SourceType: req.SourceType,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := s.repo.Create(ctx, rf); err != nil {
return nil, err
}
// Publish event
userID := getUserFromContext(ctx)
if s.eventBus != nil {
event := domain.Event{
Type: domain.EventTypeResourceFlowCreated,
EntityID: rf.ID,
OrgID: rf.OrganizationID,
UserID: userID,
Timestamp: time.Now(),
Payload: map[string]interface{}{
"resource_type": string(rf.Type),
"direction": string(rf.Direction),
"site_id": rf.SiteID,
},
}
if err := s.eventBus.Publish(event); err != nil {
// Log error but don't fail the operation
// Event publishing should not block the main operation
// TODO: Add proper logging here
}
}
return rf, nil
}
// GetByID retrieves a resource flow by ID
func (s *ResourceFlowService) GetByID(ctx context.Context, id string) (*domain.ResourceFlow, error) {
return s.repo.GetByID(ctx, id)
}
// GetBySiteID retrieves resource flows at a specific site
func (s *ResourceFlowService) GetBySiteID(ctx context.Context, siteID string) ([]*domain.ResourceFlow, error) {
return s.repo.GetBySiteID(ctx, siteID)
}
// GetByOrganizationID retrieves resource flows owned by an organization
func (s *ResourceFlowService) GetByOrganizationID(ctx context.Context, organizationID string) ([]*domain.ResourceFlow, error) {
return s.repo.GetByOrganizationID(ctx, organizationID)
}
// List retrieves all resource flows with optional filtering
func (s *ResourceFlowService) List(ctx context.Context) ([]*domain.ResourceFlow, error) {
return s.repo.GetAll(ctx)
}
// GetByTypeAndDirection retrieves resource flows by type and direction
func (s *ResourceFlowService) GetByTypeAndDirection(ctx context.Context, resType domain.ResourceType, direction domain.ResourceDirection) ([]*domain.ResourceFlow, error) {
return s.repo.GetByTypeAndDirection(ctx, resType, direction)
}
// Update updates a resource flow
func (s *ResourceFlowService) Update(ctx context.Context, rf *domain.ResourceFlow) error {
rf.UpdatedAt = time.Now()
if err := s.repo.Update(ctx, rf); err != nil {
return err
}
// Publish event
userID := getUserFromContext(ctx)
if s.eventBus != nil {
event := domain.Event{
Type: domain.EventTypeResourceFlowUpdated,
EntityID: rf.ID,
OrgID: rf.OrganizationID,
UserID: userID,
Timestamp: time.Now(),
Payload: map[string]interface{}{
"resource_type": string(rf.Type),
"direction": string(rf.Direction),
"site_id": rf.SiteID,
},
}
if err := s.eventBus.Publish(event); err != nil {
// Log error but don't fail the operation
}
}
return nil
}
// Delete deletes a resource flow
func (s *ResourceFlowService) Delete(ctx context.Context, id string) error {
// Get the resource flow before deleting to publish event with details
rf, err := s.repo.GetByID(ctx, id)
if err != nil {
return err
}
if err := s.repo.Delete(ctx, id); err != nil {
return err
}
// Publish event
userID := getUserFromContext(ctx)
if s.eventBus != nil {
event := domain.Event{
Type: domain.EventTypeResourceFlowDeleted,
EntityID: id,
OrgID: rf.OrganizationID,
UserID: userID,
Timestamp: time.Now(),
Payload: map[string]interface{}{
"resource_type": string(rf.Type),
"direction": string(rf.Direction),
"site_id": rf.SiteID,
},
}
if err := s.eventBus.Publish(event); err != nil {
// Log error but don't fail the operation
}
}
return nil
}