move tax type to enum
This commit is contained in:
parent
57b0811ecd
commit
f1e9321bdc
1 changed files with 25 additions and 21 deletions
|
|
@ -17,10 +17,27 @@ pub const BreakdownItem = struct {
|
||||||
weight: f64, // fraction of total (0.0 - 1.0)
|
weight: f64, // fraction of total (0.0 - 1.0)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Tax type classification for accounts.
|
||||||
|
pub const TaxType = enum {
|
||||||
|
taxable,
|
||||||
|
roth,
|
||||||
|
traditional,
|
||||||
|
hsa,
|
||||||
|
|
||||||
|
pub fn label(self: TaxType) []const u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.taxable => "Taxable",
|
||||||
|
.roth => "Roth (Post-Tax)",
|
||||||
|
.traditional => "Traditional (Pre-Tax)",
|
||||||
|
.hsa => "HSA (Triple Tax-Free)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Account tax type classification entry, parsed from accounts.srf.
|
/// Account tax type classification entry, parsed from accounts.srf.
|
||||||
pub const AccountTaxEntry = struct {
|
pub const AccountTaxEntry = struct {
|
||||||
account: []const u8,
|
account: []const u8,
|
||||||
tax_type: []const u8,
|
tax_type: TaxType,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parsed account metadata.
|
/// Parsed account metadata.
|
||||||
|
|
@ -31,7 +48,6 @@ pub const AccountMap = struct {
|
||||||
pub fn deinit(self: *AccountMap) void {
|
pub fn deinit(self: *AccountMap) void {
|
||||||
for (self.entries) |e| {
|
for (self.entries) |e| {
|
||||||
self.allocator.free(e.account);
|
self.allocator.free(e.account);
|
||||||
self.allocator.free(e.tax_type);
|
|
||||||
}
|
}
|
||||||
self.allocator.free(self.entries);
|
self.allocator.free(self.entries);
|
||||||
}
|
}
|
||||||
|
|
@ -40,22 +56,13 @@ pub const AccountMap = struct {
|
||||||
pub fn taxTypeFor(self: AccountMap, account: []const u8) []const u8 {
|
pub fn taxTypeFor(self: AccountMap, account: []const u8) []const u8 {
|
||||||
for (self.entries) |e| {
|
for (self.entries) |e| {
|
||||||
if (std.mem.eql(u8, e.account, account)) {
|
if (std.mem.eql(u8, e.account, account)) {
|
||||||
return taxTypeLabel(e.tax_type);
|
return e.tax_type.label();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Map raw tax_type strings to display labels.
|
|
||||||
fn taxTypeLabel(raw: []const u8) []const u8 {
|
|
||||||
if (std.mem.eql(u8, raw, "taxable")) return "Taxable";
|
|
||||||
if (std.mem.eql(u8, raw, "roth")) return "Roth (Post-Tax)";
|
|
||||||
if (std.mem.eql(u8, raw, "traditional")) return "Traditional (Pre-Tax)";
|
|
||||||
if (std.mem.eql(u8, raw, "hsa")) return "HSA (Triple Tax-Free)";
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse an accounts.srf file into an AccountMap.
|
/// Parse an accounts.srf file into an AccountMap.
|
||||||
/// Each record has: account::<NAME>,tax_type::<TYPE>
|
/// Each record has: account::<NAME>,tax_type::<TYPE>
|
||||||
pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !AccountMap {
|
pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !AccountMap {
|
||||||
|
|
@ -63,7 +70,6 @@ pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !Accoun
|
||||||
errdefer {
|
errdefer {
|
||||||
for (entries.items) |e| {
|
for (entries.items) |e| {
|
||||||
allocator.free(e.account);
|
allocator.free(e.account);
|
||||||
allocator.free(e.tax_type);
|
|
||||||
}
|
}
|
||||||
entries.deinit(allocator);
|
entries.deinit(allocator);
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +82,7 @@ pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !Accoun
|
||||||
const entry = record.to(AccountTaxEntry) catch continue;
|
const entry = record.to(AccountTaxEntry) catch continue;
|
||||||
try entries.append(allocator, .{
|
try entries.append(allocator, .{
|
||||||
.account = try allocator.dupe(u8, entry.account),
|
.account = try allocator.dupe(u8, entry.account),
|
||||||
.tax_type = try allocator.dupe(u8, entry.tax_type),
|
.tax_type = entry.tax_type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,13 +293,11 @@ test "parseAccountsFile" {
|
||||||
try std.testing.expectEqualStrings("Unknown", am.taxTypeFor("Nonexistent"));
|
try std.testing.expectEqualStrings("Unknown", am.taxTypeFor("Nonexistent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "taxTypeLabel" {
|
test "TaxType.label" {
|
||||||
try std.testing.expectEqualStrings("Taxable", taxTypeLabel("taxable"));
|
try std.testing.expectEqualStrings("Taxable", TaxType.taxable.label());
|
||||||
try std.testing.expectEqualStrings("Roth (Post-Tax)", taxTypeLabel("roth"));
|
try std.testing.expectEqualStrings("Roth (Post-Tax)", TaxType.roth.label());
|
||||||
try std.testing.expectEqualStrings("Traditional (Pre-Tax)", taxTypeLabel("traditional"));
|
try std.testing.expectEqualStrings("Traditional (Pre-Tax)", TaxType.traditional.label());
|
||||||
try std.testing.expectEqualStrings("HSA (Triple Tax-Free)", taxTypeLabel("hsa"));
|
try std.testing.expectEqualStrings("HSA (Triple Tax-Free)", TaxType.hsa.label());
|
||||||
// Unknown type returns raw string
|
|
||||||
try std.testing.expectEqualStrings("custom_type", taxTypeLabel("custom_type"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "mapToSortedBreakdown" {
|
test "mapToSortedBreakdown" {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue