+=item get_remoteid SVC
+
+Returns the remote id for this export for the given service.
+
+=cut
+
+sub get_remoteid {
+ my ($self, $svc_x) = @_;
+
+ my $export_cust_svc = qsearchs('export_cust_svc',{
+ 'exportnum' => $self->exportnum,
+ 'svcnum' => $svc_x->svcnum
+ });
+
+ return $export_cust_svc ? $export_cust_svc->remoteid : '';
+}
+
+=item set_remoteid SVC VALUE
+
+Sets the remote id for this export for the given service.
+See L<FS::export_cust_svc>.
+
+If value is true, inserts or updates export_cust_svc record.
+If value is false, deletes any existing record.
+
+Returns error message, blank on success.
+
+=cut
+
+sub set_remoteid {
+ my ($self, $svc_x, $value) = @_;
+
+ my $export_cust_svc = qsearchs('export_cust_svc',{
+ 'exportnum' => $self->exportnum,
+ 'svcnum' => $svc_x->svcnum
+ });
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = '';
+ if ($value) {
+ if ($export_cust_svc) {
+ $export_cust_svc->set('remoteid',$value);
+ $error = $export_cust_svc->replace;
+ } else {
+ $export_cust_svc = new FS::export_cust_svc {
+ 'exportnum' => $self->exportnum,
+ 'svcnum' => $svc_x->svcnum,
+ 'remoteid' => $value
+ };
+ $error = $export_cust_svc->insert;
+ }
+ } else {
+ if ($export_cust_svc) {
+ $error = $export_cust_svc->delete;
+ } #otherwise, it already doesn't exist
+ }
+
+ if ($oldAutoCommit) {
+ $dbh->rollback if $error;
+ $dbh->commit unless $error;
+ }
+
+ return $error;
+}
+
+=item export_links SVC_OBJECT ARRAYREF
+
+Adds a list of web elements to ARRAYREF specific to this export and SVC_OBJECT.
+The elements are displayed in the UI to lead the the operator to external
+configuration, monitoring, and similar tools.
+
+=item export_getsettings SVC_OBJECT SETTINGS_HASHREF DEFAUTS_HASHREF
+
+Adds a hashref of settings to SETTINGSREF specific to this export and
+SVC_OBJECT. The elements can be displayed in the UI on the service view.
+
+DEFAULTSREF is a hashref with the same keys where true values indicate the
+setting is a default (and thus can be displayed in the UI with less emphasis,
+or hidden by default).
+
+=item actions
+
+Adds one or more "action" links to the export's display in
+browse/part_export.cgi. Should return pairs of values. The first is
+the link label; the second is the Mason path to a document to load.
+The document will show in a popup.
+
+=cut
+
+sub actions { }
+
+=cut
+
+=item weight
+
+Returns the 'weight' element from the export's %info hash, or 0 if there is
+no weight defined.
+
+=cut
+
+sub weight {
+ my $self = shift;
+ export_info()->{$self->exporttype}->{'weight'} || 0;
+}
+
+=item info
+
+Returns a reference to (a copy of) the export's %info hash.
+
+=cut
+
+sub info {
+ my $self = shift;
+ $self->{_info} ||= {
+ %{ export_info()->{$self->exporttype} }
+ };
+}
+
+=item get_dids SELECTION
+
+Does several things, which is unfortunate. DID phone numbers are organized
+in a sort-of hierarchy: state, areacode, exchange, number. Or, for some
+vendors: state, region, number. But not always that, either.
+
+SELECTION is one or more field/value pairs specifying parts of the hierarchy
+that have already been selected. C<get_dids> will then return an arrayref of
+the possible values for the next selection level. Note that these are not
+actual DIDs except at the lowest level.
+
+Generally, 'state' alone will return an array of area codes or region names
+in the state.
+
+'state' and 'areacode' together will return an array of either:
+- exchange strings of the form "New York (212-555-XXXX)"
+- ratecenter names of the form "New York, NY"
+
+These strings are sent back to the UI and offered as options so that the user
+can choose the local calling area they like.
+
+'areacode' and 'exchange', or 'state' and 'ratecenter', or 'region' by itself
+will return an array of actual DID numbers.
+
+Passing 'tollfree' with a true value will override the whole hierarchy and
+return an array of tollfree numbers.
+
+C<get_dids> methods should report errors via die().
+
+=cut
+
+# no stub; can('get_dids') should return false by default
+
+#default fallbacks... FS::part_export::DID_Common ?
+sub can_get_dids { 0; }
+sub get_dids_can_tollfree { 0; }
+sub get_dids_can_manual { 0; }
+sub get_dids_can_edit { 0; } #don't use without can_manual, otherwise the
+ # DID selector provisions a new number from
+ # inventory each edit
+sub get_dids_npa_select { 1; }
+
+# get_dids_npa_select: if true, then prompt to select state, then area code,
+# then city/exchange, then phone number.
+# if false, then prompt to select state (actually province), then "region",
+# then phone number.
+#
+# get_dids_can_manual: if true, then there will be a radio button to enter
+# a phone number manually.
+#
+# get_dids_can_tollfree: if true, then the user will be prompted to choose
+# both a regular and a toll-free number. The export can have a
+# 'restrict_selection' option to enable only one or the other of those. See
+# part_export/vitelity.pm for an example.
+#
+# get_dids_can_edit: if true, then the user can use the selector again to
+# change the phone number for a service. if false, then they can't (have to
+# reprovision completely).
+
+=item svc_role SVC
+
+Returns the role that SVC occupies with respect to this export, if any.
+This is part of the part_svc's export configuration.
+
+=cut
+
+sub svc_role {
+ my $self = shift;
+ my $svc_x = shift;
+ my $cust_svc = $svc_x->cust_svc or return '';
+ my $export_svc = qsearchs('export_svc', { exportnum => $self->exportnum,
+ svcpart => $cust_svc->svcpart })
+ or return '';
+ $export_svc->role;
+}
+
+=item svc_with_role { SVC | PKGNUM }, ROLE
+
+Given a svc_* object SVC or pkgnum PKG, and a role name ROLE, finds the
+service(s) in the same package that are linked to this export with ROLE.
+
+=cut
+
+sub svc_with_role {
+ my $self = shift;
+ my $svc_or_pkgnum = shift;
+ my $role = shift;
+ my $pkgnum;
+ if ( ref $svc_or_pkgnum ) {
+ $pkgnum = $svc_or_pkgnum->cust_svc->pkgnum or return '';
+ } else {
+ $pkgnum = $svc_or_pkgnum;
+ }
+ my $role_info = $self->info->{roles}->{$role}
+ or die "role '$role' does not exist for export '".$self->exporttype."'\n";
+ my $svcdb = $role_info->{svcdb};
+
+ my @svcs = qsearch({
+ 'table' => $svcdb,
+ 'addl_from' => ' JOIN cust_svc USING (svcnum)' .
+ ' JOIN export_svc USING (svcpart)',
+ 'extra_sql' => " WHERE cust_svc.pkgnum = $pkgnum" .
+ " AND export_svc.exportnum = ".$self->exportnum .
+ " AND export_svc.role = '$role'",
+ });
+ if ( $role_info->{multiple} ) {
+ return @svcs;
+ } else {
+ if ( @svcs > 1 ) {
+ warn "multiple $role services in pkgnum $pkgnum; returning the first one.\n";
+ }
+ return $svcs[0];
+ }
+}
+