[freeside-commits] branch master updated. 7c41eea8dca02a399739c29a0dfbda7efdd6df86

Ivan ivan at 420.am
Tue May 14 00:29:06 PDT 2013


The branch, master has been updated
       via  7c41eea8dca02a399739c29a0dfbda7efdd6df86 (commit)
       via  7a33a40d9f17d73e7f14410070675da02e25ad5e (commit)
      from  080f96d15c8fb9aa02527670707840f6f5ef1e2b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 7c41eea8dca02a399739c29a0dfbda7efdd6df86
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Tue May 14 00:28:33 2013 -0700

    svc_cable, RT#22009

diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm
index 373617e..4753d31 100644
--- a/FS/FS/AccessRight.pm
+++ b/FS/FS/AccessRight.pm
@@ -293,6 +293,7 @@ tie my %rights, 'Tie::IxHash',
     'Services: Wireless broadband services',
     'Services: Wireless broadband services: Advanced search',
     'Services: DSLs',
+    'Services: Cable subscribers',
     'Services: Dish services',
     'Services: Hardware',
     'Services: Hardware: Advanced search',
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 28c7fc4..ed23d31 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -4129,6 +4129,30 @@ sub tables_hashref {
       'index' => [],
     },
 
+    'svc_cable' => {
+      'columns' => [
+        'svcnum',         'int',     '',      '', '', '', 
+        #nothing so far...  there should be _something_ uniquely identifying
+        # each subscriber besides the device info...?
+      ],
+      'primary_key' => 'svcnum',
+      'unique' => [],
+      'index'  => [],
+    },
+
+    'cable_device' => {
+      'columns' => [
+        'devicenum', 'serial',     '',      '', '', '',
+        'devicepart',   'int',     '',      '', '', '',
+        'svcnum',       'int',     '',      '', '', '', 
+        'mac_addr', 'varchar', 'NULL',      12, '', '', 
+        'serial',   'varchar', 'NULL', $char_d, '', '',
+      ],
+      'primary_key' => 'devicenum',
+      'unique' => [ [ 'mac_addr' ], ],
+      'index'  => [ [ 'devicepart' ], [ 'svcnum' ], ],
+    },
+
     %{ tables_hashref_torrus() },
 
     # tables of ours for doing torrus virtual port combining
diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm
index 5bcf922..a42d7f2 100644
--- a/FS/FS/access_right.pm
+++ b/FS/FS/access_right.pm
@@ -233,6 +233,7 @@ sub _upgrade_data { # class method
                              'Employees: Audit Report',
                            ],
     'Change customer package' => 'Detach customer package',
