File Coverage

lib/Finance/Bank/SentinelBenefits/Csv401kConverter.pm
Criterion Covered Total %
statement 56 56 100.0
branch 8 8 100.0
condition 2 3 66.6
subroutine 12 12 100.0
pod 1 1 100.0
total 79 80 98.7


line stmt bran cond sub pod time code
1             package Finance::Bank::SentinelBenefits::Csv401kConverter;
2             $Finance::Bank::SentinelBenefits::Csv401kConverter::VERSION = '1.3';
3 4     4   219019 use Modern::Perl '2015';
  4         20094  
  4         28  
4 4     4   1164 use feature 'signatures';
  4         8  
  4         125  
5              
6 4     4   4032 use DateTime;
  4         2304550  
  4         202  
7 4     4   2699 use DateTime::Format::Flexible;
  4         1104239  
  4         53  
8              
9             =head1 NAME
10              
11              
12              
13             Finance::Bank::SentinelBenefits::Csv401kConverter - Takes a series of lines in Sentinel Benefits format and writes them out as QIF files, subject to the symbol mappings specified.
14              
15              
16              
17             =head1 VERSION
18              
19             version 1.3
20              
21             =head1 SYNOPSIS
22              
23              
24              
25              
26             =head1 DESCRIPTION
27              
28              
29              
30             This module takes a CSV file in the format "provided" i.e. copy-pasted from the Sentinel Benefits website. It also takes a description->symbol mapping, and one or two filenames to write out. The first file is a list of the transactions in QIF format. The second file, if provided, is a list of the company matches with the signs reversed, which can be useful if you want to keep unvested company contributions from showing up in your net worth calculations.
31              
32              
33              
34             =cut
35              
36 4     4   3453 use Moose;
  4         1845252  
  4         26  
37 4     4   33883 use MooseX::StrictConstructor;
  4         90009  
  4         18  
38              
39 4     4   42900 use Finance::Bank::SentinelBenefits::Csv401kConverter::SymbolMap;
  4         14  
  4         190  
40 4     4   2314 use Finance::Bank::SentinelBenefits::Csv401kConverter::LineParser;
  4         1350  
  4         159  
41 4     4   2375 use Finance::Bank::SentinelBenefits::Csv401kConverter::QifWriter;
  4         1474  
  4         159  
42 4     4   2551 use Finance::Bank::SentinelBenefits::Csv401kConverter::SideReverser;
  4         1473  
  4         2972  
43              
44              
45             =head1 Accessors
46              
47              
48              
49             =head2 $p->trade_input()
50              
51              
52              
53             A file handle that supplies the trade data
54              
55              
56              
57             =cut
58              
59             has 'trade_input' => (
60             is => 'ro',
61             isa => 'FileHandle',
62             required => 1,
63             );
64              
65             has 'primary_output_file' => (
66             is => 'ro',
67             isa => 'Str',
68             required => 1,
69             );
70              
71             has 'symbol_map' => (
72             is => 'ro',
73             isa => 'Finance::Bank::SentinelBenefits::Csv401kConverter::SymbolMap',
74             required => 1,
75             );
76              
77             =head2 $p->trade_date()
78              
79              
80              
81             Used if you wish to override the trade date specified in the input file, or if no trade date is available in the files.
82              
83              
84              
85             If no dates are specified here or in the files, an exception will be thrown.
86              
87              
88              
89             =cut
90              
91             has 'trade_date' => (
92             is => 'ro',
93             isa => 'DateTime',
94             required => 0,
95             );
96              
97             has 'account' => (
98             is => 'ro',
99             isa => 'Str',
100             required => 1,
101             );
102              
103             has 'companymatch_account' => (
104             is => 'ro',
105             isa => 'Str',
106             required => 0,
107             );
108              
109             has '_side_reverser' => (
110             is => 'ro',
111             isa => 'Finance::Bank::SentinelBenefits::Csv401kConverter::SideReverser',
112             required => 0,
113             default => sub {
114             Finance::Bank::SentinelBenefits::Csv401kConverter::SideReverser->new();
115             }
116             );
117              
118              
119             =head2 p->write_output()
120              
121             Writes the output to the output file
122              
123             =cut
124              
125 8     8 1 59 sub write_output($self){
  8         14  
  8         14  
126 8         260 my $parser = Finance::Bank::SentinelBenefits::Csv401kConverter::LineParser->new
127             (
128             symbol_map => $self->symbol_map()
129             );
130              
131 8         265 my $writer = Finance::Bank::SentinelBenefits::Csv401kConverter::QifWriter->new
132             (
133             output_file => ">" . $self->primary_output_file(),
134             account => $self->account(),
135             );
136              
137 8         229 my $fh = $self->trade_input();
138              
139 8         17 my @lines;
140              
141 8         236 my $date = $self->trade_date();
142              
143 8         267 while(<$fh>){
144              
145              
146             #this line is a date and there is no override, parse it as such
147 46 100 66     17037 if(9 == length && (not defined $self->trade_date()) ){
148 4         63 $date = DateTime::Format::Flexible->parse_datetime($_);
149             # warn "date is $date";
150             }else{
151              
152 42         126 my $line = $parser->parse_line($_, $date);
153              
154 42 100       137 if (defined $line) {
155 14         60 $writer->output_line($line);
156              
157 14         2301 push @lines, $line;
158             }
159             }
160             }
161              
162 8         47 $writer->close();
163              
164 8 100       1339 if($self->companymatch_account())
165             {
166 4         128 my $cm_writer = Finance::Bank::SentinelBenefits::Csv401kConverter::QifWriter->new
167             (
168             output_file => ">>" . $self->primary_output_file(),
169             account => $self->companymatch_account(),
170             );
171              
172 4         12 foreach my $line (@lines) {
173              
174 6 100       222 if($line->source() eq 'Match'){
175 4         130 my $cm_line = Finance::Bank::SentinelBenefits::Csv401kConverter::Line->new
176             (
177             date => $line->date(),
178             symbol => $line->symbol(),
179             memo => $line->memo(),
180             quantity => $line->quantity(),
181             price => $line->price(),
182             total => $line->total(),
183             source => $line->source(),
184             side => $self->_side_reverser->flip($line->side()),
185             );
186 4         18 $cm_writer->output_line($cm_line);
187             }
188              
189             }
190              
191 4         16 $cm_writer->close();
192            
193             }
194             }
195              
196 4     4   52 no Moose;
  4         33  
  4         25  
197              
198             __PACKAGE__->meta->make_immutable;
199              
200             1;
201              
202              
203             =head1 LICENSE AND COPYRIGHT
204             Copyright 2009-2023 David Solimano
205             This file is part of Finance::Bank::SentinelBenefits::Csv401kConverter
206              
207             Finance::Bank::SentinelBenefits::Csv401kConverter is free software: you can redistribute it and/or modify
208             it under the terms of the GNU General Public License as published by
209             the Free Software Foundation, either version 3 of the License, or
210             (at your option) any later version.
211              
212             Finance::Bank::SentinelBenefits::Csv401kConverter is distributed in the hope that it will be useful,
213             but WITHOUT ANY WARRANTY; without even the implied warranty of
214             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
215             GNU General Public License for more details.
216              
217             You should have received a copy of the GNU General Public License
218             along with Finance::Bank::SentinelBenefits::Csv401kConverter. If not, see <http://www.gnu.org/licenses/>
219             =cut