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,226 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../test_helper"
|
|
4
|
+
|
|
5
|
+
class PeriodComparisonTest < 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
|
+
category :income, type: :income,
|
|
19
|
+
default_account: :checking,
|
|
20
|
+
defaults: { frequency: :monthly, start_date: "2024-01-01", end_date: "2024-12-31" } do
|
|
21
|
+
variable :sales do
|
|
22
|
+
value 5_000, start_date: "2024-01-01", end_date: "2024-03-31"
|
|
23
|
+
value 6_000, start_date: "2024-04-01", end_date: "2024-06-30"
|
|
24
|
+
value 7_000, start_date: "2024-07-01", end_date: "2024-09-30"
|
|
25
|
+
value 8_000, start_date: "2024-10-01", end_date: "2024-12-31"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
category :expenses, type: :expense,
|
|
30
|
+
default_account: :checking,
|
|
31
|
+
defaults: { frequency: :monthly, start_date: "2024-01-01", end_date: "2024-12-31" } do
|
|
32
|
+
variable :rent do
|
|
33
|
+
value 1_000
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
variable :utilities do
|
|
37
|
+
value 200
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_period_comparison_basic
|
|
44
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
45
|
+
@model,
|
|
46
|
+
periods: [
|
|
47
|
+
{ name: "Q1 2024", start_date: "2024-01-01", end_date: "2024-03-31" },
|
|
48
|
+
{ name: "Q2 2024", start_date: "2024-04-01", end_date: "2024-06-30" }
|
|
49
|
+
],
|
|
50
|
+
metrics: [:net_income, :total_revenue],
|
|
51
|
+
output_currency: 'USD'
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
data = comparison.generate
|
|
55
|
+
|
|
56
|
+
assert_equal "PeriodComparison", data[:report_type]
|
|
57
|
+
assert data[:metadata]
|
|
58
|
+
assert data[:periods]
|
|
59
|
+
assert data[:variances]
|
|
60
|
+
assert_equal 2, data[:periods].length
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_period_comparison_metadata
|
|
64
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
65
|
+
@model,
|
|
66
|
+
periods: [
|
|
67
|
+
{ name: "Q1", start_date: "2024-01-01", end_date: "2024-03-31" },
|
|
68
|
+
{ name: "Q2", start_date: "2024-04-01", end_date: "2024-06-30" }
|
|
69
|
+
],
|
|
70
|
+
metrics: [:net_income],
|
|
71
|
+
output_currency: 'USD'
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
data = comparison.generate
|
|
75
|
+
|
|
76
|
+
assert_equal 'USD', data[:metadata][:currency]
|
|
77
|
+
assert_equal 2, data[:metadata][:periods].length
|
|
78
|
+
assert data[:metadata][:normalized_metrics]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_period_comparison_quarterly
|
|
82
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
83
|
+
@model,
|
|
84
|
+
periods: [
|
|
85
|
+
{ name: "Q1 2024", start_date: "2024-01-01", end_date: "2024-03-31" },
|
|
86
|
+
{ name: "Q2 2024", start_date: "2024-04-01", end_date: "2024-06-30" },
|
|
87
|
+
{ name: "Q3 2024", start_date: "2024-07-01", end_date: "2024-09-30" },
|
|
88
|
+
{ name: "Q4 2024", start_date: "2024-10-01", end_date: "2024-12-31" }
|
|
89
|
+
],
|
|
90
|
+
metrics: [:net_income, :total_revenue, :total_expenses],
|
|
91
|
+
output_currency: 'USD'
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
data = comparison.generate
|
|
95
|
+
|
|
96
|
+
assert_equal 4, data[:periods].length
|
|
97
|
+
|
|
98
|
+
# Each period should have metrics
|
|
99
|
+
data[:periods].each do |period|
|
|
100
|
+
assert period[:name]
|
|
101
|
+
assert period[:start_date]
|
|
102
|
+
assert period[:end_date]
|
|
103
|
+
assert period[:metrics]
|
|
104
|
+
assert period[:metrics][:net_income]
|
|
105
|
+
assert period[:metrics][:total_revenue]
|
|
106
|
+
assert period[:metrics][:total_expenses]
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_period_comparison_variances
|
|
111
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
112
|
+
@model,
|
|
113
|
+
periods: [
|
|
114
|
+
{ name: "Q1", start_date: "2024-01-01", end_date: "2024-03-31" },
|
|
115
|
+
{ name: "Q2", start_date: "2024-04-01", end_date: "2024-06-30" }
|
|
116
|
+
],
|
|
117
|
+
metrics: [:total_revenue],
|
|
118
|
+
output_currency: 'USD'
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
data = comparison.generate
|
|
122
|
+
|
|
123
|
+
# First period has no variance (nil)
|
|
124
|
+
assert_nil data[:variances][0][:variances]
|
|
125
|
+
|
|
126
|
+
# Second period has variance
|
|
127
|
+
assert data[:variances][1][:variances]
|
|
128
|
+
assert data[:variances][1][:variances][:total_revenue]
|
|
129
|
+
assert data[:variances][1][:variances][:total_revenue][:absolute]
|
|
130
|
+
assert data[:variances][1][:variances][:total_revenue][:percentage]
|
|
131
|
+
|
|
132
|
+
# Q2 revenue should be higher than Q1 (6000 vs 5000)
|
|
133
|
+
assert data[:variances][1][:variances][:total_revenue][:absolute] > 0
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def test_period_comparison_console_output
|
|
137
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
138
|
+
@model,
|
|
139
|
+
periods: [
|
|
140
|
+
{ name: "Q1 2024", start_date: "2024-01-01", end_date: "2024-03-31" },
|
|
141
|
+
{ name: "Q2 2024", start_date: "2024-04-01", end_date: "2024-06-30" }
|
|
142
|
+
],
|
|
143
|
+
metrics: [:net_income, :total_revenue],
|
|
144
|
+
output_currency: 'USD'
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
output = capture_io do
|
|
148
|
+
comparison.output(FinIt::Outputs::ConsoleOutput)
|
|
149
|
+
end.first
|
|
150
|
+
|
|
151
|
+
assert_match(/PERIOD COMPARISON/, output)
|
|
152
|
+
assert_match(/Q1 2024/, output)
|
|
153
|
+
assert_match(/Q2 2024/, output)
|
|
154
|
+
assert_match(/Net Income/, output)
|
|
155
|
+
assert_match(/Total Revenue/, output)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def test_period_comparison_normalized_metrics
|
|
159
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
160
|
+
@model,
|
|
161
|
+
periods: [
|
|
162
|
+
{ name: "Q1", start_date: "2024-01-01", end_date: "2024-03-31" }
|
|
163
|
+
],
|
|
164
|
+
metrics: [:net_income, :total_revenue],
|
|
165
|
+
output_currency: 'USD'
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# Test normalized_metrics accessor
|
|
169
|
+
normalized = comparison.normalized_metrics
|
|
170
|
+
assert_equal 2, normalized.length
|
|
171
|
+
assert_equal :net_income, normalized[0][:variable]
|
|
172
|
+
assert_equal "Net Income", normalized[0][:label]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def test_period_comparison_with_date_objects
|
|
176
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
177
|
+
@model,
|
|
178
|
+
periods: [
|
|
179
|
+
{ name: "Q1", start_date: Date.new(2024, 1, 1), end_date: Date.new(2024, 3, 31) },
|
|
180
|
+
{ name: "Q2", start_date: Date.new(2024, 4, 1), end_date: Date.new(2024, 6, 30) }
|
|
181
|
+
],
|
|
182
|
+
metrics: [:net_income],
|
|
183
|
+
output_currency: 'USD'
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
data = comparison.generate
|
|
187
|
+
|
|
188
|
+
assert_equal Date.new(2024, 1, 1), data[:periods][0][:start_date]
|
|
189
|
+
assert_equal Date.new(2024, 3, 31), data[:periods][0][:end_date]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_currency_alias
|
|
193
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
194
|
+
@model,
|
|
195
|
+
periods: [{ name: "Q1", start_date: "2024-01-01", end_date: "2024-03-31" }],
|
|
196
|
+
metrics: [:net_income],
|
|
197
|
+
output_currency: 'EUR'
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
assert_equal 'EUR', comparison.currency
|
|
201
|
+
assert_equal 'EUR', comparison.output_currency
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def test_period_comparison_multiple_metrics
|
|
205
|
+
comparison = FinIt::Reports::PeriodComparison.new(
|
|
206
|
+
@model,
|
|
207
|
+
periods: [
|
|
208
|
+
{ name: "Q1", start_date: "2024-01-01", end_date: "2024-03-31" },
|
|
209
|
+
{ name: "Q2", start_date: "2024-04-01", end_date: "2024-06-30" }
|
|
210
|
+
],
|
|
211
|
+
metrics: [:net_income, :total_revenue, :total_expenses, :ending_cash, :beginning_cash],
|
|
212
|
+
output_currency: 'USD'
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
data = comparison.generate
|
|
216
|
+
|
|
217
|
+
# All metrics should be calculated for each period
|
|
218
|
+
data[:periods].each do |period|
|
|
219
|
+
assert period[:metrics].key?(:net_income)
|
|
220
|
+
assert period[:metrics].key?(:total_revenue)
|
|
221
|
+
assert period[:metrics].key?(:total_expenses)
|
|
222
|
+
assert period[:metrics].key?(:ending_cash)
|
|
223
|
+
assert period[:metrics].key?(:beginning_cash)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../test_helper"
|
|
4
|
+
|
|
5
|
+
class RestaurantModelTest < 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 :operating_account do
|
|
13
|
+
type :asset
|
|
14
|
+
currency 'USD'
|
|
15
|
+
opening_balance 50_000
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Driver variables
|
|
19
|
+
category :drivers, type: :driver do
|
|
20
|
+
variable :number_of_tables do
|
|
21
|
+
value 20, start_date: "2024-01-01", end_date: "2024-06-30"
|
|
22
|
+
value 25, start_date: "2024-07-01", end_date: "2024-12-31"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
variable :tables_turned_per_day do
|
|
26
|
+
value 2.5, start_date: "2024-01-01", end_date: "2024-03-31"
|
|
27
|
+
value 3.0, start_date: "2024-04-01", end_date: "2024-12-31"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
variable :revenue_per_table do
|
|
31
|
+
value 85, start_date: "2024-01-01", end_date: "2024-05-31"
|
|
32
|
+
value 95, start_date: "2024-06-01", end_date: "2024-12-31"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
variable :operating_days_per_month do
|
|
36
|
+
value 28
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
variable :food_cost_percentage do
|
|
40
|
+
value 0.30
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
variable :labor_cost_percentage do
|
|
44
|
+
value 0.35
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
variable :beverage_percentage_of_food do
|
|
48
|
+
value 0.25
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
variable :takeout_orders_per_day do
|
|
52
|
+
value 45, start_date: "2024-01-01", end_date: "2024-06-30"
|
|
53
|
+
value 60, start_date: "2024-07-01", end_date: "2024-12-31"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
variable :takeout_revenue_per_order do
|
|
57
|
+
value 35
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
variable :catering_events_per_month do
|
|
61
|
+
value 8, start_date: "2024-01-01", end_date: "2024-05-31"
|
|
62
|
+
value 12, start_date: "2024-06-01", end_date: "2024-12-31"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
variable :catering_revenue_per_event do
|
|
66
|
+
value 1_200
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Income categories - using type inheritance, default_account, and defaults
|
|
71
|
+
category :revenue, type: :income,
|
|
72
|
+
default_account: :operating_account,
|
|
73
|
+
defaults: { frequency: :monthly, start_date: "2024-01-01", end_date: "2024-12-31" } do
|
|
74
|
+
|
|
75
|
+
category :dine_in do # inherits type: :income, default_account, and defaults
|
|
76
|
+
calculated :dine_in_revenue,
|
|
77
|
+
formula: "number_of_tables * tables_turned_per_day * revenue_per_table * operating_days_per_month"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
category :takeout do # inherits type: :income, default_account, and defaults
|
|
81
|
+
calculated :takeout_revenue,
|
|
82
|
+
formula: "takeout_orders_per_day * takeout_revenue_per_order * operating_days_per_month"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
category :catering do # inherits type: :income, default_account, and defaults
|
|
86
|
+
calculated :catering_revenue,
|
|
87
|
+
formula: "catering_events_per_month * catering_revenue_per_event"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
category :beverages do # inherits type: :income, default_account, and defaults
|
|
91
|
+
calculated :beverage_revenue,
|
|
92
|
+
formula: "(dine_in_revenue + takeout_revenue) * beverage_percentage_of_food"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
calculated :total_revenue,
|
|
96
|
+
formula: "dine_in_revenue + takeout_revenue + catering_revenue + beverage_revenue"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Expense categories - using type inheritance, default_account, and defaults
|
|
100
|
+
category :expenses, type: :expense,
|
|
101
|
+
default_account: :operating_account,
|
|
102
|
+
defaults: { frequency: :monthly, start_date: "2024-01-01", end_date: "2024-12-31" } do
|
|
103
|
+
|
|
104
|
+
category :cogs do # inherits type: :expense, default_account, and defaults
|
|
105
|
+
calculated :food_cogs,
|
|
106
|
+
formula: "(dine_in_revenue + takeout_revenue) * food_cost_percentage"
|
|
107
|
+
|
|
108
|
+
calculated :beverage_cogs,
|
|
109
|
+
formula: "beverage_revenue * 0.20"
|
|
110
|
+
|
|
111
|
+
calculated :total_cogs,
|
|
112
|
+
formula: "food_cogs + beverage_cogs"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
category :labor do # inherits type: :expense, default_account, and defaults
|
|
116
|
+
calculated :labor_costs,
|
|
117
|
+
formula: "total_revenue * labor_cost_percentage"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
category :fixed_expenses do # inherits type: :expense, default_account, and defaults
|
|
121
|
+
variable :rent, currency: 'USD' do
|
|
122
|
+
value 8_000, start_date: "2024-01-01", end_date: "2024-12-31"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
@test_date = Date.new(2024, 2, 15)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_driver_variables_exist
|
|
132
|
+
assert @model.calculator.variable_names.include?(:number_of_tables)
|
|
133
|
+
assert @model.calculator.variable_names.include?(:food_cost_percentage)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def test_dine_in_revenue_calculation
|
|
137
|
+
# Q1: 20 tables × 2.5 turns × $85 per table × 28 days = $119,000
|
|
138
|
+
revenue = @model.calculator.calculate(:dine_in_revenue, date: @test_date, period_type: :monthly)
|
|
139
|
+
assert revenue
|
|
140
|
+
expected = 20 * 2.5 * 85 * 28
|
|
141
|
+
assert_in_delta expected, revenue.to_f, 1.0
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def test_takeout_revenue_calculation
|
|
145
|
+
# Q1: 45 orders × $35 × 28 days = $44,100
|
|
146
|
+
revenue = @model.calculator.calculate(:takeout_revenue, date: @test_date, period_type: :monthly)
|
|
147
|
+
assert revenue
|
|
148
|
+
expected = 45 * 35 * 28
|
|
149
|
+
assert_in_delta expected, revenue.to_f, 1.0
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def test_catering_revenue_calculation
|
|
153
|
+
# Q1: 8 events × $1,200 = $9,600
|
|
154
|
+
revenue = @model.calculator.calculate(:catering_revenue, date: @test_date, period_type: :monthly)
|
|
155
|
+
assert revenue
|
|
156
|
+
expected = 8 * 1_200
|
|
157
|
+
assert_in_delta expected, revenue.to_f, 1.0
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def test_beverage_revenue_calculation
|
|
161
|
+
dine_in = @model.calculator.calculate(:dine_in_revenue, date: @test_date, period_type: :monthly)
|
|
162
|
+
takeout = @model.calculator.calculate(:takeout_revenue, date: @test_date, period_type: :monthly)
|
|
163
|
+
beverage = @model.calculator.calculate(:beverage_revenue, date: @test_date, period_type: :monthly)
|
|
164
|
+
|
|
165
|
+
assert beverage
|
|
166
|
+
expected = (dine_in.to_f + takeout.to_f) * 0.25
|
|
167
|
+
assert_in_delta expected, beverage.to_f, 1.0
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def test_total_revenue_sums_all_streams
|
|
171
|
+
total = @model.calculator.calculate(:total_revenue, date: @test_date, period_type: :monthly)
|
|
172
|
+
dine_in = @model.calculator.calculate(:dine_in_revenue, date: @test_date, period_type: :monthly)
|
|
173
|
+
takeout = @model.calculator.calculate(:takeout_revenue, date: @test_date, period_type: :monthly)
|
|
174
|
+
catering = @model.calculator.calculate(:catering_revenue, date: @test_date, period_type: :monthly)
|
|
175
|
+
beverage = @model.calculator.calculate(:beverage_revenue, date: @test_date, period_type: :monthly)
|
|
176
|
+
|
|
177
|
+
assert total
|
|
178
|
+
expected = dine_in.to_f + takeout.to_f + catering.to_f + beverage.to_f
|
|
179
|
+
assert_in_delta expected, total.to_f, 1.0
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def test_cogs_calculation
|
|
183
|
+
dine_in = @model.calculator.calculate(:dine_in_revenue, date: @test_date, period_type: :monthly)
|
|
184
|
+
takeout = @model.calculator.calculate(:takeout_revenue, date: @test_date, period_type: :monthly)
|
|
185
|
+
food_cogs = @model.calculator.calculate(:food_cogs, date: @test_date, period_type: :monthly)
|
|
186
|
+
|
|
187
|
+
assert food_cogs
|
|
188
|
+
expected = (dine_in.to_f + takeout.to_f) * 0.30
|
|
189
|
+
assert_in_delta expected, food_cogs.to_f, 1.0
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_total_cogs_sums_food_and_beverage
|
|
193
|
+
food_cogs = @model.calculator.calculate(:food_cogs, date: @test_date, period_type: :monthly)
|
|
194
|
+
beverage_cogs = @model.calculator.calculate(:beverage_cogs, date: @test_date, period_type: :monthly)
|
|
195
|
+
total_cogs = @model.calculator.calculate(:total_cogs, date: @test_date, period_type: :monthly)
|
|
196
|
+
|
|
197
|
+
assert total_cogs
|
|
198
|
+
expected = food_cogs.to_f + beverage_cogs.to_f
|
|
199
|
+
assert_in_delta expected, total_cogs.to_f, 1.0
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def test_labor_costs_calculation
|
|
203
|
+
total_revenue = @model.calculator.calculate(:total_revenue, date: @test_date, period_type: :monthly)
|
|
204
|
+
labor_costs = @model.calculator.calculate(:labor_costs, date: @test_date, period_type: :monthly)
|
|
205
|
+
|
|
206
|
+
assert labor_costs
|
|
207
|
+
expected = total_revenue.to_f * 0.35
|
|
208
|
+
assert_in_delta expected, labor_costs.to_f, 1.0
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def test_income_statement_generation
|
|
212
|
+
report = FinIt::Reports::IncomeStatement.new(
|
|
213
|
+
@model,
|
|
214
|
+
start_date: Date.new(2024, 2, 1),
|
|
215
|
+
end_date: Date.new(2024, 2, 28),
|
|
216
|
+
output_currency: 'USD'
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
report_data = report.generate
|
|
220
|
+
assert report_data
|
|
221
|
+
assert report_data[:sections][:income]
|
|
222
|
+
assert report_data[:sections][:expenses]
|
|
223
|
+
assert report_data[:totals]
|
|
224
|
+
end
|
|
225
|
+
end
|