mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
Repository Structure:
- Move files from cluttered root directory into organized structure
- Create archive/ for archived data and scraper results
- Create bugulma/ for the complete application (frontend + backend)
- Create data/ for sample datasets and reference materials
- Create docs/ for comprehensive documentation structure
- Create scripts/ for utility scripts and API tools
Backend Implementation:
- Implement 3 missing backend endpoints identified in gap analysis:
* GET /api/v1/organizations/{id}/matching/direct - Direct symbiosis matches
* GET /api/v1/users/me/organizations - User organizations
* POST /api/v1/proposals/{id}/status - Update proposal status
- Add complete proposal domain model, repository, and service layers
- Create database migration for proposals table
- Fix CLI server command registration issue
API Documentation:
- Add comprehensive proposals.md API documentation
- Update README.md with Users and Proposals API sections
- Document all request/response formats, error codes, and business rules
Code Quality:
- Follow existing Go backend architecture patterns
- Add proper error handling and validation
- Match frontend expected response schemas
- Maintain clean separation of concerns (handler -> service -> repository)
193 lines
6.3 KiB
Go
193 lines
6.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
"bugulma/backend/internal/financial"
|
|
)
|
|
|
|
// EconomicService provides high-level economic analysis services
|
|
type EconomicService struct {
|
|
calculator financial.Calculator
|
|
}
|
|
|
|
// NewEconomicService creates a new economic service
|
|
func NewEconomicService(calculator financial.Calculator) *EconomicService {
|
|
return &EconomicService{
|
|
calculator: calculator,
|
|
}
|
|
}
|
|
|
|
// AnalyzeMatch performs comprehensive economic analysis for a resource flow match
|
|
func (es *EconomicService) AnalyzeMatch(
|
|
ctx context.Context,
|
|
source, target *domain.ResourceFlow,
|
|
distanceKm float64,
|
|
) (*financial.EconomicAnalysis, error) {
|
|
|
|
// Extract resource flow data
|
|
data, err := es.extractResourceFlowData(source, target, distanceKm)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to extract resource flow data: %w", err)
|
|
}
|
|
|
|
// Get default assumptions (could be made configurable per organization/client)
|
|
assumptions := es.getDefaultAssumptions()
|
|
|
|
// Perform basic economic analysis first
|
|
analysis, err := es.calculator.Calculate(financial.AnalysisTypeBasic, data, assumptions)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to perform economic analysis: %w", err)
|
|
}
|
|
|
|
// Type assert to get the EconomicAnalysis
|
|
basicAnalysis, ok := analysis.(*financial.EconomicAnalysis)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected analysis type returned for basic analysis: %T", analysis)
|
|
}
|
|
|
|
return basicAnalysis, nil
|
|
}
|
|
|
|
// AnalyzeAdvancedMatch performs comprehensive advanced economic analysis for a resource flow match
|
|
func (es *EconomicService) AnalyzeAdvancedMatch(
|
|
ctx context.Context,
|
|
source, target *domain.ResourceFlow,
|
|
distanceKm float64,
|
|
) (*financial.AdvancedEconomicAnalysis, error) {
|
|
|
|
// Extract resource flow data
|
|
data, err := es.extractResourceFlowData(source, target, distanceKm)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to extract resource flow data: %w", err)
|
|
}
|
|
|
|
// Get default assumptions (could be made configurable per organization/client)
|
|
assumptions := es.getDefaultAssumptions()
|
|
|
|
// Perform advanced economic analysis
|
|
analysis, err := es.calculator.Calculate(financial.AnalysisTypeAdvanced, data, assumptions)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to perform advanced economic analysis: %w", err)
|
|
}
|
|
|
|
// Type assert to get the AdvancedEconomicAnalysis
|
|
advancedAnalysis, ok := analysis.(*financial.AdvancedEconomicAnalysis)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected analysis type returned for advanced analysis")
|
|
}
|
|
|
|
return advancedAnalysis, nil
|
|
}
|
|
|
|
// AnalyzeMatchWithSensitivity performs economic analysis with sensitivity analysis
|
|
func (es *EconomicService) AnalyzeMatchWithSensitivity(
|
|
ctx context.Context,
|
|
source, target *domain.ResourceFlow,
|
|
distanceKm float64,
|
|
) (*financial.EconomicAnalysis, error) {
|
|
|
|
data, err := es.extractResourceFlowData(source, target, distanceKm)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to extract resource flow data: %w", err)
|
|
}
|
|
|
|
assumptions := es.getDefaultAssumptions()
|
|
|
|
analysis, err := es.calculator.Calculate(financial.AnalysisTypeSensitivity, data, assumptions)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to perform sensitivity analysis: %w", err)
|
|
}
|
|
|
|
// Type assert to get the EconomicAnalysis
|
|
sensitivityAnalysis, ok := analysis.(*financial.EconomicAnalysis)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected analysis type returned for sensitivity analysis: %T", analysis)
|
|
}
|
|
|
|
return sensitivityAnalysis, nil
|
|
}
|
|
|
|
// extractResourceFlowData extracts financial data from resource flow entities
|
|
func (es *EconomicService) extractResourceFlowData(
|
|
source, target *domain.ResourceFlow,
|
|
distanceKm float64,
|
|
) (*financial.ResourceFlowData, error) {
|
|
|
|
var sourceEcon, targetEcon domain.EconomicData
|
|
if err := json.Unmarshal(source.EconomicData, &sourceEcon); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal source economic data: %w", err)
|
|
}
|
|
if err := json.Unmarshal(target.EconomicData, &targetEcon); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal target economic data: %w", err)
|
|
}
|
|
|
|
var sourceQty domain.Quantity
|
|
if err := json.Unmarshal(source.Quantity, &sourceQty); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal source quantity: %w", err)
|
|
}
|
|
|
|
// Convert to annual volume
|
|
annualVolume := es.calculateAnnualVolume(sourceQty.Amount, sourceQty.TemporalUnit)
|
|
|
|
return &financial.ResourceFlowData{
|
|
ResourceType: string(source.Type),
|
|
DistanceKm: distanceKm,
|
|
AnnualVolume: annualVolume,
|
|
CostIn: targetEcon.CostIn, // Buyer's cost
|
|
CostOut: sourceEcon.CostOut, // Seller's cost
|
|
TemporalUnit: string(sourceQty.TemporalUnit),
|
|
}, nil
|
|
}
|
|
|
|
// calculateAnnualVolume converts temporal unit to annual volume
|
|
func (es *EconomicService) calculateAnnualVolume(amount float64, unit domain.TemporalUnit) float64 {
|
|
multipliers := map[domain.TemporalUnit]float64{
|
|
domain.UnitPerSecond: 31536000, // 365 * 24 * 3600
|
|
domain.UnitPerMinute: 525600, // 365 * 24 * 60
|
|
domain.UnitPerHour: 8760, // 365 * 24
|
|
domain.UnitPerDay: 365,
|
|
domain.UnitPerWeek: 52,
|
|
domain.UnitPerMonth: 12,
|
|
domain.UnitPerYear: 1,
|
|
domain.UnitContinuous: 1, // Already annual
|
|
}
|
|
|
|
multiplier, exists := multipliers[unit]
|
|
if !exists {
|
|
multiplier = 1 // Default to annual
|
|
}
|
|
|
|
return amount * multiplier
|
|
}
|
|
|
|
// getDefaultAssumptions returns default economic assumptions
|
|
func (es *EconomicService) getDefaultAssumptions() *financial.EconomicAssumptions {
|
|
return &financial.EconomicAssumptions{
|
|
DiscountRate: 0.08, // 8%
|
|
ProjectLifeYears: 10,
|
|
OperatingHoursYear: 8760, // 24/7 operation
|
|
MaintenanceCostFactor: 0.02, // 2% of CAPEX
|
|
EnergyCostInflation: 0.03, // 3% inflation
|
|
InsuranceCostPct: 0.005, // 0.5% of CAPEX
|
|
RegulatoryCostBuffer: 0.1, // 10% buffer
|
|
ContingencyPct: 0.15, // 15% contingency
|
|
}
|
|
}
|
|
|
|
// GetViabilitySummary provides a high-level viability assessment
|
|
func (es *EconomicService) GetViabilitySummary(analysis *financial.EconomicAnalysis) string {
|
|
if analysis.IsViable && analysis.ConfidenceScore > 0.8 {
|
|
return "Highly viable - strong economic case with low risk"
|
|
} else if analysis.IsViable && analysis.ConfidenceScore > 0.6 {
|
|
return "Viable - positive economics with moderate confidence"
|
|
} else if analysis.IsViable {
|
|
return "Marginally viable - meets basic criteria but high uncertainty"
|
|
} else {
|
|
return "Not viable - negative economic indicators"
|
|
}
|
|
}
|