first pass at VoIP rating
[freeside.git] / FS / FS / rate.pm
1 package FS::rate;
2
3 use strict;
4 use vars qw( @ISA );
5 use FS::Record qw( qsearch qsearchs dbh );
6 use FS::rate_detail;
7
8 @ISA = qw(FS::Record);
9
10 =head1 NAME
11
12 FS::rate - Object methods for rate records
13
14 =head1 SYNOPSIS
15
16   use FS::rate;
17
18   $record = new FS::rate \%hash;
19   $record = new FS::rate { 'column' => 'value' };
20
21   $error = $record->insert;
22
23   $error = $new_record->replace($old_record);
24
25   $error = $record->delete;
26
27   $error = $record->check;
28
29 =head1 DESCRIPTION
30
31 An FS::rate object represents an rate plan.  FS::rate inherits from
32 FS::Record.  The following fields are currently supported:
33
34 =over 4
35
36 =item ratenum - primary key
37
38 =item ratename
39
40 =back
41
42 =head1 METHODS
43
44 =over 4
45
46 =item new HASHREF
47
48 Creates a new rate plan.  To add the rate plan to the database, see L<"insert">.
49
50 Note that this stores the hash reference, not a distinct copy of the hash it
51 points to.  You can ask the object for a copy with the I<hash> method.
52
53 =cut
54
55 # the new method can be inherited from FS::Record, if a table method is defined
56
57 sub table { 'rate'; }
58
59 =item insert [ , OPTION => VALUE ... ]
60
61 Adds this record to the database.  If there is an error, returns the error,
62 otherwise returns false.
63
64 Currently available options are: I<rate_detail>
65
66 If I<rate_detail> is set to an array reference of FS::rate_detail objects, the
67 objects will have their ratenum field set and will be inserted after this
68 record.
69
70 =cut
71
72 sub insert {
73   my $self = shift;
74   my %options = @_;
75
76   local $SIG{HUP} = 'IGNORE';
77   local $SIG{INT} = 'IGNORE';
78   local $SIG{QUIT} = 'IGNORE';
79   local $SIG{TERM} = 'IGNORE';
80   local $SIG{TSTP} = 'IGNORE';
81   local $SIG{PIPE} = 'IGNORE';
82
83   my $oldAutoCommit = $FS::UID::AutoCommit;
84   local $FS::UID::AutoCommit = 0;
85   my $dbh = dbh;
86
87   my $error = $self->check;
88   return $error if $error;
89
90   $error = $self->SUPER::insert;
91   if ( $error ) {
92     $dbh->rollback if $oldAutoCommit;
93     return $error;
94   }
95
96   if ( $options{'rate_detail'} ) {
97     foreach my $rate_detail ( @{$options{'rate_detail'}} ) {
98       $rate_detail->ratenum($self->ratenum);
99       $error = $rate_detail->insert;
100       if ( $error ) {
101         $dbh->rollback if $oldAutoCommit;
102         return $error;
103       }
104     }
105   }
106
107   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
108
109   '';
110 }
111
112
113
114 =item delete
115
116 Delete this record from the database.
117
118 =cut
119
120 # the delete method can be inherited from FS::Record
121
122 =item replace OLD_RECORD [ , OPTION => VALUE ... ]
123
124 Replaces the OLD_RECORD with this one in the database.  If there is an error,
125 returns the error, otherwise returns false.
126
127 Currently available options are: I<rate_detail>
128
129 If I<rate_detail> is set to an array reference of FS::rate_detail objects, the
130 objects will have their ratenum field set and will be inserted after this
131 record.  Any existing rate_detail records associated with this record will be
132 deleted.
133
134 =cut
135
136 sub replace {
137   my ($new, $old) = (shift, shift);
138   my %options = @_;
139
140   local $SIG{HUP} = 'IGNORE';
141   local $SIG{INT} = 'IGNORE';
142   local $SIG{QUIT} = 'IGNORE';
143   local $SIG{TERM} = 'IGNORE';
144   local $SIG{TSTP} = 'IGNORE';
145   local $SIG{PIPE} = 'IGNORE';
146
147   my $oldAutoCommit = $FS::UID::AutoCommit;
148   local $FS::UID::AutoCommit = 0;
149   my $dbh = dbh;
150
151   my @old_rate_detail = ();
152   @old_rate_detail = $old->rate_detail if $options{'rate_detail'};
153
154   my $error = $new->SUPER::replace($old);
155   if ($error) {
156     $dbh->rollback if $oldAutoCommit;
157     return $error;
158   }
159
160   foreach my $old_rate_detail ( @old_rate_detail ) {
161     my $error = $old_rate_detail->delete;
162     if ($error) {
163       $dbh->rollback if $oldAutoCommit;
164       return $error;
165     }
166   }
167
168   foreach my $rate_detail ( @{$options{'rate_detail'}} ) {
169     $rate_detail->ratenum($new->ratenum);
170     $error = $rate_detail->insert;
171     if ( $error ) {
172       $dbh->rollback if $oldAutoCommit;
173       return $error;
174     }
175   }
176
177   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
178   '';
179
180 }
181
182 =item check
183
184 Checks all fields to make sure this is a valid rate plan.  If there is
185 an error, returns the error, otherwise returns false.  Called by the insert
186 and replace methods.
187
188 =cut
189
190 # the check method should currently be supplied - FS::Record contains some
191 # data checking routines
192
193 sub check {
194   my $self = shift;
195
196   my $error =
197        $self->ut_numbern('ratenum')
198     || $self->ut_text('ratename')
199   ;
200   return $error if $error;
201
202   $self->SUPER::check;
203 }
204
205 =item dest_detail REGIONNUM | RATE_REGION_OBJECTD
206
207 Returns the rate detail (see L<FS::rate_detail>) for this rate to the
208 specificed destination.
209
210 =cut
211
212 sub dest_detail {
213   my $self = shift;
214   my $regionnum = ref($_[0]) ? shift->regionnum : shift;
215   qsearchs( 'rate_detail', { 'ratenum'        => $self->ratenum,
216                              'dest_regionnum' => $regionnum,     } );
217 }
218
219 =item rate_detail
220
221 Returns all region-specific details  (see L<FS::rate_detail>) for this rate.
222
223 =cut
224
225 sub rate_detail {
226   my $self = shift;
227   qsearch( 'rate_detail', { 'ratenum' => $self->ratenum } );
228 }
229
230
231 =back
232
233 =head1 BUGS
234
235 =head1 SEE ALSO
236
237 L<FS::Record>, schema.html from the base documentation.
238
239 =cut
240
241 1;
242