fin_it 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/ARCHITECTURE.md +24 -0
  3. data/CHANGELOG.md +9 -0
  4. data/CONTRIBUTING.md +20 -0
  5. data/LICENSE +21 -0
  6. data/QUICKSTART.md +56 -0
  7. data/README.md +74 -0
  8. data/Rakefile +23 -0
  9. data/SECURITY.md +14 -0
  10. data/assets/fin_it_logo.png +0 -0
  11. data/lib/fin_it/account.rb +120 -0
  12. data/lib/fin_it/calculator/currency_conversion.rb +27 -0
  13. data/lib/fin_it/calculator/date_helpers.rb +53 -0
  14. data/lib/fin_it/calculator/variable_hashing.rb +120 -0
  15. data/lib/fin_it/calculator.rb +480 -0
  16. data/lib/fin_it/categories/category.rb +137 -0
  17. data/lib/fin_it/complex_model.rb +169 -0
  18. data/lib/fin_it/dsl/account_builder.rb +35 -0
  19. data/lib/fin_it/dsl/calculated_builder.rb +87 -0
  20. data/lib/fin_it/dsl/config_builder.rb +58 -0
  21. data/lib/fin_it/dsl/model_builder.rb +938 -0
  22. data/lib/fin_it/dsl/model_template_builder.rb +29 -0
  23. data/lib/fin_it/dsl/plan_builder.rb +52 -0
  24. data/lib/fin_it/dsl/project_inheritance_resolver.rb +46 -0
  25. data/lib/fin_it/dsl/variable_builder.rb +41 -0
  26. data/lib/fin_it/dsl.rb +13 -0
  27. data/lib/fin_it/engine.rb +15 -0
  28. data/lib/fin_it/financial_model/account_balances.rb +99 -0
  29. data/lib/fin_it/financial_model/account_hierarchy.rb +158 -0
  30. data/lib/fin_it/financial_model/category_values.rb +179 -0
  31. data/lib/fin_it/financial_model/currency_helpers.rb +14 -0
  32. data/lib/fin_it/financial_model/date_helpers.rb +58 -0
  33. data/lib/fin_it/financial_model/debugging.rb +353 -0
  34. data/lib/fin_it/financial_model/period_flows.rb +121 -0
  35. data/lib/fin_it/financial_model/validation.rb +85 -0
  36. data/lib/fin_it/financial_model/variable_matching.rb +49 -0
  37. data/lib/fin_it/financial_model.rb +395 -0
  38. data/lib/fin_it/model_template.rb +121 -0
  39. data/lib/fin_it/outputs/base_output.rb +51 -0
  40. data/lib/fin_it/outputs/console_output.rb +1528 -0
  41. data/lib/fin_it/outputs/monthly_console_output.rb +145 -0
  42. data/lib/fin_it/outputs/zaxcel_output.rb +1264 -0
  43. data/lib/fin_it/payment_schedule.rb +112 -0
  44. data/lib/fin_it/plan.rb +159 -0
  45. data/lib/fin_it/reports/balance_sheet.rb +638 -0
  46. data/lib/fin_it/reports/base_report.rb +239 -0
  47. data/lib/fin_it/reports/cash_flow_statement.rb +480 -0
  48. data/lib/fin_it/reports/custom_sheet.rb +436 -0
  49. data/lib/fin_it/reports/income_statement.rb +793 -0
  50. data/lib/fin_it/reports/period_comparison.rb +309 -0
  51. data/lib/fin_it/reports/scenario_comparison.rb +296 -0
  52. data/lib/fin_it/temporal_value.rb +349 -0
  53. data/lib/fin_it/transaction_generator/account_resolver.rb +118 -0
  54. data/lib/fin_it/transaction_generator/cache_management.rb +39 -0
  55. data/lib/fin_it/transaction_generator/date_generation.rb +57 -0
  56. data/lib/fin_it/transaction_generator.rb +357 -0
  57. data/lib/fin_it/version.rb +6 -0
  58. data/lib/fin_it.rb +27 -0
  59. data/test/fin_it/calculator_test.rb +109 -0
  60. data/test/fin_it/complex_model_test.rb +198 -0
  61. data/test/fin_it/debugging_test.rb +112 -0
  62. data/test/fin_it/driver_variables_test.rb +109 -0
  63. data/test/fin_it/dsl_test.rb +581 -0
  64. data/test/fin_it/financial_model_test.rb +196 -0
  65. data/test/fin_it/frequency_test.rb +51 -0
  66. data/test/fin_it/outputs/console_output_test.rb +249 -0
  67. data/test/fin_it/plan_test.rb +281 -0
  68. data/test/fin_it/reports/account_balance_test.rb +232 -0
  69. data/test/fin_it/reports/balance_sheet_test.rb +355 -0
  70. data/test/fin_it/reports/cash_flow_statement_test.rb +234 -0
  71. data/test/fin_it/reports/custom_sheet_test.rb +246 -0
  72. data/test/fin_it/reports/income_statement_test.rb +431 -0
  73. data/test/fin_it/reports/period_comparison_test.rb +226 -0
  74. data/test/fin_it/reports/restaurant_model_test.rb +225 -0
  75. data/test/fin_it/reports/scenario_comparison_test.rb +414 -0
  76. data/test/scripts/generate_demo_reports.rb +47 -0
  77. data/test/scripts/startup_saas_demo.rb +62 -0
  78. data/test/test_helper.rb +25 -0
  79. data/test/verify_accounting_equation.rb +91 -0
  80. metadata +264 -0
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FinIt
4
+ module Outputs
5
+ class MonthlyConsoleOutput < BaseOutput
6
+ def generate
7
+ currency = @report.output_currency
8
+ start_date = @report.start_date
9
+ end_date = @report.end_date
10
+
11
+ puts "=" * 100
12
+ puts "MONTHLY BREAKDOWN - #{@report.class.name.split('::').last.upcase}"
13
+ puts "Currency: #{currency} | Period: #{start_date.strftime('%B %Y')} to #{end_date.strftime('%B %Y')}"
14
+ puts "=" * 100
15
+
16
+ # Generate monthly data
17
+ monthly_data = calculate_monthly_data
18
+
19
+ # Display monthly table
20
+ display_monthly_table(monthly_data, currency)
21
+
22
+ # Display summary statistics
23
+ display_summary_statistics(monthly_data, currency)
24
+
25
+ nil
26
+ end
27
+
28
+ private
29
+
30
+ def calculate_monthly_data
31
+ data = []
32
+ current_date = @report.start_date
33
+
34
+ while current_date <= @report.end_date
35
+ month_data = calculate_month(current_date)
36
+ data << month_data
37
+ current_date = current_date >> 1 # Next month
38
+ end
39
+
40
+ data
41
+ end
42
+
43
+ def calculate_month(date)
44
+ # Get all categories for this month
45
+ income_total = 0
46
+ expense_total = 0
47
+
48
+ # Calculate income
49
+ income_categories = @report.model.categories.select { |c| c.type == :income }
50
+ income_categories.each do |cat|
51
+ value = cat.total(
52
+ date: date,
53
+ calculator: @report.model.calculator,
54
+ output_currency: @report.output_currency
55
+ )
56
+ income_total += value || 0
57
+ end
58
+
59
+ # Calculate expenses
60
+ expense_categories = @report.model.categories.select { |c| c.type == :expense }
61
+ expense_categories.each do |cat|
62
+ value = cat.total(
63
+ date: date,
64
+ calculator: @report.model.calculator,
65
+ output_currency: @report.output_currency
66
+ )
67
+ expense_total += value || 0
68
+ end
69
+
70
+ # Monthly values (divide annual by 12)
71
+ monthly_income = income_total / 12.0
72
+ monthly_expense = expense_total / 12.0
73
+ net_income = monthly_income - monthly_expense
74
+ savings_rate = monthly_income > 0 ? (net_income / monthly_income * 100) : 0
75
+
76
+ {
77
+ date: date,
78
+ income: monthly_income,
79
+ expenses: monthly_expense,
80
+ net_income: net_income,
81
+ savings_rate: savings_rate
82
+ }
83
+ end
84
+
85
+ def display_monthly_table(data, currency)
86
+ # Headers
87
+ puts "%-15s %15s %15s %15s %12s" % [
88
+ "Month", "Income", "Expenses", "Net Income", "Savings %"
89
+ ]
90
+ puts "-" * 100
91
+
92
+ # Monthly rows
93
+ data.each do |month|
94
+ puts "%-15s %15s %15s %15s %11.1f%%" % [
95
+ month[:date].strftime("%b %Y"),
96
+ format_currency(month[:income], currency),
97
+ format_currency(month[:expenses], currency),
98
+ format_currency(month[:net_income], currency),
99
+ month[:savings_rate]
100
+ ]
101
+ end
102
+
103
+ puts "-" * 100
104
+ end
105
+
106
+ def display_summary_statistics(data, currency)
107
+ # Calculate statistics
108
+ total_income = data.sum { |m| m[:income] }
109
+ total_expenses = data.sum { |m| m[:expenses] }
110
+ total_net = data.sum { |m| m[:net_income] }
111
+
112
+ avg_income = total_income / data.size
113
+ avg_expenses = total_expenses / data.size
114
+ avg_net = total_net / data.size
115
+ avg_savings_rate = data.sum { |m| m[:savings_rate] } / data.size
116
+
117
+ max_income_month = data.max_by { |m| m[:income] }
118
+ min_income_month = data.min_by { |m| m[:income] }
119
+ max_expense_month = data.max_by { |m| m[:expenses] }
120
+
121
+ puts "\nSUMMARY STATISTICS"
122
+ puts "=" * 100
123
+
124
+ puts "\nTOTALS (#{data.size} months):"
125
+ puts " Total Income: #{format_currency(total_income, currency)}"
126
+ puts " Total Expenses: #{format_currency(total_expenses, currency)}"
127
+ puts " Total Net: #{format_currency(total_net, currency)}"
128
+
129
+ puts "\nMONTHLY AVERAGES:"
130
+ puts " Avg Income: #{format_currency(avg_income, currency)}"
131
+ puts " Avg Expenses: #{format_currency(avg_expenses, currency)}"
132
+ puts " Avg Net Income: #{format_currency(avg_net, currency)}"
133
+ puts " Avg Savings: #{'%.1f' % avg_savings_rate}%"
134
+
135
+ puts "\nHIGHLIGHTS:"
136
+ puts " Highest Income: #{max_income_month[:date].strftime('%b %Y')} - #{format_currency(max_income_month[:income], currency)}"
137
+ puts " Lowest Income: #{min_income_month[:date].strftime('%b %Y')} - #{format_currency(min_income_month[:income], currency)}"
138
+ puts " Highest Expense: #{max_expense_month[:date].strftime('%b %Y')} - #{format_currency(max_expense_month[:expenses], currency)}"
139
+
140
+ puts "=" * 100
141
+ end
142
+ end
143
+ end
144
+ end
145
+