mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Reorganized funding program structure: moved standalone .md files into organized directories with PROGRAM_INFO.md and APPLICATION_SCOPE.md - Created budget files for selected priority programs: * EIC Accelerator: budget_breakdown.csv and budget_justification.md (€1.815M) * ZIM: budget_breakdown.csv and budget_justification.md (€465k) * DBU: budget_breakdown.csv and budget_justification.md (€152.5k) * LIFE Programme: budget_breakdown.csv and budget_justification.md (€1.815M) - Created team CV files for all selected programs (CV_Damir_Mukimov.md) - Added application documents structure: * funding/applications/budget/ - Master budget files and templates * funding/applications/team_cvs/ - Master CV and team expertise summary - Updated FUNDING_GAP_ANALYSIS.md to reflect completed documents - Added APPLICATION_REQUIREMENTS_REPORT.md with detailed requirements - Added PREPARATION_PRIORITY.md for application preparation workflow
229 lines
8.1 KiB
Go
229 lines
8.1 KiB
Go
package cli
|
||
|
||
import (
|
||
"fmt"
|
||
|
||
"github.com/damirmukimov/city_resource_graph/models/cost"
|
||
"github.com/damirmukimov/city_resource_graph/models/params"
|
||
"github.com/spf13/cobra"
|
||
)
|
||
|
||
// NewBudgetCmd creates a budget calculation command for funding applications
|
||
func NewBudgetCmd() *cobra.Command {
|
||
var durationMonths int
|
||
var phase string
|
||
var outputFormat string
|
||
|
||
cmd := &cobra.Command{
|
||
Use: "budget [params.yaml]",
|
||
Short: "Calculate detailed budget breakdown for funding applications",
|
||
Long: `Calculate detailed budget breakdown by category (personnel, infrastructure, etc.)
|
||
for funding applications. Supports different phases (MVP Foundation, MVP+, Full Program).
|
||
|
||
Examples:
|
||
# Calculate full program budget (18 months)
|
||
go run ./cmd budget params.yaml --duration 18
|
||
|
||
# Calculate MVP+ budget (6 months)
|
||
go run ./cmd budget params.yaml --duration 6 --phase MVP+
|
||
|
||
# Output as CSV
|
||
go run ./cmd budget params.yaml --duration 6 --format csv > budget.csv`,
|
||
Args: cobra.ExactArgs(1),
|
||
RunE: func(cmd *cobra.Command, args []string) error {
|
||
paramsFile := args[0]
|
||
return calculateBudget(paramsFile, durationMonths, phase, outputFormat)
|
||
},
|
||
}
|
||
|
||
cmd.Flags().IntVar(&durationMonths, "duration", 18, "Budget duration in months")
|
||
cmd.Flags().StringVar(&phase, "phase", "Full", "Budget phase: MVP-Foundation, MVP+, Full")
|
||
cmd.Flags().StringVar(&outputFormat, "format", "table", "Output format: table, csv, json")
|
||
|
||
return cmd
|
||
}
|
||
|
||
func calculateBudget(paramsFile string, durationMonths int, phase string, outputFormat string) error {
|
||
// Load parameters
|
||
p, err := params.LoadFromFile(paramsFile)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to load params: %w", err)
|
||
}
|
||
|
||
// Use first year's parameters for calculation
|
||
year := 1
|
||
if year > len(p.Time.Years) {
|
||
year = len(p.Time.Years)
|
||
}
|
||
|
||
// Calculate costs using the cost package (convert months to year fraction)
|
||
monthlyMultiplier := float64(durationMonths) / 12.0
|
||
|
||
engineering := float64(p.Costs.Engineers.GetYear(year)) * p.Costs.EngineerSalary * monthlyMultiplier
|
||
infrastructure := p.Costs.Infrastructure.GetYear(year) * monthlyMultiplier
|
||
marketingSales := p.Costs.MarketingSales.GetYear(year) * monthlyMultiplier
|
||
operations := p.Costs.Operations.GetYear(year) * monthlyMultiplier
|
||
|
||
// Create base cost breakdown
|
||
costBreakdown := cost.CostBreakdown{
|
||
Engineering: engineering,
|
||
Infrastructure: infrastructure,
|
||
MarketingSales: marketingSales,
|
||
Operations: operations,
|
||
Total: engineering + infrastructure + marketingSales + operations,
|
||
}
|
||
|
||
// Apply phase-specific adjustments
|
||
adjustedBudget := adjustBudgetForPhase(costBreakdown, phase, durationMonths, p)
|
||
|
||
// Output based on format
|
||
switch outputFormat {
|
||
case "json":
|
||
return outputBudgetJSON(adjustedBudget, phase, durationMonths)
|
||
case "csv":
|
||
return outputBudgetCSV(adjustedBudget, phase, durationMonths)
|
||
default:
|
||
return outputBudgetTable(adjustedBudget, phase, durationMonths, p)
|
||
}
|
||
}
|
||
|
||
func adjustBudgetForPhase(base cost.CostBreakdown, phase string, months int, p *params.Params) BudgetBreakdown {
|
||
// Base adjustments for different phases
|
||
switch phase {
|
||
case "MVP-Foundation":
|
||
// MVP Foundation: Smaller team, reduced infrastructure
|
||
return BudgetBreakdown{
|
||
Personnel: base.Engineering * 0.35, // Smaller team
|
||
Infrastructure: base.Infrastructure * 0.15, // MVP-scale infrastructure
|
||
Subcontracting: 25000, // Legal, accounting
|
||
Travel: 10000, // Essential travel
|
||
Marketing: 25000, // Basic marketing
|
||
Other: 15000, // Tools, communication
|
||
Total: 0,
|
||
}
|
||
case "MVP+":
|
||
// MVP+: Medium team, expanded infrastructure
|
||
return BudgetBreakdown{
|
||
Personnel: base.Engineering * 0.69, // Medium team
|
||
Infrastructure: base.Infrastructure * 0.32, // MVP+ infrastructure
|
||
Subcontracting: 45000,
|
||
Travel: 25000,
|
||
Marketing: 66000,
|
||
Other: 21000,
|
||
Total: 0,
|
||
}
|
||
default: // "Full"
|
||
// Full Program: Complete team, full infrastructure
|
||
// Add detailed breakdown
|
||
personnelTotal := base.Engineering + base.MarketingSales*0.3 // Add BD/domain experts
|
||
return BudgetBreakdown{
|
||
Personnel: personnelTotal,
|
||
Infrastructure: base.Infrastructure,
|
||
Subcontracting: 50000,
|
||
Travel: 40000,
|
||
Marketing: 85000,
|
||
Other: 5000,
|
||
Total: 0,
|
||
}
|
||
}
|
||
}
|
||
|
||
type BudgetBreakdown struct {
|
||
Personnel float64 `json:"personnel"`
|
||
Infrastructure float64 `json:"infrastructure"`
|
||
Subcontracting float64 `json:"subcontracting"`
|
||
Travel float64 `json:"travel"`
|
||
Marketing float64 `json:"marketing"`
|
||
Other float64 `json:"other"`
|
||
Total float64 `json:"total"`
|
||
}
|
||
|
||
func outputBudgetTable(budget BudgetBreakdown, phase string, months int, p *params.Params) error {
|
||
budget.Total = budget.Personnel + budget.Infrastructure + budget.Subcontracting +
|
||
budget.Travel + budget.Marketing + budget.Other
|
||
|
||
fmt.Printf("\nBudget Breakdown for %s Phase (%d months)\n", phase, months)
|
||
fmt.Println(string(make([]byte, 60)))
|
||
fmt.Printf("\nCategory Breakdown:\n\n")
|
||
fmt.Printf(" Personnel: €%12.2f (%5.1f%%)\n",
|
||
budget.Personnel, (budget.Personnel/budget.Total)*100)
|
||
fmt.Printf(" Infrastructure: €%12.2f (%5.1f%%)\n",
|
||
budget.Infrastructure, (budget.Infrastructure/budget.Total)*100)
|
||
fmt.Printf(" Subcontracting: €%12.2f (%5.1f%%)\n",
|
||
budget.Subcontracting, (budget.Subcontracting/budget.Total)*100)
|
||
fmt.Printf(" Travel: €%12.2f (%5.1f%%)\n",
|
||
budget.Travel, (budget.Travel/budget.Total)*100)
|
||
fmt.Printf(" Marketing: €%12.2f (%5.1f%%)\n",
|
||
budget.Marketing, (budget.Marketing/budget.Total)*100)
|
||
fmt.Printf(" Other: €%12.2f (%5.1f%%)\n",
|
||
budget.Other, (budget.Other/budget.Total)*100)
|
||
fmt.Printf("\n TOTAL: €%12.2f (100.0%%)\n", budget.Total)
|
||
|
||
fmt.Printf("\nModel Validation (from params.yaml):\n")
|
||
fmt.Printf(" Engineers (Year 1): %d × €%.0f = €%.0f/year\n",
|
||
p.Costs.Engineers.GetYear(1), p.Costs.EngineerSalary,
|
||
float64(p.Costs.Engineers.GetYear(1))*p.Costs.EngineerSalary)
|
||
fmt.Printf(" Adjusted for %d months: €%.0f\n",
|
||
months, float64(p.Costs.Engineers.GetYear(1))*p.Costs.EngineerSalary*float64(months)/12.0)
|
||
|
||
return nil
|
||
}
|
||
|
||
func outputBudgetCSV(budget BudgetBreakdown, phase string, months int) error {
|
||
budget.Total = budget.Personnel + budget.Infrastructure + budget.Subcontracting +
|
||
budget.Travel + budget.Marketing + budget.Other
|
||
|
||
fmt.Println("Category,Amount (EUR),Percentage")
|
||
fmt.Printf("Personnel,%.2f,%.2f%%\n", budget.Personnel, (budget.Personnel/budget.Total)*100)
|
||
fmt.Printf("Infrastructure,%.2f,%.2f%%\n", budget.Infrastructure, (budget.Infrastructure/budget.Total)*100)
|
||
fmt.Printf("Subcontracting,%.2f,%.2f%%\n", budget.Subcontracting, (budget.Subcontracting/budget.Total)*100)
|
||
fmt.Printf("Travel,%.2f,%.2f%%\n", budget.Travel, (budget.Travel/budget.Total)*100)
|
||
fmt.Printf("Marketing,%.2f,%.2f%%\n", budget.Marketing, (budget.Marketing/budget.Total)*100)
|
||
fmt.Printf("Other,%.2f,%.2f%%\n", budget.Other, (budget.Other/budget.Total)*100)
|
||
fmt.Printf("TOTAL,%.2f,100.00%%\n", budget.Total)
|
||
|
||
return nil
|
||
}
|
||
|
||
func outputBudgetJSON(budget BudgetBreakdown, phase string, months int) error {
|
||
budget.Total = budget.Personnel + budget.Infrastructure + budget.Subcontracting +
|
||
budget.Travel + budget.Marketing + budget.Other
|
||
|
||
jsonOutput := fmt.Sprintf(`{
|
||
"phase": "%s",
|
||
"duration_months": %d,
|
||
"budget": {
|
||
"personnel": %.2f,
|
||
"infrastructure": %.2f,
|
||
"subcontracting": %.2f,
|
||
"travel": %.2f,
|
||
"marketing": %.2f,
|
||
"other": %.2f,
|
||
"total": %.2f
|
||
},
|
||
"percentages": {
|
||
"personnel": %.2f,
|
||
"infrastructure": %.2f,
|
||
"subcontracting": %.2f,
|
||
"travel": %.2f,
|
||
"marketing": %.2f,
|
||
"other": %.2f
|
||
}
|
||
}
|
||
`,
|
||
phase, months,
|
||
budget.Personnel, budget.Infrastructure, budget.Subcontracting,
|
||
budget.Travel, budget.Marketing, budget.Other, budget.Total,
|
||
(budget.Personnel/budget.Total)*100,
|
||
(budget.Infrastructure/budget.Total)*100,
|
||
(budget.Subcontracting/budget.Total)*100,
|
||
(budget.Travel/budget.Total)*100,
|
||
(budget.Marketing/budget.Total)*100,
|
||
(budget.Other/budget.Total)*100,
|
||
)
|
||
|
||
fmt.Print(jsonOutput)
|
||
return nil
|
||
}
|
||
|