diff options
author | Ivan Kohler <ivan@freeside.biz> | 2015-12-26 12:30:18 -0800 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2015-12-26 12:30:18 -0800 |
commit | dd003d59f56742f9374cec309ad81d527e88c846 (patch) | |
tree | fa890d0a64c6713e29674deff8d0fae6560ca644 | |
parent | 2040b70c10db3390b26777bc584d54333534419d (diff) | |
parent | 7ec6e27220e3fe82405c911a4c52b24070438328 (diff) |
Merge branch 'master' of git.freeside.biz:/home/git/freeside
41 files changed, 966 insertions, 94 deletions
diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index a96a6cb41..51e47adaf 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -314,6 +314,8 @@ tie my %rights, 'Tie::IxHash', 'Services: Alarm services', 'Services: Video', 'Services: Circuits', + 'Services: Fiber', + 'Services: Fiber: Advanced search', 'Services: External services', 'Usage: RADIUS sessions', 'Usage: Call Detail Records (CDRs)', diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 72421c767..e066225c0 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -4321,6 +4321,7 @@ and customer address. Include units.', 'description' => 'Method for standardizing customer addresses.', 'type' => 'select', 'select_hash' => [ '' => '', + 'uscensus' => 'U.S. Census Bureau', 'usps' => 'U.S. Postal Service', 'uscensus' => 'U.S. Census Bureau', 'tomtom' => 'TomTom', diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index a2a761737..370ac1af7 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -411,6 +411,8 @@ if ( -e $addl_handler_use_file ) { use FS::report_batch; use FS::report_batch; use FS::password_history; + use FS::svc_fiber; + use FS::fiber_olt; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Misc/Geo.pm b/FS/FS/Misc/Geo.pm index e83d6dcfe..aa4e55e36 100644 --- a/FS/FS/Misc/Geo.pm +++ b/FS/FS/Misc/Geo.pm @@ -11,6 +11,7 @@ use Cpanel::JSON::XS; use URI::Escape 3.31; use Data::Dumper; use FS::Conf; +use FS::Log; use Locale::Country; FS::UID->install_callback( sub { @@ -300,6 +301,8 @@ sub standardize_usps { sub standardize_uscensus { my $self = shift; my $location = shift; + my $log = FS::Log->new('FS::Misc::Geo::standardize_uscensus'); + $log->debug(join("\n", @{$location}{'address1', 'city', 'state', 'zip'})); eval "use Geo::USCensus::Geocoding"; die $@ if $@; @@ -322,6 +325,7 @@ sub standardize_uscensus { my $result = Geo::USCensus::Geocoding->query($request); if ( $result->is_match ) { # unfortunately we get the address back as a single line + $log->debug($result->address); if ($result->address =~ /^(.*), (.*), ([A-Z]{2}), (\d{5}.*)$/) { return +{ address1 => $1, @@ -341,8 +345,8 @@ sub standardize_uscensus { } elsif ( $result->match_level ) { die "Geocoding did not find a matching address.\n"; } else { - warn Dumper($result) if $DEBUG; - die $result->error_message; + $log->error($result->error_message); + return; # for internal errors, don't return anything } } diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index c1ed79cda..a10b5c023 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -6870,6 +6870,52 @@ sub tables_hashref { ], }, + 'svc_fiber' => { + 'columns' => [ + 'svcnum', 'int', '', '', '', '', + 'oltnum', 'int', 'NULL', '', '', '', + 'shelf', 'int', 'NULL', '', '', '', + 'card', 'int', 'NULL', '', '', '', + 'olt_port', 'int', 'NULL', '', '', '', + 'ont_id', 'int', 'NULL', '', '', '', + 'ont_typenum', 'int', 'NULL', '', '', '', + 'ont_serial', 'varchar', 'NULL', $char_d, '', '', + 'ont_port', 'varchar', 'NULL', 16, '', '', + 'vlan', 'int', 'NULL', '', '', '', + 'signal', 'int', 'NULL', '', '', '', + 'speed_up', 'int', 'NULL', '', '', '', + 'speed_down', 'int', 'NULL', '', '', '', + 'ont_install','varchar', 'NULL', $char_d, '', '', + ], + 'primary_key' => 'svcnum', + 'unique' => [ ], + 'index' => [ [ 'ont_serial' ] ], + 'foreign_keys' => [ + { columns => [ 'svcnum' ], + table => 'cust_svc', + }, + { columns => [ 'oltnum' ], + table => 'fiber_olt', + }, + { columns => [ 'ont_typenum' ], + table => 'hardware_type', + references => [ 'typenum' ], + }, + ], + }, + + 'fiber_olt' => { + 'columns' => [ + 'oltnum', 'serial', '', '', '', '', + 'oltname', 'varchar', '', $char_d, '', '', + 'serial', 'varchar', '', $char_d, '', '', + 'disabled', 'char', 'NULL', 1, '', '', + ], + 'primary_key' => 'oltnum', + 'unique' => [ ], + 'index' => [ ], + }, + 'vend_main' => { 'columns' => [ 'vendnum', 'serial', '', '', '', '', diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index d3c618d55..29535f25c 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -999,9 +999,10 @@ sub _make_lines { # - it doesn't already HAVE a setup date # - or a start date in the future # - and it's not suspended + # - and it doesn't have an expire date in the past # - # The last condition used to check the "disable_setup_suspended" option but - # that's obsolete. We now never set the setup date on a suspended package. + # The "disable_setup_suspended" option is now obsolete; we never set the + # setup date on a suspended package. if ( ! $options{recurring_only} and ! $options{cancel} and ( $options{'resetup'} @@ -1012,6 +1013,8 @@ sub _make_lines { && ( ! $cust_pkg->getfield('susp') ) ) ) + and ( ! $cust_pkg->expire + || $cust_pkg->expire > $cmp_time ) ) { @@ -1059,6 +1062,20 @@ sub _make_lines { my $recur_billed_currency = ''; my $recur_billed_amount = 0; my $sdate; + # Conditions for billing the recurring fee: + # - the package doesn't have a future start date + # - and it's not suspended + # - unless suspend_bill is enabled on the package or package def + # - but still not, if the package is on hold + # - or it's suspended for a delayed cancellation + # - and its next bill date is in the past + # - or it doesn't have a next bill date yet + # - or it's a one-time charge + # - or it's a CDR plan with the "bill_every_call" option + # - or it's being canceled + # - and it doesn't have an expire date in the past (this can happen with + # advance billing) + # - again, unless it's being canceled if ( ! $cust_pkg->start_date and ( ! $cust_pkg->susp @@ -1077,6 +1094,12 @@ sub _make_lines { && $part_pkg->option('bill_every_call') ) || $options{cancel} + + and + ( ! $cust_pkg->expire + || $cust_pkg->expire > $cmp_time + || $options{cancel} + ) ) { # XXX should this be a package event? probably. events are called diff --git a/FS/FS/cust_main/Billing_Batch.pm b/FS/FS/cust_main/Billing_Batch.pm index cdaf2938f..f91c5fbdc 100644 --- a/FS/FS/cust_main/Billing_Batch.pm +++ b/FS/FS/cust_main/Billing_Batch.pm @@ -23,8 +23,6 @@ Options may include: B<amount>: the amount to be paid; defaults to the customer's balance minus any payments in transit. -B<payby>: the payment method; defaults to cust_main.payby - B<realtime>: runs this as a realtime payment instead of adding it to a batch. Deprecated. @@ -34,8 +32,9 @@ B<address1>, B<address2>, B<city>, B<state>, B<zip>, B<country>: sets the billing address for the payment; defaults to the customer's billing location. -B<payinfo>, B<paydate>, B<payname>: sets the payment account, expiration -date, and name; defaults to those fields in cust_main. +B<payby>, B<payinfo>, B<paydate>, B<payname>: sets the payment method, +payment account, expiration date, and name; defaults to those fields +in cust_main. =cut @@ -58,6 +57,13 @@ sub batch_card { my $invnum = delete $options{invnum}; + #pay fields should all come from either cust_payby or options, not both + # in theory, could just pass payby, and use it to select cust_payby, + # but nothing currently needs that, so not implementing it now + die "Incomplete payment details" + if ($options{payby} || $options{payinfo} || $options{paydate} || $options{payname}) + && !($options{payby} && $options{payinfo} && $options{paydate} && $options{payname}); + #false laziness with Billing_Realtime my @cust_payby = qsearch({ 'table' => 'cust_payby', @@ -67,7 +73,10 @@ sub batch_card { }); # batch can't try out every one like realtime, just use first one - my $cust_payby = $cust_payby[0] || $self; # somewhat dubious + my $cust_payby = $cust_payby[0]; + + die "No customer payment info found" + unless $options{payinfo} || $cust_payby; my $payby = $options{payby} || $cust_payby->payby; diff --git a/FS/FS/fiber_olt.pm b/FS/FS/fiber_olt.pm new file mode 100644 index 000000000..a0de38d6d --- /dev/null +++ b/FS/FS/fiber_olt.pm @@ -0,0 +1,106 @@ +package FS::fiber_olt; +use base qw( FS::Record ); + +use strict; +use FS::Record qw( qsearch qsearchs ); + +=head1 NAME + +FS::fiber_olt - Object methods for fiber_olt records + +=head1 SYNOPSIS + + use FS::fiber_olt; + + $record = new FS::fiber_olt \%hash; + $record = new FS::fiber_olt { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::fiber_olt object represents an Optical Line Terminal that fiber +connections (L<FS::svc_fiber>) connect to. FS::fiber_olt inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item oltnum - primary key + +=item oltname - name of this device + +=item serial - serial number + +=item disabled - set to 'Y' to make this OLT unavailable for new connections + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new fiber_olt record. To add it to the database, see L<"insert">. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'fiber_olt'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=item check + +Checks all fields to make sure this is a valid example. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('oltnum') + || $self->ut_text('oltname') + || $self->ut_text('serial') + || $self->ut_flag('disabled') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 SEE ALSO + +L<FS::svc_fiber>, L<FS::Record> + +=cut + +1; + diff --git a/FS/FS/geocode_Mixin.pm b/FS/FS/geocode_Mixin.pm index 0625b5ac3..bc8c1180d 100644 --- a/FS/FS/geocode_Mixin.pm +++ b/FS/FS/geocode_Mixin.pm @@ -140,7 +140,7 @@ Returns the full country name. sub country_full { my $self = shift; - $self->code2country($self->country); + $self->code2country($self->get('country')); } sub code2country { diff --git a/FS/FS/log.pm b/FS/FS/log.pm index b07910528..95bc4c409 100644 --- a/FS/FS/log.pm +++ b/FS/FS/log.pm @@ -110,6 +110,7 @@ sub insert { next; } my $emailerror = $msg_template->send( + 'msgtype' => 'admin', 'to' => $log_email->to_addr, 'substitutions' => { 'loglevel' => $FS::Log::LEVELS[$self->level], # which has hopefully been loaded... @@ -147,7 +148,7 @@ sub check { || $self->ut_textn('tablename') || $self->ut_numbern('tablenum') || $self->ut_number('level') - || $self->ut_text('message') + || $self->ut_anything('message') ; return $error if $error; diff --git a/FS/FS/log_context.pm b/FS/FS/log_context.pm index ff3471760..9dba5824c 100644 --- a/FS/FS/log_context.pm +++ b/FS/FS/log_context.pm @@ -10,6 +10,7 @@ my @contexts = ( qw( FS::cust_main::Billing::bill_and_collect FS::cust_main::Billing::bill FS::pay_batch::import_from_gateway + FS::Misc::Geo::standardize_uscensus Cron::bill Cron::backup Cron::upload diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm index 7d9750cc2..978d71394 100644 --- a/FS/FS/msg_template.pm +++ b/FS/FS/msg_template.pm @@ -803,6 +803,25 @@ sub _upgrade_data { ### $self->_populate_initial_data; + ### Fix dump-email_to (needs to happen after _populate_initial_data) + if ($conf->config('dump-email_to')) { + # anyone who still uses dump-email_to should have just had this created + my ($msg_template) = qsearch('msg_template',{ msgname => 'System log' }); + if ($msg_template) { + eval "use FS::log_email;"; + die $@ if $@; + my $log_email = new FS::log_email { + 'context' => 'Cron::backup', + 'min_level' => 1, + 'msgnum' => $msg_template->msgnum, + 'to_addr' => $conf->config('dump-email_to'), + }; + my $error = $log_email->insert; + die $error if $error; + $conf->delete('dump-email_to'); + } + } + } sub _populate_initial_data { #class method @@ -811,18 +830,22 @@ sub _populate_initial_data { #class method eval "use FS::msg_template::InitialData;"; die $@ if $@; + eval "use FS::upgrade_journal;"; + die $@ if $@; my $initial_data = FS::msg_template::InitialData->_initial_data; foreach my $hash ( @$initial_data ) { next if $hash->{_conf} && $conf->config( $hash->{_conf} ); + next if $hash->{_upgrade_journal} && FS::upgrade_journal->is_done( $hash->{_upgrade_journal} ); my $msg_template = new FS::msg_template($hash); my $error = $msg_template->insert( @{ $hash->{_insert_args} || [] } ); die $error if $error; $conf->set( $hash->{_conf}, $msg_template->msgnum ) if $hash->{_conf}; + FS::upgrade_journal->set_done( $hash->{_upgrade_journal} ); } diff --git a/FS/FS/msg_template/InitialData.pm b/FS/FS/msg_template/InitialData.pm index baf145d8b..d502b3f0c 100644 --- a/FS/FS/msg_template/InitialData.pm +++ b/FS/FS/msg_template/InitialData.pm @@ -39,6 +39,20 @@ Amount: {$refund}<BR> END ], }, + { msgname => 'System log', + msgclass => 'email', + mime_type => 'text/html', + _upgrade_journal => 'system_log_email_template', + _insert_args => [ subject => '{ $company_name } system log', + body => <<'END', +Level: {$loglevel}<BR> +Context: {$logcontext}<BR> +<BR> +{$logmessage}<BR> + +END + ], + }, ]; } diff --git a/FS/FS/part_export/broadband_snmp_get.pm b/FS/FS/part_export/broadband_snmp_get.pm index faa51ed06..fafe91a65 100644 --- a/FS/FS/part_export/broadband_snmp_get.pm +++ b/FS/FS/part_export/broadband_snmp_get.pm @@ -30,8 +30,7 @@ tie my %options, 'Tie::IxHash', 'options' => \%options, 'no_machine' => 1, 'notes' => <<'END', -Use this export to configure the community and object ids for displaying realtime -SNMP data from the service IP address when viewing a provisioned service. Timeout is +Display broadband service status information via SNMP. Timeout is per object, and should be small enough for realtime use. This export takes no action during provisioning itself; it is expected that snmp will be separately configured on the service machine. diff --git a/FS/FS/pay_batch.pm b/FS/FS/pay_batch.pm index e299dd9c7..35c79f50b 100644 --- a/FS/FS/pay_batch.pm +++ b/FS/FS/pay_batch.pm @@ -888,7 +888,8 @@ Prepare the batch to be exported. This will: increment expiration dates that are in the past. - If this is the first download for this batch, adjust payment amounts to not be greater than the customer's current balance. If the customer's - balance is zero, the entry will be removed. + balance is zero, the entry will be removed (caution: all cust_pay_batch + entries might be removed!) Use this within a transaction. @@ -947,15 +948,6 @@ sub prepare_for_export { # else $balance >= $cust_pay_batch->amount } - # we might end up removing all cust_pay_batch above... - # probably the better way to handle this is to commit that removal, - # but no time to trace code & test that right now - # - # additionally, UI currently allows hand-deletion of all payments from a batch, meaning - # it's possible to try and process an empty batch...this is where we catch - # such an attempt, though it probably shouldn't be possible in the first place - return "Batch is empty" unless $self->cust_pay_batch; - #need to do this after unbatch_and_delete my $error = $self->set_status('I'); return "error updating pay_batch status: $error\n" if $error; @@ -973,6 +965,10 @@ module, in which case the configuration options are in 'batchconfig-FORMAT'. Alternatively, GATEWAY can be an L<FS::payment_gateway> object set to a L<Business::BatchPayment> module. +Returns the text of the batch. If batch contains no cust_pay_batch entries +(or has them all removed by L</prepare_for_export>) then the batch will be +resolved and a blank string will be returned. All other errors are fatal. + =cut sub export_batch { @@ -1008,6 +1004,12 @@ sub export_batch { my $batchcount = 0; my @cust_pay_batch = $self->cust_pay_batch; + unless (@cust_pay_batch) { + # if it's empty, just resolve the batch + $self->set_status('R'); + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return ''; + } my $delim = exists($info->{'delimiter'}) ? $info->{'delimiter'} : "\n"; @@ -1052,6 +1054,10 @@ that gateway via Business::BatchPayment. OPTIONS may include: - file: override the default transport and write to this file (name or handle) +If batch contains no cust_pay_batch entries (or has them all removed by +L</prepare_for_export>) then nothing will be transported (or written to +the override file) and the batch will be resolved. + =cut sub export_to_gateway { @@ -1072,6 +1078,13 @@ sub export_to_gateway { my $processor = $gateway->batch_processor(%proc_opt); my @items = map { $_->request_item } $self->cust_pay_batch; + unless (@items) { + # if it's empty, just resolve the batch + $self->set_status('R'); + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return ''; + } + my $batch = Business::BatchPayment->create(Batch => batch_id => $self->batchnum, items => \@items diff --git a/FS/FS/svc_fiber.pm b/FS/FS/svc_fiber.pm new file mode 100644 index 000000000..c4036dc66 --- /dev/null +++ b/FS/FS/svc_fiber.pm @@ -0,0 +1,323 @@ +package FS::svc_fiber; + +use strict; +use base qw( FS::svc_Common ); +use FS::cust_svc; +use FS::hardware_type; +use FS::fiber_olt; +use FS::Record 'dbh'; + +=head1 NAME + +FS::svc_fiber - Object methods for svc_fiber records + +=head1 SYNOPSIS + + use FS::table_name; + + $record = new FS::table_name \%hash; + $record = new FS::table_name { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + + $error = $record->suspend; + + $error = $record->unsuspend; + + $error = $record->cancel; + +=head1 DESCRIPTION + +An FS::svc_fiber object represents a fiber-to-the-premises service. +FS::svc_fiber inherits from FS::svc_Common. The following fields are +currently supported: + +=over 4 + +=item svcnum - Primary key + +=item oltnum - The Optical Line Terminal this service connects to (see +L<FS::fiber_olt>). + +=item shelf - The shelf number on the OLT. + +=item card - The card number on the OLT shelf. + +=item olt_port - The port number on that card. + +=item vlan - The VLAN number. + +=item signal - Measured signal strength in dB. + +=item speed_up - Measured uplink speed in Mbps. + +=item speed_down - Measured downlink speed in Mbps. + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new fiber service record. To add it to the database, see L<"insert">. + +=cut + +sub table { 'svc_fiber'; } + +sub table_info { + { + 'name' => 'Fiber', + 'name_plural' => 'Fiber', # really the name of the ACL + 'longname_plural' => 'Fiber services', + 'sorts' => [ 'oltnum', ], + 'display_weight' => 74, + 'cancel_weight' => 74, + 'fields' => { + 'oltnum' => { + 'label' => 'OLT', + 'type' => 'select', + 'select_table' => 'fiber_olt', + 'select_key' => 'oltnum', + 'select_label' => 'oltname', + 'disable_inventory' => 1, + }, + 'shelf' => { + 'label' => 'Shelf', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + 'card' => { + 'label' => 'Card', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + 'olt_port' => { + 'label' => 'GPON port', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + # ONT stuff + 'ont_id' => { + 'label' => 'ONT #', + 'disable_select' => 1, + }, + 'ont_typenum' => { + 'label' => 'Device type', + 'type' => 'select-hardware', + 'disable_select' => 1, + 'disable_default' => 1, + 'disable_inventory' => 1, + }, + 'ont_serial' => { + 'label' => 'Serial number', + 'disable_select' => 1, + }, + 'ont_port' => { + 'label' => 'GE port', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + 'vlan' => { + 'label' => 'VLAN #', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + 'signal' => { + 'label' => 'Signal strength (dB)', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + 'speed_down' => { + 'label' => 'Download speed (Mbps)', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + 'speed_up' => { + 'label' => 'Upload speed (Mbps)', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + 'ont_install' => { + 'label' => 'ONT install location', + 'type' => 'text', + 'disable_inventory' => 1, + 'disable_select' => 1, + }, + }, + }; +} + +=item search_sql STRING + +Class method which returns an SQL fragment to search for the given string. +For svc_fiber, STRING can be a full or partial ONT serial number. + +=cut + +#or something more complicated if necessary +sub search_sql { + my($class, $string) = @_; + $string = dbh->quote('%' . $string . '%'); + "LOWER(svc_fiber.ont_serial) LIKE LOWER($string)"; +} + +=item label + +Returns a description of this fiber service containing the OLT name and +port location, and the ONT serial number. + +=cut + +sub label { + my $self = shift; + $self->ont_serial . ' @ ' . $self->fiber_olt->oltname . ' ' . + join('-', $self->shelf, $self->card, $self->olt_port); +} + +# nothing special for insert, delete, or replace + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be +defined. An FS::cust_svc record will be created and inserted. + +=item delete + +Delete this record from the database. + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=item suspend + +Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>). + +=item unsuspend + +Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>). + +=item cancel + +Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>). + +=item check + +Checks all fields to make sure this is a valid example. If there is +an error, returns the error, otherwise returns false. Called by the insert +and repalce methods. + +=cut + +sub check { + my $self = shift; + + my $x = $self->setfixed; + return $x unless ref($x); + my $part_svc = $x; + + my $error = + $self->ut_number('oltnum') + || $self->ut_numbern('shelf') + || $self->ut_numbern('card') + || $self->ut_numbern('olt_port') + || $self->ut_number('ont_id') + || $self->ut_number('ont_typenum') + || $self->ut_alphan('ont_serial') + || $self->ut_alphan('ont_port') + || $self->ut_numbern('vlan') + || $self->ut_snumbern('signal') + || $self->ut_numbern('speed_up') + || $self->ut_numbern('speed_down') + || $self->ut_textn('ont_install') + ; + return $error if $error; + + $self->SUPER::check; +} + +=item ont_description + +Returns the description of the ONT hardware, if there is one. + +=cut + +sub ont_description { + my $self = shift; + $self->ont_typenum ? $self->hardware_type->description : ''; +} + +=item search HASHREF + +Returns a qsearch hash expression to search for parameters specified in +HASHREF. + +Parameters are those in L<FS::svc_Common/search>, plus: + +ont_typenum - the ONT L<FS::hardware_type> key + +oltnum - the OLT L<FS::fiber_olt> key + +shelf, card, olt_port - the OLT port location fields + +vlan - the VLAN number + +ont_serial - the ONT serial number + +=cut + +sub _search_svc { + my ($class, $params, $from, $where) = @_; + + # make this simple: all of these are numeric fields, except that 0 means null + foreach my $field (qw(ont_typenum oltnum shelf olt_port card vlan)) { + if ( $params->{$field} =~ /^(\d+)$/ ) { + push @$where, "COALESCE($field,0) = $1"; + } + } + if ( length($params->{ont_serial}) ) { + my $string = dbh->quote('%'.$params->{ont_serial}.'%'); + push @$where, "LOWER(ont_serial) LIKE LOWER($string)"; + } + +} + +#stub still needed under 4.x+ + +sub hardware_type { + my $self = shift; + $self->ont_typenum ? FS::hardware_type->by_key($self->ont_typenum) : ''; +} + +=back + +=head1 SEE ALSO + +L<FS::svc_Common>, L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>, +L<FS::cust_pkg>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/MANIFEST b/FS/MANIFEST index f1195acc7..176fe7884 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -860,3 +860,5 @@ FS/report_batch.pm t/report_batch.t FS/password_history.pm t/password_history.t +FS/fiber_olt.pm +t/fiber_olt.t diff --git a/FS/bin/freeside-eftca-upload b/FS/bin/freeside-eftca-upload index b66765af3..107aa19ce 100755 --- a/FS/bin/freeside-eftca-upload +++ b/FS/bin/freeside-eftca-upload @@ -47,6 +47,10 @@ foreach my $pay_batch (@batches) { my $filename = time2str('%Y%m%d', time) . '-' . sprintf('%06d.csv',$batchnum); print STDERR "Exporting batch $batchnum to $filename...\n" if $opt_v; my $text = $pay_batch->export_batch(format => 'eft_canada'); + unless ($text) { + print STDERR "Batch is empty, resolving..." if $opt_v; + next; + } open OUT, ">$tmpdir/$filename"; print OUT $text; close OUT; diff --git a/FS/bin/freeside-paymentech-upload b/FS/bin/freeside-paymentech-upload index 5ae147d07..799e6c42c 100755 --- a/FS/bin/freeside-paymentech-upload +++ b/FS/bin/freeside-paymentech-upload @@ -68,6 +68,10 @@ foreach my $pay_batch (@batches) { my $filename = sprintf('%06d',$batchnum) . '-' .time2str('%Y%m%d%H%M%S', time); print STDERR "Exporting batch $batchnum to $filename...\n" if $opt_v; my $text = $pay_batch->export_batch(format => 'paymentech'); + unless ($text) { + print STDERR "Batch is empty, resolving..." if $opt_v; + next; + } $text =~ s!<fileID>FILEID</fileID>!<fileID>$filename</fileID>! or log_and_die("couldn't find FILEID tag\n"); open OUT, ">$tmpdir/$filename.xml"; @@ -80,6 +84,7 @@ foreach my $pay_batch (@batches) { log_and_die("failed to create zip file\n") if (! -f "$tmpdir/$filename.zip" ); push @filenames, $filename; } +log_and_die("All batches empty\n") if !@filenames; my $host = ($opt_t ? 'orbitalbatchvar.paymentech.net' : 'orbitalbatch.paymentech.net'); diff --git a/FS/bin/freeside-rbc-upload b/FS/bin/freeside-rbc-upload index 52501028c..3fff32a67 100755 --- a/FS/bin/freeside-rbc-upload +++ b/FS/bin/freeside-rbc-upload @@ -70,6 +70,10 @@ foreach my $pay_batch (@batches) { debug "Exporting batch $batchnum to $filename\n"; my $text = $pay_batch->export_batch(format => 'RBC'); + unless ($text) { + print STDERR "Batch is empty, resolving..." if $opt_v; + next; + } write_file("$tmpdir/$filename", $text); debug "Uploading $filename..."; diff --git a/FS/t/fiber_olt.t b/FS/t/fiber_olt.t new file mode 100644 index 000000000..4caada134 --- /dev/null +++ b/FS/t/fiber_olt.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::fiber_olt; +$loaded=1; +print "ok 1\n"; diff --git a/httemplate/browse/fiber_olt.html b/httemplate/browse/fiber_olt.html new file mode 100644 index 000000000..bffd5f222 --- /dev/null +++ b/httemplate/browse/fiber_olt.html @@ -0,0 +1,11 @@ +<& elements/browse-simple.html, + 'table' => 'fiber_olt', + 'title' => 'Fiber service OLTs', + 'menubar' => [ ], + 'name_singular' => 'OLT', + 'acl' => 'Configuration', +# overrides + 'disabled_statuspos' => 3, + 'header' => [ '#', 'Name', 'Serial' ], + 'fields' => [ 'oltnum', 'oltname', 'serial' ], +&> diff --git a/httemplate/edit/fiber_olt.html b/httemplate/edit/fiber_olt.html new file mode 100644 index 000000000..ab7d2f07e --- /dev/null +++ b/httemplate/edit/fiber_olt.html @@ -0,0 +1,24 @@ +<& elements/edit.html, + 'popup' => 1, + 'table' => 'fiber_olt', + 'name_singular' => 'OLT', + 'labels' => \%labels, + 'fields' => \@fields, +&> +<%init> +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +my @fields = ( + 'oltname', + 'serial', + { field => 'disabled', type => 'checkbox', value => 'Y' } +); + +my %labels = ( + 'oltnum' => '', + 'oltname' => 'Name', + 'serial' => 'Serial', + 'disabled' => 'Disabled', +); +</%init> diff --git a/httemplate/edit/log_email.html b/httemplate/edit/log_email.html index bbce7c708..709a24069 100644 --- a/httemplate/edit/log_email.html +++ b/httemplate/edit/log_email.html @@ -18,6 +18,7 @@ { 'field' => 'msgnum', 'type' => 'select-msg_template', 'empty_label' => 'Select template', + 'value' => $msgnum, 'required' => 1, }, ], @@ -42,4 +43,14 @@ my %opts = @_; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right([ 'View system logs', 'Configuration' ]); +my $msgnum = $cgi->param('msgnum'); +unless ($msgnum) { + my ($msg_template) = qsearch('msg_template',{ msgname => 'System log' }); + # doesn't seem worth having a config just for the default selected template + # if they've deleted the system-generated one, just default to empty "Select template" + if ($msg_template) { + $msgnum = $msg_template->msgnum; + } +} + </%init> diff --git a/httemplate/edit/process/fiber_olt.html b/httemplate/edit/process/fiber_olt.html new file mode 100644 index 000000000..c8c4af490 --- /dev/null +++ b/httemplate/edit/process/fiber_olt.html @@ -0,0 +1,11 @@ +<& elements/process.html, + 'table' => 'fiber_olt', + 'viewall_dir' => 'browse', + 'popup_reload' => 'Updating', +&> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +</%init> diff --git a/httemplate/edit/process/svc_fiber.html b/httemplate/edit/process/svc_fiber.html new file mode 100644 index 000000000..815a8eeb8 --- /dev/null +++ b/httemplate/edit/process/svc_fiber.html @@ -0,0 +1,11 @@ +<& elements/svc_Common.html, + table => 'svc_fiber', + edit_ext => 'html', + redirect => popurl(3)."view/svc_fiber.cgi?", +&> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +</%init> diff --git a/httemplate/edit/quick-charge.html b/httemplate/edit/quick-charge.html index 4d87fab28..14c3f51e6 100644 --- a/httemplate/edit/quick-charge.html +++ b/httemplate/edit/quick-charge.html @@ -328,6 +328,8 @@ function bill_now_changed (what) { </TR> % my $row = 0; +% # quotation details are handled by quotation_pkg_detail records, added via link from view/quotation.html +% # the details below get attached to the part_pkg record, and there's no way to edit that from quotations % unless ($quotationnum) { <TR> <TD></TD> diff --git a/httemplate/edit/svc_fiber.html b/httemplate/edit/svc_fiber.html new file mode 100644 index 000000000..e07caa1b1 --- /dev/null +++ b/httemplate/edit/svc_fiber.html @@ -0,0 +1,36 @@ +<& elements/svc_Common.html, + 'table' => 'svc_fiber', + 'fields' => \@fields, +&> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +my $conf = new FS::Conf; + +my @fields = ( + { field => 'oltnum', + type => 'select-table', + table => 'fiber_olt', + name_col => 'oltname', + hashref => { disabled => '' }, + disable_empty => 1, + }, + { field => 'shelf' }, + { field => 'card' }, + { field => 'olt_port' }, + { field => 'ont_id' }, + { field => 'ont_typenum', + type => 'select-hardware_type' + }, + { field => 'ont_serial' }, + { field => 'ont_port' }, + { field => 'vlan' }, + { field => 'signal' }, + { field => 'speed_down' }, + { field => 'speed_up' }, + { field => 'ont_install', size => 50 }, +); + +</%init> diff --git a/httemplate/elements/broadband_snmp_get-dialog.html b/httemplate/elements/broadband_snmp_get.html index 61bb9c763..d4cc4e49d 100644 --- a/httemplate/elements/broadband_snmp_get-dialog.html +++ b/httemplate/elements/broadband_snmp_get.html @@ -1,9 +1,10 @@ <%doc> -Adds a link to display snmp statistics based on broadband_snmp_get export config. -Performs necessary checks such that, if no such exports are configured for the passed -service, returns blank space (ie may be safely invoked even if no exports are configured.) +Adds a table to display dynamically loaded snmp statistics based on broadband_snmp_get +export config. Performs necessary checks such that, if no such exports are configured +for the passed service, returns blank space (ie may be safely invoked even if no exports +are configured.) - <& '/elements/broadband_snmp_get-dialog.html', svc => $svc &> + <& '/elements/broadband_snmp_get.html', svc => $svc &> </%doc> % if (@snmp) { @@ -11,13 +12,10 @@ service, returns blank space (ie may be safely invoked even if no exports are co 'url' => $fsurl.'misc/xmlhttp-broadband_snmp_get.cgi', 'subs' => [ 'broadband_snmp_get_request' ] &> +<DIV ID="broadband_snmp_get"></DIV> <SCRIPT> function broadband_snmp_get (svcnum) { - var jqd = $( '#broadband_snmp_get_dialog' ); - if (!jqd.dialog( 'isOpen' )) { - jqd.dialog( 'open' ); - } - document.getElementById('broadband_snmp_get_dialog').innerHTML = '<B>Loading...</B>'; + document.getElementById('broadband_snmp_get').innerHTML = 'Loading SNMP...'; broadband_snmp_get_request('svcnum',svcnum, function (result) { var objects = JSON.parse(result) || []; @@ -41,24 +39,14 @@ function broadband_snmp_get (svcnum) { } table.appendChild(row); } - var dialog = document.getElementById('broadband_snmp_get_dialog'); - dialog.innerHTML = ''; - dialog.appendChild(table); + var resultblock = document.getElementById('broadband_snmp_get'); + resultblock.innerHTML = ''; + resultblock.appendChild(table); } // if objects.length } // function ); // broadband_snmp_get_request } // broadband_snmp_get -</SCRIPT> -<SPAN ID="broadband_snmp_get_dialog"></SPAN> -<SPAN ID="broadband_snmp_get_link"> -<A HREF="javascript: void(0)" onclick="broadband_snmp_get('<% $svcnum %>')">(snmp)</A> -</SPAN> -<SCRIPT> -$( '#broadband_snmp_get_dialog' ).dialog({ - position: { my: "left top", at: "left top", of: "#broadband_snmp_get_link" }, - autoOpen: false, - title: 'SNMP', -}); +broadband_snmp_get('<% $svcnum %>'); </SCRIPT> % } #if @snmp <%init> diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index fa44e86e7..a3bfeb7b0 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -227,10 +227,12 @@ foreach my $svcdb ( FS::part_svc->svc_tables() ) { ]; } - $report_svc{"Advanced $lcsname reports"} = + if ( $curuser->access_right("Services: $name: Advanced search") + && $svcdb =~ /^svc_(acct|broadband|hardware|phone|fiber)$/ ) { + + $report_svc{"Advanced $lcsname reports"} = [ $fsurl."search/report_$svcdb.html", '' ] - if $svcdb =~ /^svc_(acct|broadband|hardware|phone)$/ - && $curuser->access_right("Services: $name: Advanced search"); + } if ( $svcdb eq 'svc_phone' ) { @@ -594,6 +596,10 @@ tie my %config_circuit, 'Tie::IxHash', 'Termination types' => [ $fsurl.'browse/circuit_termination.html', '' ], ; +tie my %config_fiber, 'Tie::IxHash', + 'OLTs' => [ $fsurl.'browse/fiber_olt.html', '' ], +; + tie my %config_export_svc, 'Tie::IxHash', (); if ( $curuser->access_right('Configuration') ) { $config_export_svc{'Service definitions'} = [ $fsurl.'browse/part_svc.cgi', 'Services are items you offer to your customers' ]; @@ -617,6 +623,8 @@ $config_export_svc{'Alarm'} = [ \%config_alarm, '' ] if $curuser->access_right(['Alarm configuration', 'Alarm global configuration']); $config_export_svc{'Circuits'} = [ \%config_circuit, '' ] if $curuser->access_right('Configuration'); +$config_export_svc{'Fiber'} = [ \%config_fiber, '' ] + if $curuser->access_right('Configuration'); $config_export_svc{'Hardware types'} = [ $fsurl.'browse/hardware_class.html', 'Set up hardware type catalog' ] if $curuser->access_right('Configuration'); diff --git a/httemplate/elements/standardize_locations.js b/httemplate/elements/standardize_locations.js index b824fb249..0c4fb029a 100644 --- a/httemplate/elements/standardize_locations.js +++ b/httemplate/elements/standardize_locations.js @@ -114,7 +114,12 @@ function confirm_standardize(arg) { // then all entered address fields are correct // but we still need to set the lat/long fields and addr_clean - status_message('Verified'); + + if ( returned['addr_clean'] ) { + status_message('Verified'); + } else { + status_message('Unverified'); + } replace_address(); } else { diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi index f3a31eb3b..c4bc37e93 100644 --- a/httemplate/misc/download-batch.cgi +++ b/httemplate/misc/download-batch.cgi @@ -1,4 +1,4 @@ -<% $pay_batch->export_batch(%opt) %><%init> +<% $exporttext %><%init> #http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes http_header('Content-Type' => 'text/plain' ); # not necessarily correct... @@ -23,4 +23,15 @@ elsif ( $cgi->param('format') =~ /^([\w\- ]+)$/ ) { my $pay_batch = qsearchs('pay_batch', { batchnum => $batchnum } ); die "Batch not found: '$batchnum'" if !$pay_batch; +my $exporttext = $pay_batch->export_batch(%opt); +unless ($exporttext) { + http_header('Content-Type' => 'text/html' ); + $exporttext = <<EOF; +<SCRIPT> +alert('Batch was empty, and has been resolved'); +window.top.location.href = '${p}search/pay_batch.cgi?magic=_date;open=1;intransit=1;resolved=1'; +</SCRIPT> +EOF +} + </%init> diff --git a/httemplate/search/cust_msg.html b/httemplate/search/cust_msg.html index e9aece202..2bfbd7cb0 100644 --- a/httemplate/search/cust_msg.html +++ b/httemplate/search/cust_msg.html @@ -59,8 +59,10 @@ my $conf = new FS::Conf; my $title = 'Outgoing Message Log'; #here is the agent virtualization -my $agentnums_sql = - $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' ); +my $agentnums_sql = $FS::CurrentUser::CurrentUser->agentnums_sql( + 'table' => 'cust_main', + 'null_right' => [ 'View system logs', 'Configuration' ], +); my @where = ( $agentnums_sql ); diff --git a/httemplate/search/log.html b/httemplate/search/log.html index a707928d7..b607f505d 100644 --- a/httemplate/search/log.html +++ b/httemplate/search/log.html @@ -138,7 +138,7 @@ my $tt_sub = sub { return '' if @context == 1 and length($log->message) <= 60; my $html = '<DIV CLASS="tooltip">'.(shift @context).'</DIV>'; my $pre = '↳'; - foreach (@context, $log->message) { + foreach (map encode_entities($_), @context, $log->message) { $html .= "<DIV>$pre$_</DIV>"; $pre = ' '.$pre; } diff --git a/httemplate/search/report_svc_fiber.html b/httemplate/search/report_svc_fiber.html new file mode 100755 index 000000000..d563c5339 --- /dev/null +++ b/httemplate/search/report_svc_fiber.html @@ -0,0 +1,47 @@ +<& /elements/header.html, $title &> + +<FORM ACTION="svc_fiber.html" METHOD="GET"> + + <TABLE BGCOLOR="#cccccc" CELLSPACING=0> + <TR> + <TH CLASS="background" COLSPAN=2 ALIGN="left"><FONT SIZE="+1">Search options</FONT></TH> + </TR> + + <& /elements/tr-select-table.html, + label => 'OLT', + table => 'fiber_olt', + name_col => 'oltname', + &> + <& /elements/tr-input-text.html, field => 'shelf', label => 'Shelf' &> + <& /elements/tr-input-text.html, field => 'card', label => 'Card' &> + <& /elements/tr-input-text.html, field => 'olt_port', label => 'Port' &> + + <& /elements/tr-td-label.html, label => 'ONT model' &> + <TD> + <& /elements/select-hardware_type.html, + 'empty_label' => '(all)' + &> + </TD> + </TR> + + <& /elements/tr-input-text.html, field => 'ont_serial', label => 'Serial number' &> + <& /elements/tr-input-text.html, field => 'vlan', label => 'VLAN' &> + </TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Search"> + +</FORM> + +<& /elements/footer.html &> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Services: Fiber'); + +my $title = 'Search Fiber Services'; + +my @olts = qsearch('fiber_olt', {}); + +</%init> + diff --git a/httemplate/search/svc_fiber.html b/httemplate/search/svc_fiber.html new file mode 100644 index 000000000..0cb735c96 --- /dev/null +++ b/httemplate/search/svc_fiber.html @@ -0,0 +1,69 @@ +<& elements/svc_Common.html, + 'title' => 'Fiber Search Results', + 'name' => 'fiber services', + 'query' => $query, + 'count_query' => $query->{'count_query'}, + 'redirect' => $link, + 'header' => [ '#', + 'OLT', + 'Shelf/Card/Port', + 'ONT', + 'Model', + 'Serial', + FS::UI::Web::cust_header($cgi->param('cust_fields')), + ], + 'fields' => [ 'svcnum', + 'oltname', + sub { my $svc = shift; + join('-', $svc->shelf, $svc->card, $svc->olt_port) + }, + 'ont_id', + 'ont_description', + 'ont_serial', + \&FS::UI::Web::cust_fields, + ], + 'links' => [ $link, + '', + '', + $link, + $link, + $link, + FS::UI::Web::cust_links($cgi->param('cust_fields')), + ], + 'align' => 'rlllll'. FS::UI::Web::cust_aligns(), + 'color' => [ + ('') x 6, + FS::UI::Web::cust_colors(), + ], + 'style' => [ + ('') x 6, + FS::UI::Web::cust_styles(), + ], + +&> +<%init> + +die "access denied" unless + $FS::CurrentUser::CurrentUser->access_right([ 'Services: Fiber', + 'List services' + ]); + +my $conf = new FS::Conf; + +my %search_hash; +if ( $cgi->param('magic') eq 'unlinked' ) { + %search_hash = ( 'unlinked' => 1 ); +} else { + foreach (qw( custnum agentnum svcpart cust_fields + ont_typenum oltnum shelf olt_port card vlan )) { + $search_hash{$_} = $cgi->param($_) if defined($cgi->param($_)); + } +} + +my $query = FS::svc_fiber->search(\%search_hash); +$query->{addl_from} .= ' LEFT JOIN fiber_olt USING (oltnum) '; +$query->{select} .= ', oltname'; + +my $link = [ $p.'view/svc_fiber.cgi?', 'svcnum' ]; + +</%init> diff --git a/httemplate/view/cust_main/packages/location.html b/httemplate/view/cust_main/packages/location.html index 99d91e514..595d6b3b1 100644 --- a/httemplate/view/cust_main/packages/location.html +++ b/httemplate/view/cust_main/packages/location.html @@ -91,7 +91,7 @@ sub pkg_change_location_link { 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, 'width' => 960, - 'height' => 490, + 'height' => 530, ); } diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html index e98b95e1c..dec1c6f40 100644 --- a/httemplate/view/cust_main/packages/package.html +++ b/httemplate/view/cust_main/packages/package.html @@ -371,7 +371,7 @@ sub pkg_change_location_link { 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, 'width' => 960, - 'height' => 490, + 'height' => 530, ); } diff --git a/httemplate/view/svc_broadband.cgi b/httemplate/view/svc_broadband.cgi index bc272e844..0517c307a 100644 --- a/httemplate/view/svc_broadband.cgi +++ b/httemplate/view/svc_broadband.cgi @@ -72,7 +72,6 @@ sub ip_addr { my $out = $ip_addr; $out .= ' (' . include('/elements/popup_link-ping.html', ip => $ip_addr) . ')' if $ip_addr; - $out .= include('/elements/broadband_snmp_get-dialog.html', svc => $svc); if ($svc->cust_svc->part_svc->part_export('cacti')) { $out .= ' (<A HREF="' . popurl(2) @@ -84,6 +83,7 @@ sub ip_addr { $out .= '<br>Netmask: ' . $addr_block->NetAddr->mask . '<br>Gateway: ' . $addr_block->ip_gateway; } + $out .= include('/elements/broadband_snmp_get.html', svc => $svc); $out; } diff --git a/httemplate/view/svc_fiber.cgi b/httemplate/view/svc_fiber.cgi new file mode 100644 index 000000000..ce9c03dc7 --- /dev/null +++ b/httemplate/view/svc_fiber.cgi @@ -0,0 +1,34 @@ +<& elements/svc_Common.html, + 'table' => 'svc_fiber', + 'fields' => \@fields, + 'labels' => \%labels, + 'edit_url' => $fsurl.'edit/svc_fiber.html?', +&> +<%init> + +my @fields = ( + { field => 'oltnum', + type => 'select-table', + table => 'fiber_olt', + name_col => 'oltname', + }, + 'shelf', + 'card', + 'olt_port', + 'ont_id', + 'ont_description', + 'ont_serial', + 'ont_port', + 'vlan', + 'signal', + 'speed_down', + 'speed_up', + 'ont_install', +); + +my $fields = FS::svc_fiber->table_info->{'fields'}; +my %labels = map { $_ => $fields->{$_}{'label'} } keys %$fields; + +$labels{'ont_description'} = 'ONT model'; + +</%init> diff --git a/rt/share/html/Admin/Queues/Tasks.html b/rt/share/html/Admin/Queues/Tasks.html index 94df549cc..e8f8468f9 100755 --- a/rt/share/html/Admin/Queues/Tasks.html +++ b/rt/share/html/Admin/Queues/Tasks.html @@ -4,22 +4,6 @@ <form action="Tasks.html" method="post"> <input type="hidden" name="Queue" value="<% $Queue %>" /> -<h2> - <label for="ConditionCF"><&|/l&>Enabled if</&>:</label> -% if ( $PossibleCustomFields->Count > 0 ) { - <select name="ConditionCF"> -% while ( my $thiscf = $PossibleCustomFields->Next ) { - <option value="<% $thiscf->Id %>" <% $thiscf->Id == $cfid ? 'selected' : '' %>><% $thiscf->Name %></option> -% } - </select> - <label for="ConditionValue"><&|/l&>equals</&></label> - <input name="ConditionValue" value="<% $cfvalue %>" /> -% } else { - <select name="no_cfs" disabled> - <option value="1">(no custom fields defined)</option> - </select> -% } -</h2> <table> % my (@links, @postponed); # not really used here % my $idx = 1; @@ -93,6 +77,7 @@ my $title = loc("Set up subtasks for queue [_1]", $QueueObj->Name); my $TEMPLATE_NAME = '[Subtask]'; my $SCRIPCONDITION_NAME = '[Subtask] Queue='.$Queue; my $SUBJECT_PREFIX = q({ $TOP->Subject }-); +my $CUSTOMFIELD_NAME = 'Create subtasks'; my ($Scrip, $ScripCondition, $Template, $CustomField); @@ -112,20 +97,17 @@ $Scrip = RT::Scrip->new($RT::SystemUser); { my $Scrips = RT::Scrips->new($RT::SystemUser); $Scrips->LimitToQueue($Queue); - $Scrips->Limit( FIELD => 'Template', VALUE => $Template->Id ); + $Scrips->Limit( FIELD => 'Template', VALUE => $Template->Name ); if ( $Scrips->Count > 0 ) { $Scrip = $Scrips->First; } } -# The CF name to test, and the value it must have to trigger the scrip. -my $cfid = $ARGS{ConditionCF}; -my $cfvalue = $ARGS{ConditionValue}; -$CustomField = RT::CustomField->new($session{'CurrentUser'}); -if ( $cfid ) { - $CustomField->Load($cfid); -} -my $cfname = $CustomField->Name; +my $CustomField = RT::CustomField->new($RT::SystemUser); +$CustomField->LoadByName( + Name => $CUSTOMFIELD_NAME, + LookupType => 'RT::Queue-RT::Ticket', +); # if there's input from the form, process it into a new template content my $new_content = ''; @@ -138,7 +120,7 @@ if ( $ARGS{task_id} ) { # actually contains numeric indices my %task_opts = map { $_ => $ARGS{$_} } grep /^$task_id-/, keys(%ARGS); my $task_content = "===Create-Ticket: $task_id -CF-$cfname:" . q[ +CF-$CUSTOMFIELD_NAME" . q[ Depended-On-By: TOP Owner: { $TOP->Owner } { join("\n", map { "Requestor: $_" } @@ -173,6 +155,45 @@ Owner: { $TOP->Owner } } } + # set up custom field, if necessary + if ( ! $CustomField->Id ) { + # should be RenderType 'Checkbox', but there isn't one yet... + my ($val, $msg) = $CustomField->Create( + Name => $CUSTOMFIELD_NAME, + Type => 'Select', + MaxValues => 1, + LookupType => 'RT::Queue-RT::Ticket', + Description => 'Start subtasks for this ticket', + RenderType => 'Dropdown', + ); + if ($val) { + # should be impossible for this to fail + ($val, $msg) = $CustomField->AddValue(Name => 'Yes'); + } + if (!$val) { + push @results, loc("Could not create ticket custom field: [_1]", $msg); + } else { + push @results, loc("Custom field created"); + } + } + + # apply CF to the queue, iff there are any tasks set up + if ( length($new_content) and ! $CustomField->IsAdded($Queue) ) { + my ($val, $msg) = $CustomField->AddToObject($QueueObj); + if (!$val) { + push @results, loc("Could not apply custom field to this queue: [_1]", $msg); + } else { + push @results, loc("Applied custom field to this queue"); + } + } elsif ( ! length($new_content) and $CustomField->IsAdded($Queue) ) { + my ($val, $msg) = $CustomField->RemoveFromObject($QueueObj); + if (!$val) { + push @results, loc("Could not remove custom field from this queue: [_1]", $msg); + } else { + push @results, loc("Removed custom field from this queue"); + } + } + if ( ! $Template->Id ) { my ( $val, $msg ) = $Template->Create( Queue => $Queue, @@ -196,16 +217,12 @@ Owner: { $TOP->Owner } } # Set up ScripCondition - if ( !$cfname ) { - push @results, loc("No custom field selected"); - } elsif ( length($cfvalue) == 0 ) { - push @results, loc("Custom field value is required"); - } elsif ( ! $ScripCondition->Id ) { + if ( ! $ScripCondition->Id ) { my ( $val, $msg ) = $ScripCondition->Create( Name => $SCRIPCONDITION_NAME, - Description => "When CF.[$cfname] equals '$cfvalue'", + Description => "When CF.[$CUSTOMFIELD_NAME] equals 'Yes'", ExecModule => 'CustomFieldEquals', - Argument => "$cfname=$cfvalue", + Argument => "$CUSTOMFIELD_NAME=Yes", ApplicableTransTypes => 'Any', ); if (!$val) { @@ -213,8 +230,8 @@ Owner: { $TOP->Owner } } else { push @results, loc("Custom field condition created"); } - } elsif ( $ScripCondition->Argument ne "$cfname=$cfvalue" ) { - my ( $val, $msg ) = $ScripCondition->SetArgument("$cfname=$cfvalue"); + } elsif ( $ScripCondition->Argument ne "$CUSTOMFIELD_NAME=Yes" ) { + my ( $val, $msg ) = $ScripCondition->SetArgument("$CUSTOMFIELD_NAME=Yes"); if (!$val) { push @results, loc("Could not set custom field condition: [_1]", $msg); } else { @@ -259,8 +276,6 @@ $Action->Parse( my @task_ids; @task_ids = @{ $Action->{create_tickets} } if exists $Action->{create_tickets}; -my $PossibleCustomFields = $QueueObj->TicketCustomFields; - </%init> <%ARGS> $Queue => undef #queue id |