-
Notifications
You must be signed in to change notification settings - Fork 0
/
Accounts.swift
102 lines (90 loc) · 3.9 KB
/
Accounts.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import ArgumentParser
import Foundation
import SwiftBeanCountModel
struct Accounts: FormattableLedgerCommand {
static var configuration = CommandConfiguration(abstract: "Print all accounts")
private static let dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd"
return dateFormatter
}()
@OptionGroup()
var ledgerOptions: LedgerCommandOptions
@Argument(help: "String to filter account names by.")
private var filter: String = ""
@OptionGroup()
var formatOptions: FormattableCommandOptions
@OptionGroup()
var colorOptions: ColorizedCommandOptions
@ArgumentParser.Flag(inversion: .prefixedNo, help: "Show open accounts.")
private var open = true
@ArgumentParser.Flag(inversion: .prefixedNo, help: "Show closed accounts.")
private var closed = true
@ArgumentParser.Flag(inversion: .prefixedNo, help: "Show dates of account opening and closing.")
private var dates = true
@ArgumentParser.Flag(inversion: .prefixedNo, help: "Show number of postings in each account.")
private var postings = false
@ArgumentParser.Flag(inversion: .prefixedNo, help: "Show the date of the last activity in each account.")
private var activity = false
@ArgumentParser.Flag(name: [.short, .long], help: "Display the number of accounts.")
private var count = false
func validate() throws {
if formatOptions.format == .csv && count {
throw ValidationError("Cannot print count in csv format. Please remove count flag or specify another format.")
}
}
func getResult(from ledger: Ledger, parsingDuration _: Double) -> [FormattableResult] {
var accounts = ledger.accounts.sorted { $0.name.fullName < $1.name.fullName }
if !filter.isEmpty { accounts = accounts.filter { $0.name.fullName.contains(filter) } }
if !closed { accounts = accounts.filter { $0.closing == nil || $0.closing! > Date() } }
if !open { accounts = accounts.filter { $0.closing != nil && $0.closing! < Date() } }
let values: [[String]] = accounts.map { account in
var result = [account.name.fullName]
if postings {
result.append(String(ledger.transactions.map { $0.postings.filter { $0.accountName == account.name }.count }.reduce(0) { $0 + $1 }))
}
if activity {
let transactionDates = ledger.transactions.compactMap { $0.postings.contains { $0.accountName == account.name } ? $0.metaData.date : nil }
let balanceDates = account.balances.map { $0.date }
let allDates = transactionDates + balanceDates + [account.opening] + [account.closing]
let dates = allDates.compactMap { $0 }.sorted(by: >)
result.append(dateString(dates.first))
}
if dates {
result.append(dateString(account.opening))
if closed {
result.append(dateString(account.closing))
}
}
return result
}
var footer: String?
if count {
footer = "\(accounts.count) Accounts"
}
return [FormattableResult(title: "Accounts", columns: columns(), values: values, footer: footer)]
}
private func columns() -> [String] {
var columns = ["Name"]
if postings {
columns.append("# Postings")
}
if activity {
columns.append("Last Activity")
}
if dates {
columns.append("Opening")
if closed {
columns.append("Closing")
}
}
return columns
}
private func dateString(_ date: Date?) -> String {
guard let date else {
return ""
}
return Self.dateFormatter.string(from: date)
}
}