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.
- checksums.yaml +7 -0
- data/ARCHITECTURE.md +24 -0
- data/CHANGELOG.md +9 -0
- data/CONTRIBUTING.md +20 -0
- data/LICENSE +21 -0
- data/QUICKSTART.md +56 -0
- data/README.md +74 -0
- data/Rakefile +23 -0
- data/SECURITY.md +14 -0
- data/assets/fin_it_logo.png +0 -0
- data/lib/fin_it/account.rb +120 -0
- data/lib/fin_it/calculator/currency_conversion.rb +27 -0
- data/lib/fin_it/calculator/date_helpers.rb +53 -0
- data/lib/fin_it/calculator/variable_hashing.rb +120 -0
- data/lib/fin_it/calculator.rb +480 -0
- data/lib/fin_it/categories/category.rb +137 -0
- data/lib/fin_it/complex_model.rb +169 -0
- data/lib/fin_it/dsl/account_builder.rb +35 -0
- data/lib/fin_it/dsl/calculated_builder.rb +87 -0
- data/lib/fin_it/dsl/config_builder.rb +58 -0
- data/lib/fin_it/dsl/model_builder.rb +938 -0
- data/lib/fin_it/dsl/model_template_builder.rb +29 -0
- data/lib/fin_it/dsl/plan_builder.rb +52 -0
- data/lib/fin_it/dsl/project_inheritance_resolver.rb +46 -0
- data/lib/fin_it/dsl/variable_builder.rb +41 -0
- data/lib/fin_it/dsl.rb +13 -0
- data/lib/fin_it/engine.rb +15 -0
- data/lib/fin_it/financial_model/account_balances.rb +99 -0
- data/lib/fin_it/financial_model/account_hierarchy.rb +158 -0
- data/lib/fin_it/financial_model/category_values.rb +179 -0
- data/lib/fin_it/financial_model/currency_helpers.rb +14 -0
- data/lib/fin_it/financial_model/date_helpers.rb +58 -0
- data/lib/fin_it/financial_model/debugging.rb +353 -0
- data/lib/fin_it/financial_model/period_flows.rb +121 -0
- data/lib/fin_it/financial_model/validation.rb +85 -0
- data/lib/fin_it/financial_model/variable_matching.rb +49 -0
- data/lib/fin_it/financial_model.rb +395 -0
- data/lib/fin_it/model_template.rb +121 -0
- data/lib/fin_it/outputs/base_output.rb +51 -0
- data/lib/fin_it/outputs/console_output.rb +1528 -0
- data/lib/fin_it/outputs/monthly_console_output.rb +145 -0
- data/lib/fin_it/outputs/zaxcel_output.rb +1264 -0
- data/lib/fin_it/payment_schedule.rb +112 -0
- data/lib/fin_it/plan.rb +159 -0
- data/lib/fin_it/reports/balance_sheet.rb +638 -0
- data/lib/fin_it/reports/base_report.rb +239 -0
- data/lib/fin_it/reports/cash_flow_statement.rb +480 -0
- data/lib/fin_it/reports/custom_sheet.rb +436 -0
- data/lib/fin_it/reports/income_statement.rb +793 -0
- data/lib/fin_it/reports/period_comparison.rb +309 -0
- data/lib/fin_it/reports/scenario_comparison.rb +296 -0
- data/lib/fin_it/temporal_value.rb +349 -0
- data/lib/fin_it/transaction_generator/account_resolver.rb +118 -0
- data/lib/fin_it/transaction_generator/cache_management.rb +39 -0
- data/lib/fin_it/transaction_generator/date_generation.rb +57 -0
- data/lib/fin_it/transaction_generator.rb +357 -0
- data/lib/fin_it/version.rb +6 -0
- data/lib/fin_it.rb +27 -0
- data/test/fin_it/calculator_test.rb +109 -0
- data/test/fin_it/complex_model_test.rb +198 -0
- data/test/fin_it/debugging_test.rb +112 -0
- data/test/fin_it/driver_variables_test.rb +109 -0
- data/test/fin_it/dsl_test.rb +581 -0
- data/test/fin_it/financial_model_test.rb +196 -0
- data/test/fin_it/frequency_test.rb +51 -0
- data/test/fin_it/outputs/console_output_test.rb +249 -0
- data/test/fin_it/plan_test.rb +281 -0
- data/test/fin_it/reports/account_balance_test.rb +232 -0
- data/test/fin_it/reports/balance_sheet_test.rb +355 -0
- data/test/fin_it/reports/cash_flow_statement_test.rb +234 -0
- data/test/fin_it/reports/custom_sheet_test.rb +246 -0
- data/test/fin_it/reports/income_statement_test.rb +431 -0
- data/test/fin_it/reports/period_comparison_test.rb +226 -0
- data/test/fin_it/reports/restaurant_model_test.rb +225 -0
- data/test/fin_it/reports/scenario_comparison_test.rb +414 -0
- data/test/scripts/generate_demo_reports.rb +47 -0
- data/test/scripts/startup_saas_demo.rb +62 -0
- data/test/test_helper.rb +25 -0
- data/test/verify_accounting_equation.rb +91 -0
- 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
|
+
|