1 package FS::part_export;
4 use vars qw( @ISA @EXPORT_OK $DEBUG %exports );
7 use base qw( FS::option_Common FS::m2m_Common ); # m2m for 'export_nas'
8 use FS::Record qw( qsearch qsearchs dbh );
10 use FS::part_export_option;
13 #for export modules, though they should probably just use it themselves
16 @EXPORT_OK = qw(export_info);
22 FS::part_export - Object methods for part_export records
28 $record = new FS::part_export \%hash;
29 $record = new FS::part_export { 'column' => 'value' };
31 #($new_record, $options) = $template_recored->clone( $svcpart );
33 $error = $record->insert( { 'option' => 'value' } );
34 $error = $record->insert( \%options );
36 $error = $new_record->replace($old_record);
38 $error = $record->delete;
40 $error = $record->check;
44 An FS::part_export object represents an export of Freeside data to an external
45 provisioning system. FS::part_export inherits from FS::Record. The following
46 fields are currently supported:
50 =item exportnum - primary key
52 =item exportname - Descriptive name
54 =item machine - Machine name
56 =item exporttype - Export type
58 =item nodomain - blank or "Y" : usernames are exported to this service with no domain
68 Creates a new export. To add the export to the database, see L<"insert">.
70 Note that this stores the hash reference, not a distinct copy of the hash it
71 points to. You can ask the object for a copy with the I<hash> method.
75 # the new method can be inherited from FS::Record, if a table method is defined
77 sub table { 'part_export'; }
83 #An alternate constructor. Creates a new export by duplicating an existing
84 #export. The given svcpart is assigned to the new export.
86 #Returns a list consisting of the new export object and a hashref of options.
92 # my $class = ref($self);
93 # my %hash = $self->hash;
94 # $hash{'exportnum'} = '';
95 # $hash{'svcpart'} = shift;
96 # ( $class->new( \%hash ),
97 # { map { $_->optionname => $_->optionvalue }
98 # qsearch('part_export_option', { 'exportnum' => $self->exportnum } )
105 Adds this record to the database. If there is an error, returns the error,
106 otherwise returns false.
108 If a hash reference of options is supplied, part_export_option records are
109 created (see L<FS::part_export_option>).
113 Delete this record from the database.
117 #foreign keys would make this much less tedious... grr dumb mysql
120 local $SIG{HUP} = 'IGNORE';
121 local $SIG{INT} = 'IGNORE';
122 local $SIG{QUIT} = 'IGNORE';
123 local $SIG{TERM} = 'IGNORE';
124 local $SIG{TSTP} = 'IGNORE';
125 local $SIG{PIPE} = 'IGNORE';
127 my $oldAutoCommit = $FS::UID::AutoCommit;
128 local $FS::UID::AutoCommit = 0;
131 # clean up export_nas records
132 my $error = $self->process_m2m(
133 'link_table' => 'export_nas',
134 'target_table' => 'nas',
136 ) || $self->SUPER::delete;
138 $dbh->rollback if $oldAutoCommit;
142 foreach my $export_svc ( $self->export_svc ) {
143 my $error = $export_svc->delete;
145 $dbh->rollback if $oldAutoCommit;
150 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
158 Checks all fields to make sure this is a valid export. If there is
159 an error, returns the error, otherwise returns false. Called by the insert
167 $self->ut_numbern('exportnum')
168 || $self->ut_textn('exportname')
169 || $self->ut_domain('machine')
170 || $self->ut_alpha('exporttype')
172 return $error if $error;
174 $self->nodomain =~ /^(Y?)$/ or return "Illegal nodomain: ". $self->nodomain;
177 $self->deprecated(1); #BLAH
186 Returns a label for this export, "exportname||exportype (machine)".
192 ($self->exportname || $self->exporttype ). ' ('. $self->machine. ')';
197 #Returns the service definition (see L<FS::part_svc>) for this export.
203 # qsearchs('part_svc', { svcpart => $self->svcpart } );
208 croak "FS::part_export::part_svc deprecated";
209 #confess "FS::part_export::part_svc deprecated";
214 Returns a list of associated FS::svc_* records.
220 map { $_->svc_x } $self->cust_svc;
225 Returns a list of associated FS::cust_svc records.
231 map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
232 grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
238 Returns a list of associated FS::export_svc records.
244 qsearch('export_svc', { 'exportnum' => $self->exportnum } );
249 Returns a list of associated FS::export_device records.
255 qsearch('export_device', { 'exportnum' => $self->exportnum } );
258 =item part_export_option
260 Returns all options as FS::part_export_option objects (see
261 L<FS::part_export_option>).
265 sub part_export_option {
267 $self->option_objects;
272 Returns a list of option names and values suitable for assigning to a hash.
274 =item option OPTIONNAME
276 Returns the option value for the given name, or the empty string.
280 Reblesses the object into the FS::part_export::EXPORTTYPE class, where
281 EXPORTTYPE is the object's I<exporttype> field. There should be better docs
282 on how to create new exports, but until then, see L</NEW EXPORT CLASSES>.
288 my $exporttype = $self->exporttype;
289 my $class = ref($self). "::$exporttype";
292 bless($self, $class) unless $@;
296 #these should probably all go away, just let the subclasses define em
298 =item export_insert SVC_OBJECT
305 $self->_export_insert(@_);
311 # my $method = $AUTOLOAD;
312 # #$method =~ s/::(\w+)$/::_$1/; #infinite loop prevention
313 # $method =~ s/::(\w+)$/_$1/; #infinite loop prevention
314 # $self->$method(@_);
317 =item export_replace NEW OLD
324 $self->_export_replace(@_);
334 $self->_export_delete(@_);
344 $self->_export_suspend(@_);
347 =item export_unsuspend
351 sub export_unsuspend {
354 $self->_export_unsuspend(@_);
357 #fallbacks providing useful error messages intead of infinite loops
360 return "_export_insert: unknown export type ". $self->exporttype;
363 sub _export_replace {
365 return "_export_replace: unknown export type ". $self->exporttype;
370 return "_export_delete: unknown export type ". $self->exporttype;
373 #call svcdb-specific fallbacks
375 sub _export_suspend {
377 #warn "warning: _export_suspened unimplemented for". ref($self);
379 my $new = $svc_x->clone_suspended;
380 $self->_export_replace( $new, $svc_x );
383 sub _export_unsuspend {
385 #warn "warning: _export_unsuspend unimplemented for ". ref($self);
387 my $old = $svc_x->clone_kludge_unsuspend;
388 $self->_export_replace( $svc_x, $old );
391 =item export_links SVC_OBJECT ARRAYREF
393 Adds a list of web elements to ARRAYREF specific to this export and SVC_OBJECT.
394 The elements are displayed in the UI to lead the the operator to external
395 configuration, monitoring, and similar tools.
397 =item export_getsettings SVC_OBJECT SETTINGS_HASHREF DEFAUTS_HASHREF
399 Adds a hashref of settings to SETTINGSREF specific to this export and
400 SVC_OBJECT. The elements can be displayed in the UI on the service view.
402 DEFAULTSREF is a hashref with the same keys where true values indicate the
403 setting is a default (and thus can be displayed in the UI with less emphasis,
404 or hidden by default).
410 Returns the 'weight' element from the export's %info hash, or 0 if there is
417 export_info()->{$self->exporttype}->{'weight'} || 0;
426 =item export_info [ SVCDB ]
428 Returns a hash reference of the exports for the given I<svcdb>, or if no
429 I<svcdb> is specified, for all exports. The keys of the hash are
430 I<exporttype>s and the values are again hash references containing information
433 'desc' => 'Description',
435 'option' => { label=>'Option Label' },
436 'option2' => { label=>'Another label' },
438 'nodomain' => 'Y', #or ''
439 'notes' => 'Additional notes',
445 return $exports{$_[0]} || {} if @_;
446 #{ map { %{$exports{$_}} } keys %exports };
447 my $r = { map { %{$exports{$_}} } keys %exports };
451 sub _upgrade_data { #class method
452 my ($class, %opts) = @_;
454 my @part_export_option = qsearch('part_export_option', { 'optionname' => 'overlimit_groups' });
455 foreach my $opt ( @part_export_option ) {
456 next if $opt->optionvalue =~ /^[\d\s]+$/ || !$opt->optionvalue;
457 my @groupnames = split(' ',$opt->optionvalue);
460 foreach my $groupname ( @groupnames ) {
461 my $g = qsearchs('radius_group', { 'groupname' => $groupname } );
463 $g = new FS::radius_group {
464 'groupname' => $groupname,
465 'description' => $groupname,
468 die $error if $error;
470 push @groupnums, $g->groupnum;
472 $opt->optionvalue(join(' ',@groupnums));
473 $error = $opt->replace;
474 die $error if $error;
478 $exports_in_use{ref $_} = 1 foreach qsearch('part_export', {});
479 foreach (keys(%exports_in_use)) {
480 $_->_upgrade_exporttype(%opts) if $_->can('_upgrade_exporttype');
484 #=item exporttype2svcdb EXPORTTYPE
486 #Returns the applicable I<svcdb> for an I<exporttype>.
490 #sub exporttype2svcdb {
491 # my $exporttype = $_[0];
492 # foreach my $svcdb ( keys %exports ) {
493 # return $svcdb if grep { $exporttype eq $_ } keys %{$exports{$svcdb}};
498 #false laziness w/part_pkg & cdr
499 foreach my $INC ( @INC ) {
500 foreach my $file ( glob("$INC/FS/part_export/*.pm") ) {
501 warn "attempting to load export info from $file\n" if $DEBUG;
502 $file =~ /\/(\w+)\.pm$/ or do {
503 warn "unrecognized file in $INC/FS/part_export/: $file\n";
507 my $info = eval "use FS::part_export::$mod; ".
508 "\\%FS::part_export::$mod\::info;";
510 die "error using FS::part_export::$mod (skipping): $@\n" if $@;
513 unless ( keys %$info ) {
514 warn "no %info hash found in FS::part_export::$mod, skipping\n"
515 unless $mod =~ /^(passwdfile|null|.+_Common)$/; #hack but what the heck
518 warn "got export info from FS::part_export::$mod: $info\n" if $DEBUG;
521 ref($info->{'svc'}) ? @{$info->{'svc'}} : $info->{'svc'}
524 warn "blank svc for FS::part_export::$mod (skipping)\n";
527 $exports{$svc}->{$mod} = $info;
534 =head1 NEW EXPORT CLASSES
536 A module should be added in FS/FS/part_export/ (an example may be found in
537 eg/export_template.pm)
541 Hmm... cust_export class (not necessarily a database table...) ... ?
547 L<FS::part_export_option>, L<FS::export_svc>, L<FS::svc_acct>,
549 L<FS::svc_forward>, L<FS::Record>, schema.html from the base documentation.