add customer fields option with agent, display_custnum, status and name, RT#73721
[freeside.git] / FS / FS / part_pkg_usageprice.pm
1 package FS::part_pkg_usageprice;
2 use base qw( FS::Record );
3
4 use strict;
5 use Tie::IxHash;
6 #use FS::Record qw( qsearch qsearchs );
7
8 =head1 NAME
9
10 FS::part_pkg_usageprice - Object methods for part_pkg_usageprice records
11
12 =head1 SYNOPSIS
13
14   use FS::part_pkg_usageprice;
15
16   $record = new FS::part_pkg_usageprice \%hash;
17   $record = new FS::part_pkg_usageprice { 'column' => 'value' };
18
19   $error = $record->insert;
20
21   $error = $new_record->replace($old_record);
22
23   $error = $record->delete;
24
25   $error = $record->check;
26
27 =head1 DESCRIPTION
28
29 An FS::part_pkg_usageprice object represents a usage pricing add-on.
30 FS::part_pkg_usageprice inherits from FS::Record.  The following fields are
31 currently supported:
32
33 =over 4
34
35 =item usagepricepart
36
37 primary key
38
39 =item pkgpart
40
41 pkgpart
42
43 =item price
44
45 price
46
47 =item currency
48
49 currency
50
51 =item action
52
53 action
54
55 =item target
56
57 target
58
59 =item amount
60
61 amount
62
63
64 =back
65
66 =head1 METHODS
67
68 =over 4
69
70 =item new HASHREF
71
72 Creates a new record.  To add the record to the database, see L<"insert">.
73
74 Note that this stores the hash reference, not a distinct copy of the hash it
75 points to.  You can ask the object for a copy with the I<hash> method.
76
77 =cut
78
79 sub table { 'part_pkg_usageprice'; }
80
81 =item insert
82
83 Adds this record to the database.  If there is an error, returns the error,
84 otherwise returns false.
85
86 =item delete
87
88 Delete this record from the database.
89
90 =item replace OLD_RECORD
91
92 Replaces the OLD_RECORD with this one in the database.  If there is an error,
93 returns the error, otherwise returns false.
94
95 =item check
96
97 Checks all fields to make sure this is a valid record.  If there is
98 an error, returns the error, otherwise returns false.  Called by the insert
99 and replace methods.
100
101 =cut
102
103 sub check {
104   my $self = shift;
105
106   my $error = 
107     $self->ut_numbern('usagepricepart')
108     || $self->ut_number('pkgpart')
109     || $self->ut_money('price')
110     || $self->ut_currencyn('currency')
111     || $self->ut_enum('action', [ 'increment', 'set' ])
112     || $self->ut_enum('target', [ 'svc_acct.totalbytes', 'svc_acct.seconds',
113                                   'svc_conferencing.participants',
114 #                                  'svc_conferencing.confqualitynum',
115                                   'sqlradacct_hour.recur_included_total'
116                                 ]
117                      )
118     || $self->ut_text('amount')
119   ;
120   return $error if $error;
121
122   #Check target against package
123   #UI doesn't currently prevent these from happing,
124   #so keep error messages informative
125   my $part_pkg = $self->part_pkg;
126   my $target = $self->target;
127   my $label = $self->target_info->{'label'};
128   my ($needs_svcdb, $needs_plan);
129   if ( $target =~ /^svc_acct.(\w+)$/ ) {
130     $needs_svcdb = 'svc_acct';
131   } elsif ( $target eq 'svc_conferencing.participants' ) {
132     $needs_svcdb = 'svc_conferencing';
133   } elsif ( $target =~ /^sqlradacct_hour.(\w+)$/ ) {
134     $needs_plan = 'sqlradacct_hour';
135   }
136   if ($needs_svcdb) {
137     my $has_svcdb = 0;
138     foreach my $pkg_svc ($part_pkg->pkg_svc) {
139       next unless $pkg_svc->quantity;
140       my $svcdb = $pkg_svc->part_svc->svcdb;
141       $has_svcdb = 1
142         if $svcdb eq $needs_svcdb;
143       last if $has_svcdb;
144     }
145     return "Usage pricing add-on \'$label\' can only be used on packages with at least one $needs_svcdb service.\n"
146       unless $has_svcdb;
147   }
148   if ($needs_plan) {
149     return "Usage pricing add-on \'$label\' can only be used on packages with pricing plan \'" . 
150            FS::part_pkg->plan_info->{$needs_plan}->{'shortname'} . "\'\n"
151       unless ref($part_pkg) eq 'FS::part_pkg::' . $needs_plan;
152   }
153
154   $self->SUPER::check;
155 }
156
157 =item target_info
158
159 Returns a hash reference of information about the target of this object.
160 Keys are "label" and "multiplier".
161
162 =cut
163
164 sub target_info {
165   my $self = shift;
166   $self->targets->{$self->target};
167 }
168
169 =item targets
170
171 (Class method)
172 Returns a hash reference.  Keys are possible values for the "target" field.
173 Values are hash references with "label" and "multiplier" keys.
174
175 =cut
176
177 sub targets {
178
179   tie my %targets, 'Tie::IxHash', # once?
180     #'svc_acct.totalbytes' => { label      => 'Megabytes',
181     #                           multiplier => 1048576,
182     #                         },
183     'svc_acct.totalbytes' => { label      => 'Total Gigabytes',
184                                multiplier => 1073741824,
185                              },
186     'svc_acct.seconds' => { label      => 'Total Hours',
187                             multiplier => 3600,
188                           },
189     'svc_conferencing.participants' => { label     => 'Conference Participants',
190                                          multiplier=> 1,
191                                        },
192   #this will take more work: set action, not increment..
193   #  and then value comes from a select, not a text field
194   #  'svc_conferencing.confqualitynum' => { label => 'Conference Quality',
195   #                                        },
196
197     # this bypasses usual apply methods, handled entirely in sqlradacct_hour
198     'sqlradacct_hour.recur_included_total' => { label => 'Included Gigabytes',
199                                                 multiplier => 1 }, #recur_included_total is stored in GB
200  
201   ;
202
203   \%targets;
204
205 }
206
207 =back
208
209 =head1 BUGS
210
211 =head1 SEE ALSO
212
213 L<FS::part_pkg>, L<FS::Record>
214
215 =cut
216
217 1;
218