4 use vars qw( @ISA $DEBUG );
5 use FS::Record qw( qsearch qsearchs dbh fields );
14 FS::rate - Object methods for rate records
20 $record = new FS::rate \%hash;
21 $record = new FS::rate { 'column' => 'value' };
23 $error = $record->insert;
25 $error = $new_record->replace($old_record);
27 $error = $record->delete;
29 $error = $record->check;
33 An FS::rate object represents an rate plan. FS::rate inherits from
34 FS::Record. The following fields are currently supported:
38 =item ratenum - primary key
50 Creates a new rate plan. To add the rate plan to the database, see L<"insert">.
52 Note that this stores the hash reference, not a distinct copy of the hash it
53 points to. You can ask the object for a copy with the I<hash> method.
57 # the new method can be inherited from FS::Record, if a table method is defined
61 =item insert [ , OPTION => VALUE ... ]
63 Adds this record to the database. If there is an error, returns the error,
64 otherwise returns false.
66 Currently available options are: I<rate_detail>
68 If I<rate_detail> is set to an array reference of FS::rate_detail objects, the
69 objects will have their ratenum field set and will be inserted after this
78 local $SIG{HUP} = 'IGNORE';
79 local $SIG{INT} = 'IGNORE';
80 local $SIG{QUIT} = 'IGNORE';
81 local $SIG{TERM} = 'IGNORE';
82 local $SIG{TSTP} = 'IGNORE';
83 local $SIG{PIPE} = 'IGNORE';
85 my $oldAutoCommit = $FS::UID::AutoCommit;
86 local $FS::UID::AutoCommit = 0;
89 my $error = $self->check;
90 return $error if $error;
92 $error = $self->SUPER::insert;
94 $dbh->rollback if $oldAutoCommit;
98 if ( $options{'rate_detail'} ) {
100 my( $num, $last, $min_sec ) = (0, time, 5); #progressbar foo
102 foreach my $rate_detail ( @{$options{'rate_detail'}} ) {
104 $rate_detail->ratenum($self->ratenum);
105 $error = $rate_detail->insert;
107 $dbh->rollback if $oldAutoCommit;
111 if ( $options{'job'} ) {
113 if ( time - $min_sec > $last ) {
114 my $error = $options{'job'}->update_statustext(
115 int( 100 * $num / scalar( @{$options{'rate_detail'}} ) )
118 $dbh->rollback if $oldAutoCommit;
128 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
137 Delete this record from the database.
141 # the delete method can be inherited from FS::Record
143 =item replace OLD_RECORD [ , OPTION => VALUE ... ]
145 Replaces the OLD_RECORD with this one in the database. If there is an error,
146 returns the error, otherwise returns false.
148 Currently available options are: I<rate_detail>
150 If I<rate_detail> is set to an array reference of FS::rate_detail objects, the
151 objects will have their ratenum field set and will be inserted after this
152 record. Any existing rate_detail records associated with this record will be
158 my ($new, $old) = (shift, shift);
161 local $SIG{HUP} = 'IGNORE';
162 local $SIG{INT} = 'IGNORE';
163 local $SIG{QUIT} = 'IGNORE';
164 local $SIG{TERM} = 'IGNORE';
165 local $SIG{TSTP} = 'IGNORE';
166 local $SIG{PIPE} = 'IGNORE';
168 my $oldAutoCommit = $FS::UID::AutoCommit;
169 local $FS::UID::AutoCommit = 0;
172 # my @old_rate_detail = ();
173 # @old_rate_detail = $old->rate_detail if $options{'rate_detail'};
175 my $error = $new->SUPER::replace($old);
177 $dbh->rollback if $oldAutoCommit;
181 # foreach my $old_rate_detail ( @old_rate_detail ) {
183 # my $error = $old_rate_detail->delete;
185 # $dbh->rollback if $oldAutoCommit;
189 # if ( $options{'job'} ) {
191 # if ( time - $min_sec > $last ) {
192 # my $error = $options{'job'}->update_statustext(
193 # int( 50 * $num / scalar( @old_rate_detail ) )
196 # $dbh->rollback if $oldAutoCommit;
204 if ( $options{'rate_detail'} ) {
205 my $sth = $dbh->prepare('DELETE FROM rate_detail WHERE ratenum = ?') or do {
206 $dbh->rollback if $oldAutoCommit;
210 $sth->execute($old->ratenum) or do {
211 $dbh->rollback if $oldAutoCommit;
215 my( $num, $last, $min_sec ) = (0, time, 5); #progresbar foo
217 foreach my $rate_detail ( @{$options{'rate_detail'}} ) {
219 $rate_detail->ratenum($new->ratenum);
220 $error = $rate_detail->insert;
222 $dbh->rollback if $oldAutoCommit;
226 if ( $options{'job'} ) {
228 if ( time - $min_sec > $last ) {
229 my $error = $options{'job'}->update_statustext(
230 int( 100 * $num / scalar( @{$options{'rate_detail'}} ) )
233 $dbh->rollback if $oldAutoCommit;
244 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
251 Checks all fields to make sure this is a valid rate plan. If there is
252 an error, returns the error, otherwise returns false. Called by the insert
257 # the check method should currently be supplied - FS::Record contains some
258 # data checking routines
264 $self->ut_numbern('ratenum')
265 || $self->ut_text('ratename')
267 return $error if $error;
272 =item dest_detail REGIONNUM | RATE_REGION_OBJECTD | HASHREF
274 Returns the rate detail (see L<FS::rate_detail>) for this rate to the
275 specificed destination. Destination can be specified as an FS::rate_detail
276 object or regionnum (see L<FS::rate_detail>), or as a hashref with two keys:
277 I<countrycode> and I<phonenum>.
285 if ( ref($_[0]) eq 'HASH' ) {
287 my $countrycode = $_[0]->{'countrycode'};
288 my $phonenum = $_[0]->{'phonenum'};
290 #find a rate prefix, first look at most specific (4 digits) then 3, etc.,
291 # finally trying the country code only
292 my $rate_prefix = '';
293 for my $len ( reverse(1..10) ) {
294 $rate_prefix = qsearchs('rate_prefix', {
295 'countrycode' => $countrycode,
296 #'npa' => { op=> 'LIKE', value=> substr($number, 0, $len) }
297 'npa' => substr($phonenum, 0, $len),
300 $rate_prefix ||= qsearchs('rate_prefix', {
301 'countrycode' => $countrycode,
306 #die "Can't find rate for call $to_or_from +$countrycode $number\n"
307 die "Can't find rate for +$countrycode $phonenum\n"
310 $regionnum = $rate_prefix->regionnum;
312 #$rate_region = $rate_prefix->rate_region;
315 $regionnum = ref($_[0]) ? shift->regionnum : shift;
318 qsearchs( 'rate_detail', { 'ratenum' => $self->ratenum,
319 'dest_regionnum' => $regionnum, } );
324 Returns all region-specific details (see L<FS::rate_detail>) for this rate.
330 qsearch( 'rate_detail', { 'ratenum' => $self->ratenum } );
342 Experimental job-queue processor for web interface adds/edits
346 use Storable qw(thaw);
352 my $param = thaw(decode_base64(shift));
353 warn Dumper($param) if $DEBUG;
355 my $old = qsearchs('rate', { 'ratenum' => $param->{'ratenum'} } )
356 if $param->{'ratenum'};
358 my @rate_detail = map {
360 my $regionnum = $_->regionnum;
361 if ( $param->{"sec_granularity$regionnum"} ) {
363 new FS::rate_detail {
364 'dest_regionnum' => $regionnum,
365 map { $_ => $param->{"$_$regionnum"} }
366 qw( min_included min_charge sec_granularity )
371 new FS::rate_detail {
372 'dest_regionnum' => $regionnum,
375 'sec_granularity' => '60'
380 } qsearch('rate_region', {} );
382 my $rate = new FS::rate {
383 map { $_ => $param->{$_} }
388 if ( $param->{'ratenum'} ) {
389 warn "$rate replacing $old (". $param->{'ratenum'}. ")\n" if $DEBUG;
390 $error = $rate->replace( $old,
391 'rate_detail' => \@rate_detail,
395 warn "inserting $rate\n" if $DEBUG;
396 $error = $rate->insert( 'rate_detail' => \@rate_detail,
399 #$ratenum = $rate->getfield('ratenum');
402 die "$error\n" if $error;
410 L<FS::Record>, schema.html from the base documentation.