163 lines
5.7 KiB
Ruby
163 lines
5.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class FakeHledgerRunner
|
|
FIXTURES = Rails.root.join("plugins/hledger/spec/fixtures")
|
|
FILES = {
|
|
"accounts" => "accounts.json",
|
|
"balance_sheet" => "balance_sheet.json",
|
|
"income_statement" => "income_statement.json",
|
|
"equity" => "equity.json",
|
|
"transactions" => "transactions.json",
|
|
}.freeze
|
|
|
|
attr_reader :version
|
|
|
|
def initialize(version: "1.52.1")
|
|
@version = version
|
|
end
|
|
|
|
def available?
|
|
version.present?
|
|
end
|
|
|
|
def execute(argv, stdin_data: nil)
|
|
Hledger::Runner::Result.new(
|
|
success: true,
|
|
stdout: File.read(FIXTURES.join(FILES.fetch(detect(argv)))),
|
|
stderr: "",
|
|
exit_status: 0,
|
|
timed_out: false,
|
|
)
|
|
end
|
|
|
|
def detect(argv)
|
|
return "equity" if argv.include?("^equity:")
|
|
return "balance_sheet" if argv.include?("bs")
|
|
return "income_statement" if argv.include?("is")
|
|
return "transactions" if argv.include?("print")
|
|
|
|
"accounts"
|
|
end
|
|
end
|
|
|
|
RSpec.describe Hledger::ReportBuilder do
|
|
subject(:builder) { described_class.new(runner: FakeHledgerRunner.new) }
|
|
|
|
describe "accounts" do
|
|
it "returns the full account tree with aggregated totals" do
|
|
report = builder.build("accounts", journal: "journal")
|
|
|
|
expect(report["report_type"]).to eq("accounts")
|
|
rows = report["sections"].first["rows"]
|
|
|
|
expect(rows.map { |row| row["account"] }).to start_with(
|
|
"assets",
|
|
"assets:bank",
|
|
"assets:bank:checking",
|
|
)
|
|
expect(rows.map { |row| row["label"] }).to include("Assets", "Bank", "Checking")
|
|
|
|
assets = rows.find { |row| row["account"] == "assets" }
|
|
expect(assets["depth"]).to eq(0)
|
|
expect(assets["root"]).to be(true)
|
|
expect(assets["amounts"].first["display"]).to eq("1029.50 EUR")
|
|
|
|
equity = rows.find { |row| row["account"] == "equity" }
|
|
expect(equity["amounts"].first["display"]).to eq("(1000.00 EUR)")
|
|
expect(equity["amounts"].first["quantity"]).to eq("-1000.0")
|
|
|
|
checking = rows.find { |row| row["account"] == "assets:bank:checking" }
|
|
expect(checking["depth"]).to eq(2)
|
|
expect(checking["amounts"].first["display"]).to eq("1029.50 EUR")
|
|
expect(report["sections"].first["total"].first["display"]).to eq("0.00 EUR")
|
|
end
|
|
end
|
|
|
|
describe "balance sheet" do
|
|
it "returns sections, totals and net" do
|
|
report = builder.build("balance_sheet", journal: "journal")
|
|
|
|
expect(report["sections"].map { |s| s["title"] }).to eq(%w[Assets Liabilities])
|
|
assets = report["sections"].first
|
|
expect(assets["rows"].map { |row| row["label"] }).to eq(%w[Bank Checking])
|
|
expect(assets["rows"].map { |row| row["depth"] }).to eq([0, 1])
|
|
expect(assets["rows"].map { |row| row["root"] }).to eq([false, false])
|
|
expect(assets["rows"].last["amounts"].first["display"]).to eq("1029.50 EUR")
|
|
expect(assets["total"].first["display"]).to eq("1029.50 EUR")
|
|
expect(report["net"].first["display"]).to eq("1029.50 EUR")
|
|
end
|
|
end
|
|
|
|
describe "income statement" do
|
|
it "returns sections, totals and net" do
|
|
report = builder.build("income_statement", journal: "journal")
|
|
|
|
expect(report["sections"].map { |s| s["title"] }).to eq(%w[Revenues Expenses])
|
|
expect(report["sections"].first["rows"].map { |row| row["label"] }).to eq(["Donations"])
|
|
expect(report["sections"].first["rows"].map { |row| row["depth"] }).to eq([0])
|
|
expect(report["sections"].last["rows"].map { |row| row["label"] }).to eq(%w[Hosting Server])
|
|
expect(report["sections"].last["rows"].map { |row| row["depth"] }).to eq([0, 1])
|
|
expect(report["net"].first["display"]).to eq("29.50 EUR")
|
|
end
|
|
end
|
|
|
|
describe "equity" do
|
|
it "shows the equity account tree with each row's share" do
|
|
report = builder.build("equity", journal: "journal")
|
|
|
|
group = report["groups"].first
|
|
expect(group["commodity"]).to eq("EUR")
|
|
expect(group["total"]["quantity"]).to eq("1000.0")
|
|
expect(group["rows"].map { |row| row["label"] }).to eq(%w[Alice Bob])
|
|
expect(group["rows"].map { |row| row["depth"] }).to eq([0, 0])
|
|
expect(group["rows"].map { |row| row["percentage"] }).to eq(%w[60.00 40.00])
|
|
expect(group["rows"].first["amounts"].first["display"]).to eq("600.00 EUR")
|
|
end
|
|
end
|
|
|
|
describe "transactions" do
|
|
it "returns each transaction with its postings" do
|
|
report = builder.build("transactions", journal: "journal")
|
|
|
|
transactions = report["transactions"]
|
|
expect(transactions.map { |txn| txn["date"] }).to eq(%w[2024-01-01 2024-02-10 2024-03-15])
|
|
expect(transactions.map { |txn| txn["description"] }).to eq(
|
|
["Opening balances", "Hosting", "Donation"],
|
|
)
|
|
|
|
opening = transactions.first
|
|
expect(opening["postings"].map { |posting| posting["account"] }).to eq(
|
|
%w[assets:bank:checking equity:alice equity:bob],
|
|
)
|
|
expect(opening["postings"].first["amounts"].first["display"]).to eq("1000.00 EUR")
|
|
end
|
|
end
|
|
|
|
describe "period" do
|
|
it "serializes the requested period" do
|
|
report =
|
|
builder.build(
|
|
"income_statement",
|
|
journal: "journal",
|
|
begin_date: Date.new(2024, 1, 1),
|
|
end_date: Date.new(2024, 3, 15),
|
|
)
|
|
|
|
expect(report["period"]).to eq("begin" => "2024-01-01", "end" => "2024-03-15")
|
|
expect(report["meta"]["hledger_version"]).to eq("1.52.1")
|
|
end
|
|
end
|
|
|
|
it "raises for unsupported report types" do
|
|
expect { builder.build("nope", journal: "journal") }.to raise_error(Hledger::Error)
|
|
end
|
|
|
|
it "raises when hledger is unavailable" do
|
|
unavailable = FakeHledgerRunner.new(version: nil)
|
|
|
|
expect {
|
|
described_class.new(runner: unavailable).build("accounts", journal: "x")
|
|
}.to raise_error(Hledger::UnavailableError)
|
|
end
|
|
end
|