add skip_dcontext_suffix to skip CDRs with dcontext ending in a definable string...
[freeside.git] / FS / FS / part_pkg / sqlradacct_hour.pm
1 package FS::part_pkg::sqlradacct_hour;
2
3 use strict;
4 use vars qw(@ISA %info);
5 #use FS::Record qw(qsearch qsearchs);
6 use FS::part_pkg::flat;
7
8 @ISA = qw(FS::part_pkg::flat);
9
10 # some constants to facilitate changes
11 # maybe we display charge per petabyte in the future?
12 use constant KB => 1024;
13 use constant MB => KB * 1024;
14 use constant GB => MB * 1024;
15 use constant BU => GB;            # base unit
16 use constant BS => 'gigabyte';    # BU spelled out
17 use constant BA => 'gig';         # BU abbreviation
18
19 %info = (
20   'name' => 'Time and data charges from an SQL RADIUS radacct table',
21   'shortname' => 'Usage charges from RADIUS',
22   'inherit_fields' => [ 'global_Mixin' ],
23   'fields' => {
24     'recur_included_hours' => { 'name' => 'Hours included',
25                                 'default' => 0,
26                               },
27     'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
28                                'default' => 0,
29                              },
30     'recur_hourly_cap'    => { 'name' => 'Maximum overage charge for hours'.
31                                          ' (0 means no cap)',
32
33                                'default' => 0,
34                              },
35
36     'recur_included_input' => { 'name' => 'Upload ' . BS . 's included',
37                                 'default' => 0,
38                               },
39     'recur_input_charge' => { 'name' =>
40                                       'Additional charge per ' . BS . ' upload',
41                               'default' => 0,
42                             },
43     'recur_input_cap'    => { 'name' => 'Maximum overage charge for upload'.
44                                          ' (0 means no cap)',
45                                'default' => 0,
46                              },
47
48     'recur_included_output' => { 'name' => 'Download ' . BS . 's included',
49                                  'default' => 0,
50                               },
51     'recur_output_charge' => { 'name' =>
52                                      'Additional charge per ' . BS . ' download',
53                               'default' => 0,
54                             },
55     'recur_output_cap'    => { 'name' => 'Maximum overage charge for download'.
56                                          ' (0 means no cap)',
57                                'default' => 0,
58                              },
59
60     'recur_included_total' => { 'name' =>
61                                      'Total ' . BS . 's included',
62                                 'default' => 0,
63                               },
64     'recur_total_charge' => { 'name' =>
65                                'Additional charge per ' . BS . ' total',
66                               'default' => 0,
67                             },
68     'recur_total_cap'    => { 'name' => 'Maximum overage charge for total'.
69                                         ' ' . BS . 's (0 means no cap)',
70                                'default' => 0,
71                              },
72
73     'global_cap'         => { 'name' => 'Global cap on all overage charges'.
74                                         ' (0 means no cap)',
75                               'default' => 0,
76                             },
77
78   },
79   'fieldorder' => [qw( recur_included_hours recur_hourly_charge recur_hourly_cap recur_included_input recur_input_charge recur_input_cap recur_included_output recur_output_charge recur_output_cap recur_included_total recur_total_charge recur_total_cap global_cap )],
80   'weight' => 40,
81 );
82
83 sub price_info {
84     my $self = shift;
85     my $str = $self->SUPER::price_info(@_);
86     $str .= " plus usage" if $str;
87     $str;
88 }
89
90 sub calc_recur {
91   my($self, $cust_pkg, $sdate, $details ) = @_;
92
93   my $last_bill = $cust_pkg->last_bill;
94   my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $$sdate ) / 3600;
95   $hours -= $self->option('recur_included_hours');
96   $hours = 0 if $hours < 0;
97
98   my $input = $cust_pkg->attribute_since_sqlradacct(  $last_bill,
99                                                       $$sdate,
100                                                       'AcctInputOctets' )
101               / BU;
102
103   my $output = $cust_pkg->attribute_since_sqlradacct( $last_bill,
104                                                       $$sdate,
105                                                       'AcctOutputOctets' )
106                / BU;
107
108   my $included_total = $self->option('recur_included_total') || 0;
109   my $addoncharge = 0;
110   foreach my $cust_pkg_usageprice ($cust_pkg->cust_pkg_usageprice) {
111     my $part_pkg_usageprice = $cust_pkg_usageprice->part_pkg_usageprice;
112     $included_total += $cust_pkg_usageprice->quantity * $part_pkg_usageprice->amount;
113     $addoncharge += $cust_pkg_usageprice->price;
114   }
115   my $raw_total = $input + $output;
116   push(@$details,sprintf( "%.3f %ss included, %.3f %ss used", $included_total, BA, $raw_total, BA ))
117     if $included_total;
118
119   my $total = $input + $output - $included_total;
120   $total = 0 if $total < 0;
121   $input = $input - $self->option('recur_included_input');
122   $input = 0 if $input < 0;
123   $output = $output - $self->option('recur_included_output');
124   $output = 0 if $output < 0;
125
126   my $totalcharge =
127      sprintf('%.2f', $total * $self->option('recur_total_charge'));
128   $totalcharge = $self->option('recur_total_cap')
129     if $self->option('recur_total_cap')
130     && $totalcharge > $self->option('recur_total_cap');
131
132   my $inputcharge =
133      sprintf('%.2f', $input * $self->option('recur_input_charge'));
134   $inputcharge = $self->option('recur_input_cap')
135     if $self->option('recur_input_cap')
136     && $inputcharge > $self->option('recur_input_cap');
137
138   my $outputcharge = 
139     sprintf('%.2f', $output * $self->option('recur_output_charge'));
140   $outputcharge = $self->option('recur_output_cap')
141     if $self->option('recur_output_cap')
142     && $outputcharge > $self->option('recur_output_cap');
143
144   my $hourscharge =
145     sprintf('%.2f', $hours * $self->option('recur_hourly_charge'));
146   $hourscharge = $self->option('recur_hourly_cap')
147     if $self->option('recur_hourly_cap')
148     && $hourscharge > $self->option('recur_hourly_cap');
149
150   if ( $self->option('recur_total_charge') > 0 ) {
151     push @$details,
152       sprintf( "Last month's data %.3f %ss: %s", $total, BA, $totalcharge );
153   }
154   if ( $self->option('recur_input_charge') > 0 ) {
155     push @$details,
156       sprintf( "Last month's download %.3f %ss: %s", $input, BA, $inputcharge );
157   }
158   if ( $self->option('recur_output_charge') > 0 ) {
159     push @$details,
160       sprintf( "Last month's upload %.3f %ss: %s", $output, BA, $outputcharge );
161   }
162   if ( $self->option('recur_hourly_charge')  > 0 ) {
163     push @$details, "Last month\'s time ".
164                    sprintf('%.1f', $hours). " hours: $hourscharge";
165   }
166
167   my $charges = $hourscharge + $inputcharge + $outputcharge + $totalcharge + $addoncharge;
168   if ( $self->option('global_cap') && $charges > $self->option('global_cap') ) {
169     $charges = $self->option('global_cap');
170     push @$details, "Usage charges capped at: $charges";
171   }
172
173   $self->option('recur_fee') + $charges;
174 }
175
176 sub can_discount { 0; }
177
178 sub is_free_options {
179   qw( setup_fee recur_fee recur_hourly_charge
180       recur_input_charge recur_output_charge recur_total_charge );
181 }
182
183 sub base_recur {
184   my($self, $cust_pkg) = @_;
185   $self->option('recur_fee');
186 }
187
188 1;