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 /FS | |
parent | 2040b70c10db3390b26777bc584d54333534419d (diff) | |
parent | 7ec6e27220e3fe82405c911a4c52b24070438328 (diff) |
Merge branch 'master' of git.freeside.biz:/home/git/freeside
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/AccessRight.pm | 2 | ||||
-rw-r--r-- | FS/FS/Conf.pm | 1 | ||||
-rw-r--r-- | FS/FS/Mason.pm | 2 | ||||
-rw-r--r-- | FS/FS/Misc/Geo.pm | 8 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 46 | ||||
-rw-r--r-- | FS/FS/cust_main/Billing.pm | 27 | ||||
-rw-r--r-- | FS/FS/cust_main/Billing_Batch.pm | 19 | ||||
-rw-r--r-- | FS/FS/fiber_olt.pm | 106 | ||||
-rw-r--r-- | FS/FS/geocode_Mixin.pm | 2 | ||||
-rw-r--r-- | FS/FS/log.pm | 3 | ||||
-rw-r--r-- | FS/FS/log_context.pm | 1 | ||||
-rw-r--r-- | FS/FS/msg_template.pm | 23 | ||||
-rw-r--r-- | FS/FS/msg_template/InitialData.pm | 14 | ||||
-rw-r--r-- | FS/FS/part_export/broadband_snmp_get.pm | 3 | ||||
-rw-r--r-- | FS/FS/pay_batch.pm | 33 | ||||
-rw-r--r-- | FS/FS/svc_fiber.pm | 323 | ||||
-rw-r--r-- | FS/MANIFEST | 2 | ||||
-rwxr-xr-x | FS/bin/freeside-eftca-upload | 4 | ||||
-rwxr-xr-x | FS/bin/freeside-paymentech-upload | 5 | ||||
-rwxr-xr-x | FS/bin/freeside-rbc-upload | 4 | ||||
-rw-r--r-- | FS/t/fiber_olt.t | 5 |
21 files changed, 610 insertions, 23 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"; |