diff options
Diffstat (limited to 'FS')
| -rw-r--r-- | FS/FS.pm | 2 | ||||
| -rw-r--r-- | FS/FS/Mason.pm | 1 | ||||
| -rw-r--r-- | FS/FS/Schema.pm | 16 | ||||
| -rw-r--r-- | FS/FS/dsl_note.pm | 127 | ||||
| -rw-r--r-- | FS/FS/part_export/ikano.pm | 162 | ||||
| -rw-r--r-- | FS/FS/svc_dsl.pm | 16 | ||||
| -rw-r--r-- | FS/MANIFEST | 2 | ||||
| -rw-r--r-- | FS/t/dsl_note.t | 5 | 
8 files changed, 318 insertions, 13 deletions
| @@ -150,6 +150,8 @@ L<FS::svc_broadband> - DSL, wireless and other broadband class.  L<FS::svc_dsl> - DSL +L<FS::dsl_note> - DSL order notes +  L<FS::addr_block> - Address block class  L<FS::router> - Router class diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index cb8130f73..c13207474 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -261,6 +261,7 @@ if ( -e $addl_handler_use_file ) {    use FS::svc_dsl;    use FS::qual;    use FS::qual_option; +  use FS::dsl_note;    # Sammath Naur    if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index e95e1f704..281ca6ba1 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1861,13 +1861,25 @@ sub tables_hashref {          'staticips',             'text', 'NULL', '',  '', '',          'monitored',   	'char', 'NULL',       1,  '', '',   	'last_pull',     'int', 'NULL',       '', '', '', -	'notes',     'text', 'NULL',       '', '', '',        ],        'primary_key' => 'svcnum',        'unique' => [ ],        'index' => [ ['phonenum'], ['vendor_order_id'] ],      }, - +     +    'dsl_note' => { +      'columns' => [ +        'notenum',           'serial',    '',        '', '', '', +	'svcnum',     'int', '',       '', '', '', +        'by',              'varchar', 'NULL', $char_d,  '', '', +        'priority',   'char', 'NULL',       1,  '', '',  +	'date',     'int', 'NULL',       '', '', '', +	'note',     'text', '',       '', '', '', +      ], +      'primary_key' => 'notenum', +      'unique' => [ ], +      'index' => [ ['svcnum'] ], +    },      'domain_record' => {        'columns' => [ diff --git a/FS/FS/dsl_note.pm b/FS/FS/dsl_note.pm new file mode 100644 index 000000000..886365b68 --- /dev/null +++ b/FS/FS/dsl_note.pm @@ -0,0 +1,127 @@ +package FS::dsl_note; + +use strict; +use base qw( FS::Record ); +use FS::Record qw( qsearch qsearchs ); + +=head1 NAME + +FS::dsl_note - Object methods for dsl_note records + +=head1 SYNOPSIS + +  use FS::dsl_note; + +  $record = new FS::dsl_note \%hash; +  $record = new FS::dsl_note { 'column' => 'value' }; + +  $error = $record->insert; + +  $error = $new_record->replace($old_record); + +  $error = $record->delete; + +  $error = $record->check; + +=head1 DESCRIPTION + +An FS::dsl_note object represents a DSL order note.  FS::dsl_note inherits from +FS::Record.  The following fields are currently supported: + +=over 4 + +=item notenum - primary key + +=item svcnum - the DSL for this note, see L<FS::svc_dsl> + +=item by - export-specific, e.g. note's author or ISP vs. telco/vendor + +=item priority - export-specific, e.g. high priority or not; not used by most + +=item date - note date + +=item note - the note + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new note.  To add the note to the database, see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to.  You can ask the object for a copy with the I<hash> method. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'dsl_note'; } + +=item insert + +Adds this record to the database.  If there is an error, returns the error, +otherwise returns false. + +=cut + +# the insert method can be inherited from FS::Record + +=item delete + +Delete this record from the database. + +=cut + +# the delete method can be inherited from FS::Record + +=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. + +=cut + +# the replace method can be inherited from FS::Record + +=item check + +Checks all fields to make sure this is a valid note.  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('notenum') +    || $self->ut_foreign_key('svcnum', 'svc_dsl', 'svcnum') +    || $self->ut_textn('by') +    || $self->ut_alphasn('priority') +    || $self->ut_numbern('date') +    || $self->ut_text('note') +  ; +  return $error if $error; + +  $self->SUPER::check; +} + +=back + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/part_export/ikano.pm b/FS/FS/part_export/ikano.pm index 50fa29221..f162f2523 100644 --- a/FS/FS/part_export/ikano.pm +++ b/FS/FS/part_export/ikano.pm @@ -3,6 +3,7 @@ package FS::part_export::ikano;  use vars qw(@ISA %info %orderType %orderStatus %loopType $DEBUG $me);  use Tie::IxHash;  use Date::Format qw( time2str ); +use Date::Parse qw( str2time );  use FS::Record qw(qsearch qsearchs);  use FS::part_export;  use FS::svc_dsl; @@ -44,10 +45,157 @@ END  sub rebless { shift; }  sub dsl_pull { +# we distinguish between invalid new data (return error) versus data that +# has legitimately changed (may eventually execute hooks; now just update) + +    my($self, $svc_dsl) = (shift, shift); +    my $result = $self->valid_order($svc_dsl,'pull'); +    return $result unless $result eq ''; +   +    $result = $self->ikano_command('ORDERSTATUS',  +	{ OrderId => $svc_dsl->vendor_order_id } );  +    return $result unless ref($result); # scalar (string) is an error + +    # now we're getting an OrderResponse which should have one Order in it +    warn "$me pull OrderResponse hash:\n".Dumper($result) if $DEBUG; +   +    return 'Invalid order response' unless defined $result->{'Order'}; +    $result = $result->{'Order'}; + +    return 'No order id or status returned'  +	unless defined $result->{'Status'} && defined $result->{'OrderId'}; + +    # update this always (except in the above cases), even if error later +    $svc_dsl->last_pull((time)); +    local $FS::svc_Common::noexport_hack = 1; +    local $FS::UID::AutoCommit = 1; +    my $error = $svc_dsl->replace;  +    return 'Error updating last pull time' if $error; + +    # let's compare what we have to what we got back... +  +    # current assumptions of what won't change (from their side): +    # vendor_order_id, vendor_qual_id, vendor_order_type, pushed, monitored, +    # last_pull, address (from qual), contact info, ProductCustomId + +    my $wechanged = 0; + +    # 1. status  +    my $new_order_status = $self->orderstatus_long2short($result->{'Status'}); +    return 'Invalid new status' if $new_order_status eq ''; +    if($svc_dsl->vendor_order_status ne $new_order_status) { +	if($new_order_status eq 'X' || $new_order_status eq 'C') { +	    $svc_dsl->monitored(''); +	} +	$svc_dsl->vendor_order_status($new_order_status); +	$wechanged = 1; +    } + +    # 2. fields we don't care much about +    my %justUpdate = ( 'first' => 'FirstName', +		    'last' => 'LastName', +		    'company' => 'CompanyName', +		    'username' => 'Username', +		    'password' => 'Password' ); + +    while (($fsf, $ikanof) = each %justUpdate) { +       if ( $result->{$ikanof} ne $svc_dsl->$fsf ) { +	    $svc_dsl->$fsf($result->{$ikanof}); +	    $wechanged = 1; +	} +    } + +    # let's look inside the <Product> response element +    my @product = $result->{'Product'};  +    return 'Invalid number of products on order' if scalar(@product) != 1; +    my $product = $result->{'Product'}[0]; + +    # 3. phonenum  +    if($svc_dsl->loop_type eq '') { # line-share +	# TN may change only if sub changes it and  +	# New or Change order in Completed status +	my $tn = $product->{'PhoneNumber'}; +	if($tn ne $svc_dsl->phonenum) { +	    if( ($svc_dsl->vendor_order_type eq 'N'  +		|| $svc_dsl->vendor_order_type eq 'C') +	       && $svc_dsl->vendor_order_status eq 'C' ) { +		$svc_dsl->phonenum($tn); +		$wechanged = 1; +	    } +	    else { return 'TN has changed in an invalid state'; } +	} +    } +    elsif($svc_dsl->loop_type eq '0') { # dry loop +	return 'Invalid PhoneNumber value for a dry loop'  +	    if $product->{'PhoneNumber'} ne 'STANDALONE'; +	my $tn = $product->{'VirtualPhoneNumber'}; +	if($tn ne $svc_dsl->phonenum) { +	    if( ($svc_dsl->vendor_order_type eq 'N'  +		|| $svc_dsl->vendor_order_type eq 'C') +	      && $svc_dsl->vendor_order_status ne 'C' +	      && $svc_dsl->vendor_order_status ne 'X') { +		$svc_dsl->phonenum($tn); +		$wechanged = 1; +	    } +	} +    } +     +    # 4. desired_due_date - may change if manually changed +    if($svc_dsl->vendor_order_type eq 'N'  +	    || $svc_dsl->vendor_order_type eq 'C'){ +	my $f = str2time($product->{'DateToOrder'}); +	return 'Invalid DateToOrder' unless $f; +	if ( $svc_dsl->desired_due_date != $f ) { +	    $svc_dsl->desired_due_date($f); +	    $wechanged = 1; +	} +	# XXX: optionally sync back to start_date or whatever...  +    } +    elsif($svc_dsl->vendor_order_type eq 'X'){ +	my $f = str2time($product->{'DateToDisconnect'}); +	return 'Invalid DateToDisconnect' unless $f; +	if ( $svc_dsl->desired_due_date != $f ) { +	    $svc_dsl->desired_due_date($f); +	    $wechanged = 1; +	} +	# XXX: optionally sync back to expire or whatever...  +    } + +    # 4. due_date +    if($svc_dsl->vendor_order_type eq 'N'  + 	  || $svc_dsl->vendor_order_type eq 'C') { +	my $f = str2time($product->{'ActivationDate'}); +	if($svc_dsl->vendor_order_status ne 'N') { +	    return 'Invalid ActivationDate' unless $f; +	    if( $svc_dsl->due_date != $f ) { +		$svc_dsl->due_date($f); +		$wechanged = 1; +	    } +	} +    } +    # Ikano API does not implement the proper disconnect date, +    # so we can't do anything about it + +    # 6. staticips - for now just comma-separate them +    my @statics = $result->{'StaticIps'}; +# XXX + +    # 7. notes - put them into the common format: +    # "by" = 0 for Ikano; 1 for ISP +    # "priority" = 1 for high priority; 0 otherwise +    my @notes = $result->{'OrderNotes'};  +# XXX + +    if($wechanged) { # you can't check ->modified, the replace above screws it +	# noexport_hack and AutoCommit are set correctly above +	$result = $svc_dsl->replace;  +	return 'Error updating DSL data' if $result; +    } +      '';  } -sub dsl_qual { +sub qual {      '';  } @@ -109,6 +257,11 @@ sub valid_order {    # weird ifs & long lines for readability and ease of understanding - don't change    if($svc_dsl->vendor_order_type eq 'N') {      if($svc_dsl->pushed) { +	$error = !($action eq 'pull' +	    && 	length($svc_dsl->vendor_order_id) > 0 +	    && 	length($svc_dsl->vendor_order_status) > 0 +		); +	return 'Invalid order data' if $error;      }      else { # unpushed New order - cannot do anything other than push it  	$error = !($action eq 'insert' @@ -147,10 +300,9 @@ sub qual2termsid {  sub orderstatus_long2short {      my ($self,$order_status) = (shift,shift); -    while (($k, $v) = each %orderStatus) { -	return $k if $v eq $order_status; -    } -    return ''; +    my %rorderStatus = reverse %orderStatus; +    return $rorderStatus{$order_status} if exists $rorderStatus{$order_status}; +    '';  }  sub _export_insert { diff --git a/FS/FS/svc_dsl.pm b/FS/FS/svc_dsl.pm index da62dc6bb..2c30b006e 100644 --- a/FS/FS/svc_dsl.pm +++ b/FS/FS/svc_dsl.pm @@ -99,10 +99,6 @@ Ikano-specific fields, do not use otherwise  =item last_pull - time of last data pull from vendor/telco -=item notes - -DSL order notes placed by staff or vendor/telco on the vendor/telco order -  =back @@ -171,7 +167,6 @@ sub table_info {  	    'monitored' => {	label => 'Monitored',   				type => 'checkbox', %dis2 },  	    'last_pull' => { 	label => 'Last Pull', type => 'disabled' }, -	    'notes' => { 	label => 'Order Notes', %dis1 },  	},      };  } @@ -186,6 +181,16 @@ sub label {     return $self->svcnum;  } +=item notes + +Returns the set of FS::dsl_notes associated with this service + +=cut  +sub notes { +  my $self = shift; +  qsearch( 'dsl_note', { 'svcnum' => $self->svcnum } ); +} +  =item insert  Adds this record to the database.  If there is an error, returns the error, @@ -250,7 +255,6 @@ sub check {      || $self->ut_textn('staticips')      || $self->ut_enum('monitored',    [ '', 'Y' ])      || $self->ut_numbern('last_pull') -    || $self->ut_textn('notes')    ;    return $error if $error; diff --git a/FS/MANIFEST b/FS/MANIFEST index bd37d7be2..b58b58e20 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -546,3 +546,5 @@ FS/qual.pm  t/qual.t  FS/qual_option.pm  t/qual_option.t +FS/dsl_note.pm +t/dsl_note.t diff --git a/FS/t/dsl_note.t b/FS/t/dsl_note.t new file mode 100644 index 000000000..6fb698743 --- /dev/null +++ b/FS/t/dsl_note.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::dsl_note; +$loaded=1; +print "ok 1\n"; | 