+    'Services: Accounts' => 'Services: Cable Subscribers',
 ;
 
   foreach my $old_acl ( keys %onetime ) {
diff --git a/FS/FS/cable_device.pm b/FS/FS/cable_device.pm
new file mode 100644
index 0000000..1a0f1b9
--- /dev/null
+++ b/FS/FS/cable_device.pm
@@ -0,0 +1,140 @@
+package FS::cable_device;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearchs ); # qsearch );
+use FS::part_device;
+use FS::svc_cable;
+
+=head1 NAME
+
+FS::cable_device - Object methods for cable_device records
+
+=head1 SYNOPSIS
+
+  use FS::cable_device;
+
+  $record = new FS::cable_device \%hash;
+  $record = new FS::cable_device { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cable_device object represents a specific customer cable modem.
+FS::cable_device inherits from FS::Record.  The following fields are currently
+supported:
+
+=over 4
+
+=item devicenum
+
+primary key
+
+=item devicepart
+
+devicepart
+
+=item svcnum
+
+svcnum
+
+=item mac_addr
+
+mac_addr
+
+=item serial
+
+serial
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record.  To add the record 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
+
+sub table { 'cable_device'; }
+
+=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 record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $mac = $self->mac_addr;
+  $mac =~ s/\s+//g;
+  $mac =~ s/://g;
+  $self->mac_addr($mac);
+
+  my $error = 
+    $self->ut_numbern('devicenum')
+    || $self->ut_number('devicepart')
+    || $self->ut_foreign_key('devicepart', 'part_device', 'devicepart')
+    || $self->ut_foreign_key('svcnum', 'svc_cable', 'svcnum' ) #cust_svc?
+    || $self->ut_hexn('mac_addr')
+    || $self->ut_textn('serial')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item part_device
+
+Returns the device type record (see L<FS::part_device>) associated with this
+customer device.
+
+=cut
+
+sub part_device {
+  my $self = shift;
+  qsearchs( 'part_device', { 'devicepart' => $self->devicepart } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/device_Common.pm b/FS/FS/device_Common.pm
new file mode 100644
index 0000000..ac00b76
--- /dev/null
+++ b/FS/FS/device_Common.pm
@@ -0,0 +1,78 @@
+package FS::device_Common;
+
+use strict;
+use NEXT;
+use FS::Record qw( qsearch dbh ); # qsearchs );
+
+=head1 NAME
+
+FS::device_Common - Base class for svc_X classes which have associated X_devices
+
+=head1 SYNOPSIS
+
+  package FS::svc_newservice
+  use base qw( FS::device_Common FS::svc_Common );
+
+=head1 DESCRIPTION
+
+=cut
+
+sub _device_table {
+  my $self = shift;
+  ( my $device_table = $self->table ) =~ s/^svc_//;
+  $device_table.'_device';
+}
+
+sub device_table {
+  my $self = shift;
+  my $device_table = $self->_device_table;
+  eval "use FS::$device_table;";
+  die $@ if $@;
+  $device_table;
+}
+
+sub device_objects {
+  my $self = shift;
+  qsearch($self->device_table, { 'svcnum' => $self->svcnum } );
+}
+
+sub delete {
+  my $self = shift;
+
+  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;
+
+  foreach my $device ( $self->device_objects ) {
+    my $error = $device->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  my $error = $self->NEXT::delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+
+}
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+=cut
+
+1;
diff --git a/FS/FS/svc_cable.pm b/FS/FS/svc_cable.pm
new file mode 100644
index 0000000..f588f43
--- /dev/null
+++ b/FS/FS/svc_cable.pm
@@ -0,0 +1,114 @@
+package FS::svc_cable;
+use base qw( FS::device_Common FS::svc_Common );
+
+use strict;
+use base qw( FS::Record );
+use FS::Record; # qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::svc_cable - Object methods for svc_cable records
+
+=head1 SYNOPSIS
+
+  use FS::svc_cable;
+
+  $record = new FS::svc_cable \%hash;
+  $record = new FS::svc_cable { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::svc_cable object represents a cable subscriber.  FS::svc_cable inherits
+from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item svcnum
+
+primary key
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record.  To add the record 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
+
+sub table { 'svc_cable'; }
+
+sub table_info {
+  {
+    'name' => 'Cable Subscriber',
+    #'name_plural' => '', #optional,
+    #'longname_plural' => '', #optional
+    'sorts' => [ 'svcnum', ], #, 'serviceid' ], # optional sort field (or arrayref of sort fields, main first)
+    'display_weight' => 54,
+    'cancel_weight'  => 70, #?  no deps, so
+    'fields' => {
+      'svcnum'     => 'Service',
+      'identifier' => 'Identifier',
+    },
+  };
+}
+
+=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 record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('svcnum')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/MANIFEST b/FS/MANIFEST
index ee18407..3a58c8e 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -696,3 +696,7 @@ FS/part_pkg_msgcat.pm
 t/part_pkg_msgcat.t
 FS/access_user_session.pm
 t/access_user_session.t
+FS/svc_cable.pm
+t/svc_cable.t
+FS/cable_device.pm
+t/cable_device.t
diff --git a/FS/t/cable_device.t b/FS/t/cable_device.t
new file mode 100644
index 0000000..016d2c5
--- /dev/null
+++ b/FS/t/cable_device.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cable_device;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_cable.t b/FS/t/svc_cable.t
new file mode 100644
index 0000000..5057659
--- /dev/null
+++ b/FS/t/svc_cable.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_cable;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/docs/part_svc-table.html b/httemplate/docs/part_svc-table.html
index 48841f5..8d3711d 100644
--- a/httemplate/docs/part_svc-table.html
+++ b/httemplate/docs/part_svc-table.html
@@ -21,6 +21,7 @@
       <UL STYLE="margin:0">
         <LI><B>svc_dsl</B>: DSL
         <LI><B>svc_broadband</B>: Wireless broadband
+        <LI><B>svc_cable</B>: Cable
         <LI><B>svc_dish</B>: DISH Network
       </UL>
     </TD>
diff --git a/httemplate/edit/cable_device.html b/httemplate/edit/cable_device.html
new file mode 100644
index 0000000..eb91ad7
--- /dev/null
+++ b/httemplate/edit/cable_device.html
@@ -0,0 +1,114 @@
+<% include( 'elements/edit.html',
+                 'name'   => 'Cable device',
+                 'table'  => 'cable_device',
+                 'labels' => { 
+                               'devicenum'  => 'Device',
+                               'devicepart' => 'Device type',
+                               'mac_addr'   => 'MAC address',
+                               'serial'     => 'Serial number',
+                             },
+                 'fields' => [ { 'field'    => 'devicepart',
+                                 'type'     => 'select-table',
+                                 'table'    => 'part_device',
+                                 'name_col' => 'devicename',
+				 'onchange' => 'devicepart_changed',
+                                 'empty_label' =>'Select device type',
+                                 #'hashref'        =>{ disabled => '' },
+                               },
+			       { field => 'mac_addr',
+			         type => 'select-mac',
+			       },
+                               { 'field' => 'svcnum',
+                                 'type'  => 'hidden',
+                               },
+                             ],
+                 'menubar' => [], #disable viewall
+                 #'viewall_dir' => 'browse',
+                 'new_callback' => sub {
+                                     my( $cgi, $object ) = @_;
+                                     $object->svcnum( $cgi->param('svcnum') );
+                                   },
+		 'html_foot' => $html_foot,
+           )
+%>
+<%init>
+
+#bad: pretty much entirely false laziness w/phone_device, except for labels and
+# the serial field
+
+my @deviceparts_with_inventory =
+  map $_->devicepart,
+    qsearch({ 'table'     => 'part_device',
+              'extra_sql' => 'WHERE inventory_classnum IS NOT NULL',
+           });
+
+my $html_foot = sub {
+    my $js = "
+<SCRIPT TYPE=\"text/javascript\">
+
+  function opt(what,value,text) {
+    var optionName = new Option(text, value, false, false);
+    var length = what.length;
+    what.options[length] = optionName;
+  }
+
+    function devicepart_changed(what){
+	
+	var macsel = document.getElementById('sel_mac_addr');
+	var mac = document.getElementById('mac_addr');
+	
+	function update_macs(macs) {
+	    for ( var i = macsel.length; i >= 0; i-- )
+	      macsel.options[i] = null;
+	    
+	    var macArray = eval('(' + macs + ')' );
+	    if(macArray.length == 0) 
+		opt(macsel,'','No MAC addresses found in inventory for this device type');
+	    else
+		opt(macsel,'','Select MAC address');
+
+	    for ( var i = 0; i < macArray.length; i++ ) {
+		opt(macsel,macArray[i],macArray[i]);
+	    }
+
+	}
+
+	var devicepart = what.options[what.selectedIndex].value;
+
+	var deviceparts_with_inventory = new Array(";
+$js .= join(',', map qq("$_"), @deviceparts_with_inventory);
+$js .= ");
+
+	var hasInventory = false;
+	for ( i = 0; i < deviceparts_with_inventory.length; i++ ) {
+	    if ( deviceparts_with_inventory[i] == devicepart ) 
+		hasInventory = true;
+	}
+	
+
+	if(hasInventory) { // do the AJAX thing, disable text field
+	    macsel.style.display = 'inline';
+	    mac.style.display = 'none';
+	    mac.value = '';
+	    get_macs( devicepart, update_macs );
+	} else { // clear & display text field only, clear/hide select
+	    mac.style.display = 'inline';
+	    macsel.style.display = 'none';
+	    macsel.selectedIndex = 0;
+	}
+
+    }
+
+    devicepart_changed(document.getElementById('devicepart'));
+</SCRIPT>";
+
+  $js;
+};
+
+# :/  needs agent-virt so you can't futz with arbitrary devices
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific?
+
+
+</%init>
diff --git a/httemplate/edit/process/cable_device.html b/httemplate/edit/process/cable_device.html
new file mode 100644
index 0000000..97b4f81
--- /dev/null
+++ b/httemplate/edit/process/cable_device.html
@@ -0,0 +1,23 @@
+<% include( 'elements/process.html',
+               'table'    => 'cable_device',
+               'redirect' => sub {
+                 my( $cgi, $cable_device ) = @_;
+                 #popurl(3).'view/svc_cable.html?'.
+                 popurl(3).'view/svc_Common.html?svcdb=svc_cable;'.
+                   'svcnum='. $cable_device->svcnum.
+                   ';devicenum=';
+               },
+           )
+%>
+<%init>
+
+if($cgi->param('sel_mac_addr') && !$cgi->param('mac_addr')) {
+    $cgi->param('mac_addr',$cgi->param('sel_mac_addr'));
+}
+
+# :/  needs agent-virt so you can't futz with arbitrary devices
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific?
+
+</%init>
diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html
index 997ac14..3c1cc66 100644
--- a/httemplate/view/elements/svc_Common.html
+++ b/httemplate/view/elements/svc_Common.html
@@ -119,6 +119,11 @@ function areyousure(href) {
 
 <BR>
 
+<& svc_devices.html,
+     'svc_x' => $svc_x,
+     'table' => $svc_x->device_table,
+&>
+
 % if ( defined($opt{'html_foot'}) ) {
 
   <% ref($opt{'html_foot'})
diff --git a/httemplate/view/elements/svc_devices.html b/httemplate/view/elements/svc_devices.html
index 38c6d09..745eabd 100644
--- a/httemplate/view/elements/svc_devices.html
+++ b/httemplate/view/elements/svc_devices.html
@@ -30,7 +30,7 @@
 
      <& /elements/table-grid.html &>
        <TR>
-%        if ( $table eq 'phone_device' ) {
+%        if ( $table eq 'phone_device' || $table eq 'cable_device' ) {
            <TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>
 %        }
          <TH CLASS="grid" BGCOLOR="#cccccc">MAC Addr</TH>
@@ -58,7 +58,8 @@
 %          if $device->can('export_links');
 
         <TR>
-%         if ( $table eq 'phone_device' ) { #$devices->can('part_device')
+%              #$devices->can('part_device')
+%         if ( $table eq 'phone_device' || $svc_x->isa('FS::device_Common') ) {
             <% $td %><% $device->part_device->devicename |h %></TD>
 %         }
           <% $td %><% $device->mac_addr %></TD>
@@ -84,7 +85,7 @@ my $table = $opt{'table'}; #part_device, dsl_device
 my $svc_x = $opt{'svc_x'};
 
 my $num_part_device = 0;
-if ( $table eq 'phone_device' ) {
+if ( $table eq 'phone_device' || $table eq 'cable_device' ) {
   my $sth = dbh->prepare("SELECT COUNT(*) FROM part_device")
                             #WHERE disabled = '' OR disabled IS NULL;");
     or die dbh->errstr;
@@ -92,6 +93,7 @@ if ( $table eq 'phone_device' ) {
   $num_part_device = $sth->fetchrow_arrayref->[0];
 }
 
-my @devices = $svc_x->$table();
+my @devices = $svc_x->isa('FS::device_Common') ? $svc_x->device_objects()
+                                               : $svc_x->$table();
 
 </%init>
diff --git a/httemplate/view/svc_phone.cgi b/httemplate/view/svc_phone.cgi
index ed95c4c..408364a 100644
--- a/httemplate/view/svc_phone.cgi
+++ b/httemplate/view/svc_phone.cgi
@@ -67,6 +67,7 @@ my $html_foot = sub {
   ###
   # Devices
   ###
+  #remove this when svc_phone isa device_Common, as elements/svc_Common will display it
   my $devices = include('/view/elements/svc_devices.html',
                           'svc_x' => $svc_phone,
                           'table' => 'phone_device',

commit 7a33a40d9f17d73e7f14410070675da02e25ad5e
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Mon May 13 23:04:46 2013 -0700

    whitespace

diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html
index 5689b12..044426b 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -207,10 +207,10 @@ foreach my $svcdb ( FS::part_svc->svc_tables() ) {
       ];
   }
 
-    $report_svc{"Advanced $lcsname reports"} = 
-        [ $fsurl."search/report_$svcdb.html", '' ]
-      if $svcdb =~ /^svc_(acct|broadband|hardware|phone)$/
-      && $curuser->access_right("Services: $name: Advanced search");
+  $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' ) {
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/AccessRight.pm                               |    1 +
 FS/FS/Schema.pm                                    |   24 ++++++
 FS/FS/access_right.pm                              |    1 +
 ...st_bill_pkg_display_void.pm => cable_device.pm} |   82 +++++++++++---------
 FS/FS/device_Common.pm                             |   78 +++++++++++++++++++
 FS/FS/{agent_pkg_class.pm => svc_cable.pm}         |   57 +++++++-------
 FS/MANIFEST                                        |    4 +
 FS/t/{AccessRight.t => cable_device.t}             |    2 +-
 FS/t/{ConfItem.t => svc_cable.t}                   |    2 +-
 httemplate/docs/part_svc-table.html                |    1 +
 .../edit/{phone_device.html => cable_device.html}  |    8 ++-
 .../{phone_device.html => cable_device.html}       |    9 +-
 httemplate/elements/menu.html                      |    8 +-
 httemplate/view/elements/svc_Common.html           |    5 +
 httemplate/view/elements/svc_devices.html          |   10 ++-
 httemplate/view/svc_phone.cgi                      |    1 +
 16 files changed, 210 insertions(+), 83 deletions(-)
 copy FS/FS/{cust_bill_pkg_display_void.pm => cable_device.pm} (50%)
 create mode 100644 FS/FS/device_Common.pm
 copy FS/FS/{agent_pkg_class.pm => svc_cable.pm} (57%)
 copy FS/t/{AccessRight.t => cable_device.t} (82%)
 copy FS/t/{ConfItem.t => svc_cable.t} (84%)
 copy httemplate/edit/{phone_device.html => cable_device.html} (93%)
 copy httemplate/edit/process/{phone_device.html => cable_device.html} (64%)




More information about the freeside-commits mailing list