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,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ class DebuggingTest < Minitest::Test
6
+ def setup
7
+ @model = FinIt.define(default_currency: 'USD') do
8
+ config do
9
+ start_date 2024
10
+ end
11
+
12
+ account :checking do
13
+ type :asset
14
+ currency 'USD'
15
+ opening_balance 10_000
16
+ end
17
+
18
+ account :savings do
19
+ type :asset
20
+ currency 'USD'
21
+ opening_balance 5_000
22
+ end
23
+
24
+ account :credit_card do
25
+ type :liability
26
+ currency 'USD'
27
+ opening_balance(-2_000)
28
+ end
29
+
30
+ category :income, type: :income do
31
+ variable :salary, currency: 'USD', frequency: :monthly, account: :checking do
32
+ value 5_000, start_date: "2024-01-01", end_date: "2024-12-31"
33
+ end
34
+ end
35
+
36
+ category :expenses, type: :expense do
37
+ variable :rent, currency: 'USD', frequency: :monthly, account: :credit_card do
38
+ value 2_000, start_date: "2024-01-01", end_date: "2024-12-31"
39
+ end
40
+
41
+ calculated :utilities,
42
+ formula: "500",
43
+ frequency: :monthly,
44
+ account: :credit_card,
45
+ start_date: "2024-01-01",
46
+ end_date: "2024-12-31" do
47
+ description "Monthly utilities"
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def test_print_account_transactions_outputs_correctly
54
+ output = StringIO.new
55
+ @model.print_account_transactions(:checking,
56
+ start_date: Date.new(2024, 1, 1),
57
+ end_date: Date.new(2024, 2, 28),
58
+ io: output
59
+ )
60
+
61
+ result = output.string
62
+ assert_includes result, "TRANSACTIONS FOR ACCOUNT: CHECKING"
63
+ assert_includes result, "Opening Balance: $10,000.00"
64
+ assert_includes result, "salary"
65
+ assert_includes result, "$20,000.00" # Ending balance
66
+ end
67
+
68
+ def test_print_accounts_summary_outputs_correctly
69
+ output = StringIO.new
70
+ @model.print_accounts_summary(
71
+ as_of_date: Date.new(2024, 2, 28),
72
+ include_hashes: false,
73
+ io: output
74
+ )
75
+
76
+ result = output.string
77
+ assert_includes result, "ACCOUNT SUMMARY"
78
+ assert_includes result, "ASSETS"
79
+ assert_includes result, "LIABILITYS"
80
+ assert_includes result, "EQUITYS"
81
+ assert_includes result, "BALANCE SHEET VALIDATION"
82
+ end
83
+
84
+ def test_print_variables_summary_outputs_correctly
85
+ output = StringIO.new
86
+ @model.print_variables_summary(
87
+ as_of_date: Date.new(2024, 2, 28),
88
+ io: output
89
+ )
90
+
91
+ result = output.string
92
+ assert_includes result, "VARIABLE VALUES & HASHES"
93
+ assert_includes result, "salary"
94
+ assert_includes result, "rent"
95
+ assert_includes result, "utilities"
96
+ end
97
+
98
+ def test_print_accounts_summary_with_hashes_includes_variable_info
99
+ output = StringIO.new
100
+ @model.print_accounts_summary(
101
+ as_of_date: Date.new(2024, 2, 28),
102
+ include_hashes: true,
103
+ io: output
104
+ )
105
+
106
+ result = output.string
107
+ assert_includes result, "VARIABLE INFORMATION & HASHES"
108
+ assert_includes result, "INCOME"
109
+ assert_includes result, "EXPENSES"
110
+ end
111
+ end
112
+
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ class DriverVariablesTest < Minitest::Test
6
+ def setup
7
+ @model = FinIt.define(default_currency: 'USD') do
8
+ config do
9
+ start_date 2024
10
+ end
11
+
12
+ account :company_account do
13
+ type :asset
14
+ currency 'USD'
15
+ end
16
+
17
+ # Driver that changes over time
18
+ category :drivers, type: :driver do
19
+ variable :employee_count do
20
+ value 10, start_date: "2024-01-01", end_date: "2024-06-30"
21
+ value 15, start_date: "2024-07-01", end_date: "2024-12-31"
22
+ description "Number of employees"
23
+ end
24
+
25
+ variable :cost_per_employee do
26
+ value 5_000
27
+ description "Monthly cost per employee"
28
+ end
29
+ end
30
+
31
+ category :expenses, type: :expense do
32
+ # Monthly payroll paid on the 15th of each month
33
+ calculated :monthly_payroll,
34
+ formula: "employee_count * cost_per_employee",
35
+ frequency: :monthly,
36
+ payment_schedule: { day_of_month: 15 },
37
+ start_date: "2024-01-15",
38
+ account: :company_account do
39
+ description "Monthly payroll"
40
+ end
41
+
42
+ # Quarterly bonus paid on specific dates
43
+ calculated :quarterly_bonus,
44
+ formula: "employee_count * 1000",
45
+ frequency: :quarterly,
46
+ payment_schedule: { months: [1, 4, 7, 10], day: 15 },
47
+ start_date: "2024-01-15",
48
+ end_date: "2024-12-31",
49
+ account: :company_account do
50
+ description "Quarterly bonus"
51
+ end
52
+ end
53
+ end
54
+
55
+ @q2_date = Date.new(2024, 5, 15)
56
+ @q4_date = Date.new(2024, 10, 15)
57
+ end
58
+
59
+ def test_employee_count_q2
60
+ q2_employees = @model.calculator.calculate(:employee_count, date: @q2_date).to_i
61
+ assert_equal 10, q2_employees, "Employee count should be 10 in Q2"
62
+ end
63
+
64
+ def test_employee_count_q4
65
+ q4_employees = @model.calculator.calculate(:employee_count, date: @q4_date).to_i
66
+ assert_equal 15, q4_employees, "Employee count should be 15 in Q4"
67
+ end
68
+
69
+ def test_monthly_payroll_on_payment_date
70
+ # Feb 15 is a payment date
71
+ payroll = @model.calculator.calculate(:monthly_payroll, date: Date.new(2024, 2, 15), output_currency: 'USD')
72
+ assert payroll, "Monthly payroll should exist on payment date"
73
+ assert_in_delta 50_000, payroll.to_f, 0.01, "Monthly payroll should be $50,000 (10 employees × $5,000)"
74
+ end
75
+
76
+ def test_monthly_payroll_not_on_payment_date
77
+ # Feb 20 is NOT a payment date
78
+ payroll = @model.calculator.calculate(:monthly_payroll, date: Date.new(2024, 2, 20), output_currency: 'USD')
79
+ assert_nil payroll, "Monthly payroll should be nil on non-payment date"
80
+ end
81
+
82
+ def test_monthly_payroll_with_changed_employee_count
83
+ # July 15 - after employee count increased to 15
84
+ payroll = @model.calculator.calculate(:monthly_payroll, date: Date.new(2024, 7, 15), output_currency: 'USD')
85
+ assert payroll, "Monthly payroll should exist on payment date"
86
+ assert_in_delta 75_000, payroll.to_f, 0.01, "Monthly payroll should be $75,000 (15 employees × $5,000)"
87
+ end
88
+
89
+ def test_quarterly_bonus_on_payment_date
90
+ # Jan 15 is a quarterly payment date
91
+ bonus = @model.calculator.calculate(:quarterly_bonus, date: Date.new(2024, 1, 15), output_currency: 'USD')
92
+ assert bonus, "Quarterly bonus should exist on payment date"
93
+ assert_in_delta 10_000, bonus.to_f, 0.01, "Quarterly bonus should be $10,000 (10 employees × $1,000)"
94
+ end
95
+
96
+ def test_quarterly_bonus_not_on_payment_date
97
+ # Feb 15 is NOT a quarterly payment date
98
+ bonus = @model.calculator.calculate(:quarterly_bonus, date: Date.new(2024, 2, 15), output_currency: 'USD')
99
+ assert_nil bonus, "Quarterly bonus should be nil on non-payment date"
100
+ end
101
+
102
+ def test_quarterly_bonus_on_october_payment_date
103
+ # Oct 15 is a quarterly payment date, with 15 employees
104
+ bonus = @model.calculator.calculate(:quarterly_bonus, date: Date.new(2024, 10, 15), output_currency: 'USD')
105
+ assert bonus, "Quarterly bonus should exist on payment date"
106
+ assert_in_delta 15_000, bonus.to_f, 0.01, "Quarterly bonus should be $15,000 (15 employees × $1,000)"
107
+ end
108
+ end
109
+