1 package FS::Report::Table::Monthly;
7 use Time::Local qw( timelocal );
9 @ISA = qw( FS::Report::Table );
13 FS::Report::Table::Monthly - Tables of report data, indexed monthly
17 use FS::Report::Table::Monthly;
19 my $report = new FS::Report::Table::Monthly (
20 'items' => [ 'invoiced', 'netsales', 'credits', 'receipts', ],
27 'params' => [ [ 'paramsfor', 'item_one' ], [ 'item', 'two' ] ], # ...
28 'remove_empty' => 1, #collapse empty rows, default 0
29 'item_labels' => [ ], #useful with remove_empty
32 my $data = $report->data;
40 Returns a hashref of data (!! describe)
45 local $FS::UID::AutoCommit = 0;
48 my $smonth = $self->{'start_month'};
49 my $syear = $self->{'start_year'};
50 my $emonth = $self->{'end_month'};
51 my $eyear = $self->{'end_year'};
52 # how far to extrapolate into the future
53 my $pmonth = $self->{'project_month'};
54 my $pyear = $self->{'project_year'};
57 if ( $eyear < $syear or
58 ($eyear == $syear and $emonth < $smonth) ) {
59 return { error => 'Start month must be before end month' };
62 my $agentnum = $self->{'agentnum'};
64 if ( $pyear > $eyear or
65 ($pyear == $eyear and $pmonth > $emonth) ) {
67 # create the entire projection set first to avoid timing problems
69 $self->init_projection if $pmonth;
71 my $thisyear = $eyear;
72 my $thismonth = $emonth;
73 while ( $thisyear < $pyear ||
74 ( $thisyear == $pyear and $thismonth <= $pmonth )
76 my $speriod = timelocal(0,0,0,1,$thismonth-1,$thisyear);
78 if ( $thismonth == 13 ) { $thisyear++; $thismonth = 1; }
79 my $eperiod = timelocal(0,0,0,1,$thismonth-1,$thisyear);
81 $self->extend_projection($speriod, $eperiod);
87 my $max_year = $pyear || $eyear;
88 my $max_month = $pmonth || $emonth;
90 my $projecting = 0; # are we currently projecting?
92 while ( $syear < $max_year
93 || ( $syear == $max_year && $smonth < $max_month+1 ) ) {
95 if ( $self->{'doublemonths'} ) {
96 my($firstLabel,$secondLabel) = @{$self->{'doublemonths'}};
97 push @{$data{label}}, "$smonth/$syear $firstLabel";
98 push @{$data{label}}, "$smonth/$syear $secondLabel";
101 push @{$data{label}}, "$smonth/$syear";
104 if ( $syear > $eyear || ( $syear == $eyear && $smonth >= $emonth + 1 ) ) {
105 # start getting data from the projection
109 my $speriod = timelocal(0,0,0,1,$smonth-1,$syear);
110 push @{$data{speriod}}, $speriod;
111 if ( ++$smonth == 13 ) { $syear++; $smonth=1; }
112 my $eperiod = timelocal(0,0,0,1,$smonth-1,$syear);
113 push @{$data{eperiod}}, $eperiod;
116 my @items = @{$self->{'items'}};
119 for ( $i = 0; $i < scalar(@items); $i++ ) {
120 if ( $self->{'doublemonths'} ) {
121 my $item = $items[$i];
122 my @param = $self->{'params'} ? @{ $self->{'params'}[$i] }: ();
123 push @param, 'project', $projecting;
124 my $value = $self->$item($speriod, $eperiod, $agentnum, @param);
125 push @{$data{data}->[$col]}, $value;
126 $item = $items[$i+1];
127 @param = $self->{'params'} ? @{ $self->{'params'}[++$i] }: ();
128 push @param, 'project', $projecting;
129 $value = $self->$item($speriod, $eperiod, $agentnum, @param);
130 push @{$data{data}->[$col++]}, $value;
133 my $item = $items[$i];
134 my @param = $self->{'params'} ? @{ $self->{'params'}[$col] }: ();
135 push @param, 'project', $projecting;
136 my $value = $self->$item($speriod, $eperiod, $agentnum, @param);
137 push @{$data{data}->[$col++]}, $value;
143 #these need to get generalized, sheesh
144 $data{'items'} = $self->{'items'};
145 $data{'item_labels'} = $self->{'item_labels'} || $self->{'items'};
146 $data{'colors'} = $self->{'colors'};
147 $data{'links'} = $self->{'links'} || [];
149 if ( $self->{'remove_empty'} ) {
152 #these need to get generalized, sheesh
153 #(though we now return a list of item indices that are present in the
154 #output, so the front-end code could do this)
161 foreach my $item ( @{$self->{'items'}} ) {
163 if ( grep { $_ != 0 } @{$data{'data'}->[$col]} ) {
164 push @newitems, $data{'items'}->[$col];
165 push @newlabels, $data{'item_labels'}->[$col];
166 push @newdata, $data{'data'}->[$col];
167 push @newcolors, $data{'colors'}->[$col];
168 push @newlinks, $data{'links'}->[$col];
175 $data{'items'} = \@newitems;
176 $data{'item_labels'} = \@newlabels;
177 $data{'data'} = \@newdata;
178 $data{'colors'} = \@newcolors;
179 $data{'links'} = \@newlinks;
180 $data{'indices'} = \@indices;
183 # clean up after ourselves
185 # leave in until development is finished, for diagnostics