1 package FS::part_export;
4 use vars qw( @ISA @EXPORT_OK $DEBUG %exports );
7 use FS::Record qw( qsearch qsearchs dbh );
9 use FS::part_export_option;
12 @ISA = qw(FS::Record);
13 @EXPORT_OK = qw(export_info);
19 FS::part_export - Object methods for part_export records
25 $record = new FS::part_export \%hash;
26 $record = new FS::part_export { 'column' => 'value' };
28 #($new_record, $options) = $template_recored->clone( $svcpart );
30 $error = $record->insert( { 'option' => 'value' } );
31 $error = $record->insert( \%options );
33 $error = $new_record->replace($old_record);
35 $error = $record->delete;
37 $error = $record->check;
41 An FS::part_export object represents an export of Freeside data to an external
42 provisioning system. FS::part_export inherits from FS::Record. The following
43 fields are currently supported:
47 =item exportnum - primary key
49 =item machine - Machine name
51 =item exporttype - Export type
53 =item nodomain - blank or "Y" : usernames are exported to this service with no domain
63 Creates a new export. To add the export to the database, see L<"insert">.
65 Note that this stores the hash reference, not a distinct copy of the hash it
66 points to. You can ask the object for a copy with the I<hash> method.
70 # the new method can be inherited from FS::Record, if a table method is defined
72 sub table { 'part_export'; }
78 #An alternate constructor. Creates a new export by duplicating an existing
79 #export. The given svcpart is assigned to the new export.
81 #Returns a list consisting of the new export object and a hashref of options.
87 # my $class = ref($self);
88 # my %hash = $self->hash;
89 # $hash{'exportnum'} = '';
90 # $hash{'svcpart'} = shift;
91 # ( $class->new( \%hash ),
92 # { map { $_->optionname => $_->optionvalue }
93 # qsearch('part_export_option', { 'exportnum' => $self->exportnum } )
100 Adds this record to the database. If there is an error, returns the error,
101 otherwise returns false.
103 If a hash reference of options is supplied, part_export_option records are
104 created (see L<FS::part_export_option>).
108 #false laziness w/queue.pm
112 local $SIG{HUP} = 'IGNORE';
113 local $SIG{INT} = 'IGNORE';
114 local $SIG{QUIT} = 'IGNORE';
115 local $SIG{TERM} = 'IGNORE';
116 local $SIG{TSTP} = 'IGNORE';
117 local $SIG{PIPE} = 'IGNORE';
119 my $oldAutoCommit = $FS::UID::AutoCommit;
120 local $FS::UID::AutoCommit = 0;
123 my $error = $self->SUPER::insert;
125 $dbh->rollback if $oldAutoCommit;
129 foreach my $optionname ( keys %{$options} ) {
130 my $part_export_option = new FS::part_export_option ( {
131 'exportnum' => $self->exportnum,
132 'optionname' => $optionname,
133 'optionvalue' => $options->{$optionname},
135 $error = $part_export_option->insert;
137 $dbh->rollback if $oldAutoCommit;
142 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
150 Delete this record from the database.
154 #foreign keys would make this much less tedious... grr dumb mysql
157 local $SIG{HUP} = 'IGNORE';
158 local $SIG{INT} = 'IGNORE';
159 local $SIG{QUIT} = 'IGNORE';
160 local $SIG{TERM} = 'IGNORE';
161 local $SIG{TSTP} = 'IGNORE';
162 local $SIG{PIPE} = 'IGNORE';
164 my $oldAutoCommit = $FS::UID::AutoCommit;
165 local $FS::UID::AutoCommit = 0;
168 my $error = $self->SUPER::delete;
170 $dbh->rollback if $oldAutoCommit;
174 foreach my $part_export_option ( $self->part_export_option ) {
175 my $error = $part_export_option->delete;
177 $dbh->rollback if $oldAutoCommit;
182 foreach my $export_svc ( $self->export_svc ) {
183 my $error = $export_svc->delete;
185 $dbh->rollback if $oldAutoCommit;
190 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
196 =item replace OLD_RECORD HASHREF
198 Replaces the OLD_RECORD with this one in the database. If there is an error,
199 returns the error, otherwise returns false.
201 If a hash reference of options is supplied, part_export_option records are
202 created or modified (see L<FS::part_export_option>).
210 local $SIG{HUP} = 'IGNORE';
211 local $SIG{INT} = 'IGNORE';
212 local $SIG{QUIT} = 'IGNORE';
213 local $SIG{TERM} = 'IGNORE';
214 local $SIG{TSTP} = 'IGNORE';
215 local $SIG{PIPE} = 'IGNORE';
217 my $oldAutoCommit = $FS::UID::AutoCommit;
218 local $FS::UID::AutoCommit = 0;
221 my $error = $self->SUPER::replace($old);
223 $dbh->rollback if $oldAutoCommit;
227 foreach my $optionname ( keys %{$options} ) {
228 my $old = qsearchs( 'part_export_option', {
229 'exportnum' => $self->exportnum,
230 'optionname' => $optionname,
232 my $new = new FS::part_export_option ( {
233 'exportnum' => $self->exportnum,
234 'optionname' => $optionname,
235 'optionvalue' => $options->{$optionname},
237 $new->optionnum($old->optionnum) if $old;
238 my $error = $old ? $new->replace($old) : $new->insert;
240 $dbh->rollback if $oldAutoCommit;
245 #remove extraneous old options
247 grep { !exists $options->{$_->optionname} } $old->part_export_option
249 my $error = $opt->delete;
251 $dbh->rollback if $oldAutoCommit;
256 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
264 Checks all fields to make sure this is a valid export. If there is
265 an error, returns the error, otherwise returns false. Called by the insert
273 $self->ut_numbern('exportnum')
274 || $self->ut_domain('machine')
275 || $self->ut_alpha('exporttype')
277 return $error if $error;
279 $self->nodomain =~ /^(Y?)$/ or return "Illegal nodomain: ". $self->nodomain;
282 $self->deprecated(1); #BLAH
291 #Returns the service definition (see L<FS::part_svc>) for this export.
297 # qsearchs('part_svc', { svcpart => $self->svcpart } );
302 croak "FS::part_export::part_svc deprecated";
303 #confess "FS::part_export::part_svc deprecated";
308 Returns a list of associated FS::svc_* records.
314 map { $_->svc_x } $self->cust_svc;
319 Returns a list of associated FS::cust_svc records.
325 map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
326 grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
332 Returns a list of associated FS::export_svc records.
338 qsearch('export_svc', { 'exportnum' => $self->exportnum } );
341 =item part_export_option
343 Returns all options as FS::part_export_option objects (see
344 L<FS::part_export_option>).
348 sub part_export_option {
350 qsearch('part_export_option', { 'exportnum' => $self->exportnum } );
355 Returns a list of option names and values suitable for assigning to a hash.
361 map { $_->optionname => $_->optionvalue } $self->part_export_option;
364 =item option OPTIONNAME
366 Returns the option value for the given name, or the empty string.
372 my $part_export_option =
373 qsearchs('part_export_option', {
374 exportnum => $self->exportnum,
377 $part_export_option ? $part_export_option->optionvalue : '';
382 Reblesses the object into the FS::part_export::EXPORTTYPE class, where
383 EXPORTTYPE is the object's I<exporttype> field. There should be better docs
384 on how to create new exports, but until then, see L</NEW EXPORT CLASSES>.
390 my $exporttype = $self->exporttype;
391 my $class = ref($self). "::$exporttype";
394 bless($self, $class) unless $@;
398 #these should probably all go away, just let the subclasses define em
400 =item export_insert SVC_OBJECT
407 $self->_export_insert(@_);
413 # my $method = $AUTOLOAD;
414 # #$method =~ s/::(\w+)$/::_$1/; #infinite loop prevention
415 # $method =~ s/::(\w+)$/_$1/; #infinite loop prevention
416 # $self->$method(@_);
419 =item export_replace NEW OLD
426 $self->_export_replace(@_);
436 $self->_export_delete(@_);
446 $self->_export_suspend(@_);
449 =item export_unsuspend
453 sub export_unsuspend {
456 $self->_export_unsuspend(@_);
459 #fallbacks providing useful error messages intead of infinite loops
462 return "_export_insert: unknown export type ". $self->exporttype;
465 sub _export_replace {
467 return "_export_replace: unknown export type ". $self->exporttype;
472 return "_export_delete: unknown export type ". $self->exporttype;
475 #call svcdb-specific fallbacks
477 sub _export_suspend {
479 #warn "warning: _export_suspened unimplemented for". ref($self);
481 my $new = $svc_x->clone_suspended;
482 $self->_export_replace( $new, $svc_x );
485 sub _export_unsuspend {
487 #warn "warning: _export_unsuspend unimplemented for ". ref($self);
489 my $old = $svc_x->clone_kludge_unsuspend;
490 $self->_export_replace( $svc_x, $old );
499 =item export_info [ SVCDB ]
501 Returns a hash reference of the exports for the given I<svcdb>, or if no
502 I<svcdb> is specified, for all exports. The keys of the hash are
503 I<exporttype>s and the values are again hash references containing information
506 'desc' => 'Description',
508 'option' => { label=>'Option Label' },
509 'option2' => { label=>'Another label' },
511 'nodomain' => 'Y', #or ''
512 'notes' => 'Additional notes',
518 return $exports{$_[0]} || {} if @_;
519 #{ map { %{$exports{$_}} } keys %exports };
520 my $r = { map { %{$exports{$_}} } keys %exports };
523 #=item exporttype2svcdb EXPORTTYPE
525 #Returns the applicable I<svcdb> for an I<exporttype>.
529 #sub exporttype2svcdb {
530 # my $exporttype = $_[0];
531 # foreach my $svcdb ( keys %exports ) {
532 # return $svcdb if grep { $exporttype eq $_ } keys %{$exports{$svcdb}};
537 foreach my $INC ( @INC ) {
538 foreach my $file ( glob("$INC/FS/part_export/*.pm") ) {
539 warn "attempting to load export info from $file\n" if $DEBUG;
540 $file =~ /\/(\w+)\.pm$/ or do {
541 warn "unrecognized file in $INC/FS/part_export/: $file\n";
545 my $info = eval "use FS::part_export::$mod; ".
546 "\\%FS::part_export::$mod\::info;";
548 die "error using FS::part_export::$mod (skipping): $@\n" if $@;
551 unless ( keys %$info ) {
552 warn "no %info hash found in FS::part_export::$mod, skipping\n"
553 unless $mod =~ /^(passwdfile|null)$/; #hack but what the heck
556 warn "got export info from FS::part_export::$mod: $info\n" if $DEBUG;
559 ref($info->{'svc'}) ? @{$info->{'svc'}} : $info->{'svc'}
562 warn "blank svc for FS::part_export::$mod (skipping)\n";
565 $exports{$svc}->{$mod} = $info;
572 =head1 NEW EXPORT CLASSES
574 A module should be added in FS/FS/part_export/ (an example may be found in
575 eg/export_template.pm)
579 Hmm... cust_export class (not necessarily a database table...) ... ?
585 L<FS::part_export_option>, L<FS::export_svc>, L<FS::svc_acct>,
587 L<FS::svc_forward>, L<FS::Record>, schema.html from the base documentation.