Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Thu, 7 May 2015 02:10:47 +0000 (19:10 -0700)
committerIvan Kohler <ivan@freeside.biz>
Thu, 7 May 2015 02:10:47 +0000 (19:10 -0700)
23 files changed:
FS/FS/cdr/earthlink.pm
FS/FS/part_svc.pm
FS/FS/svc_Common.pm
FS/FS/svc_acct.pm
FS/FS/svc_broadband.pm
FS/FS/svc_dish.pm
FS/FS/svc_domain.pm
FS/FS/svc_hardware.pm
httemplate/edit/elements/edit.html
httemplate/edit/elements/part_svc_column.html
httemplate/edit/elements/svc_Common.html
httemplate/edit/svc_acct.cgi
httemplate/edit/svc_acct/communigate.html
httemplate/edit/svc_broadband.cgi
httemplate/elements/tr-input-date-field.html
httemplate/elements/tr-select-hardware_type.html
httemplate/elements/tr-select-router_block_ip.html
httemplate/pref/pref-process.html
httemplate/pref/pref.html
httemplate/search/cust_msg.html
httemplate/search/elements/search.html
httemplate/view/cust_main/notes.html
httemplate/view/cust_main/notes/email.html [new file with mode: 0644]

index da0d545..60cba65 100644 (file)
@@ -17,7 +17,7 @@ use Date::Parse;
        'accountcode',                  #Account number
               skip(2),                 #SERVICE LOC / BILL NUMBER 
        sub { my($cdr, $date) = @_;  
-       
+       $date;  
        },                              #date 
        sub { my($cdr, $time) = @_;
 
index 1da30cb..ca26074 100644 (file)
@@ -142,56 +142,53 @@ sub insert {
   # add part_svc_column records
 
   my $svcdb = $self->svcdb;
-#  my @rows = map { /^${svcdb}__(.*)$/; $1 }
-#    grep ! /_flag$/,
-#      grep /^${svcdb}__/,
-#        fields('part_svc');
-  foreach my $field (
-    grep { $_ ne 'svcnum'
-           && ( defined( $self->getfield($svcdb.'__'.$_.'_flag') )
-                || defined($self->getfield($svcdb.'__'.$_.'_required'))
-                || $self->getfield($svcdb.'__'.$_.'_label') !~ /^\s*$/ )
-         } (fields($svcdb), @fields)
-  ) {
-    my $part_svc_column = $self->part_svc_column($field);
-    my $previous = qsearchs('part_svc_column', {
-      'svcpart'    => $self->svcpart,
-      'columnname' => $field,
-    } );
+  foreach my $field (fields($svcdb), @fields) {
+    next if $field eq 'svcnum';
+    my $prefix = $svcdb.'__';
+    if ( defined( $self->getfield($prefix.$_.'_flag'))
+      or defined($self->getfield($prefix.$_.'_required'))
+      or length($self->getfield($prefix.$_.'_label'))
+    ) {
+      my $part_svc_column = $self->part_svc_column($field);
+      my $previous = qsearchs('part_svc_column', {
+        'svcpart'    => $self->svcpart,
+        'columnname' => $field,
+      } );
 
-    my $flag  = $self->getfield($svcdb.'__'.$field.'_flag');
-    my $label = $self->getfield($svcdb.'__'.$field.'_label');
-    my $required = $self->getfield($svcdb.'__'.$field.'_required') ? 'Y' : '';
-    if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) {
-
-      if ( uc($flag) =~ /^([A-Z])$/ ) {
-        my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse}
-                     || sub { shift };
-        $part_svc_column->setfield('columnflag', $1);
-        $part_svc_column->setfield('columnvalue',
-          &$parser($self->getfield($svcdb.'__'.$field))
-        );
-      }
+      my $flag  = $self->getfield($prefix.$field.'_flag');
+      my $label = $self->getfield($prefix.$field.'_label');
+      my $required = $self->getfield($prefix.$field.'_required') ? 'Y' : '';
+      if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) {
 
-      $part_svc_column->setfield('columnlabel', $label)
-        if $label !~ /^\s*$/;
+        if ( uc($flag) =~ /^([A-Z])$/ ) {
+          my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse}
+                       || sub { shift };
+          $part_svc_column->setfield('columnflag', $1);
+          $part_svc_column->setfield('columnvalue',
+            &$parser($self->getfield($prefix.$field))
+          );
+        }
+
+        $part_svc_column->setfield('columnlabel', $label)
+          if $label !~ /^\s*$/;
 
-      $part_svc_column->setfield('required', $required);
+        $part_svc_column->setfield('required', $required);
+
+        if ( $previous ) {
+          $error = $part_svc_column->replace($previous);
+        } else {
+          $error = $part_svc_column->insert;
+        }
 
-      if ( $previous ) {
-        $error = $part_svc_column->replace($previous);
       } else {
-        $error = $part_svc_column->insert;
+        $error = $previous ? $previous->delete : '';
+      }
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
       }
 
-    } else {
-      $error = $previous ? $previous->delete : '';
-    }
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return $error;
     }
-
   }
 
   # add export_svc records
@@ -284,54 +281,54 @@ sub replace {
    # maintain part_svc_column records
 
     my $svcdb = $new->svcdb;
-    foreach my $field (
-      grep { $_ ne 'svcnum'
-             && ( defined( $new->getfield($svcdb.'__'.$_.'_flag') )
-                  || defined($new->getfield($svcdb.'__'.$_.'_required'))
-                  || $new->getfield($svcdb.'__'.$_.'_label') !~ /^\s*$/ )
-           } (fields($svcdb),@fields)
-    ) {
-
-      my $part_svc_column = $new->part_svc_column($field);
-      my $previous = qsearchs('part_svc_column', {
-        'svcpart'    => $new->svcpart,
-        'columnname' => $field,
-      } );
-
-      my $flag  = $new->getfield($svcdb.'__'.$field.'_flag');
-      my $label = $new->getfield($svcdb.'__'.$field.'_label');
-      my $required = $new->getfield($svcdb.'__'.$field.'_required') ? 'Y' : '';
+    foreach my $field (fields($svcdb),@fields) {
+      next if $field eq 'svcnum';
+      my $prefix = $svcdb.'__';
+      if ( defined( $new->getfield($prefix.$_.'_flag'))
+        or defined($new->getfield($prefix.$_.'_required'))
+        or length($new->getfield($prefix.$_.'_label'))
+      ) {
+        my $part_svc_column = $new->part_svc_column($field);
+        my $previous = qsearchs('part_svc_column', {
+          'svcpart'    => $new->svcpart,
+          'columnname' => $field,
+        } );
+
+        my $flag  = $new->getfield($svcdb.'__'.$field.'_flag');
+        my $label = $new->getfield($svcdb.'__'.$field.'_label');
+        my $required = $new->getfield($svcdb.'__'.$field.'_required') ? 'Y' : '';
  
-      if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) {
-
-        if ( uc($flag) =~ /^([A-Z])$/ ) {
-          $part_svc_column->setfield('columnflag', $1);
-          my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse}
-                     || sub { shift };
-          $part_svc_column->setfield('columnvalue',
-            &$parser($new->getfield($svcdb.'__'.$field))
-          );
-        } else {
-          $part_svc_column->setfield('columnflag',  '');
-          $part_svc_column->setfield('columnvalue', '');
-        }
+        if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) {
+
+          if ( uc($flag) =~ /^([A-Z])$/ ) {
+            $part_svc_column->setfield('columnflag', $1);
+            my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse}
+                       || sub { shift };
+            $part_svc_column->setfield('columnvalue',
+              &$parser($new->getfield($svcdb.'__'.$field))
+            );
+          } else {
+            $part_svc_column->setfield('columnflag',  '');
+            $part_svc_column->setfield('columnvalue', '');
+          }
 
-        $part_svc_column->setfield('columnlabel', $label)
-          if $label !~ /^\s*$/;
+          $part_svc_column->setfield('columnlabel', $label)
+            if $label !~ /^\s*$/;
 
-        $part_svc_column->setfield('required', $required);
+          $part_svc_column->setfield('required', $required);
 
-        if ( $previous ) {
-          $error = $part_svc_column->replace($previous);
+          if ( $previous ) {
+            $error = $part_svc_column->replace($previous);
+          } else {
+            $error = $part_svc_column->insert;
+          }
         } else {
-          $error = $part_svc_column->insert;
+          $error = $previous ? $previous->delete : '';
+        }
+        if ( $error ) {
+          $dbh->rollback if $oldAutoCommit;
+          return $error;
         }
-      } else {
-        $error = $previous ? $previous->delete : '';
-      }
-      if ( $error ) {
-        $dbh->rollback if $oldAutoCommit;
-        return $error;
       }
     }
 
@@ -605,6 +602,7 @@ sub svc_x {
 =cut
 
 my $svc_defs;
+my $svc_info;
 sub _svc_defs {
 
   return $svc_defs if $svc_defs; #cache
@@ -659,7 +657,14 @@ sub _svc_defs {
     sort { $info{$a}->{'display_weight'} <=> $info{$b}->{'display_weight'} }
     keys %info,
   ;
-  
+
+  tie my %svc_info, 'Tie::IxHash',
+    map  { $_ => $info{$_} }
+    sort { $info{$a}->{'display_weight'} <=> $info{$b}->{'display_weight'} }
+    keys %info,
+  ;
+    
+  $svc_info = \%svc_info; #access via svc_table_info  
   $svc_defs = \%svc_defs; #cache
   
 }
@@ -735,6 +740,27 @@ sub svc_table_fields {
   $def;
 }
 
+=item svc_table_info TABLE
+
+Returns table_info for TABLE from cache, or empty
+hashref if none is found.
+
+Caution:  caches table_info for ALL services when run;
+access a service's table_info directly unless you know
+you're loading them all.
+
+Caution:  does not standardize fields into hashrefs;
+use L</svc_table_fields> to access fields.
+
+=cut
+
+sub svc_table_info {
+  my $class = shift;
+  my $table = shift;
+  $class->_svc_defs; #creates cache if needed
+  return $svc_info->{$table} || {};
+}
+
 =back
 
 =head1 SUBROUTINES
index 8d3b535..9d9e50f 100644 (file)
@@ -167,28 +167,30 @@ sub check {
   my $required = {};
   my $labels = {};
   my $tinfo = $self->can('table_info') ? $self->table_info : {};
-  my $fields = $tinfo->{'fields'} || {};
-  foreach my $field (keys %$fields) {
-    if (ref($fields->{$field}) && $fields->{$field}->{'required'}) {
-      $required->{$field} = 1;
-      $labels->{$field} = $fields->{$field}->{'label'};
+  if ($tinfo->{'manual_require'}) {
+    my $fields = $tinfo->{'fields'} || {};
+    foreach my $field (keys %$fields) {
+      if (ref($fields->{$field}) && $fields->{$field}->{'required'}) {
+        $required->{$field} = 1;
+        $labels->{$field} = $fields->{$field}->{'label'};
+      }
     }
-  }
-  # add fields marked as required in database
-  foreach my $column (
-    qsearch('part_svc_column',{
-      'svcpart' => $self->svcpart,
-      'required' => 'Y'
-    })
-  ) {
-    $required->{$column->columnname} = 1;
-    $labels->{$column->columnname} = $column->columnlabel;
-  }
-  # do the actual checking
-  foreach my $field (keys %$required) {
-    unless ($self->$field) {
-      my $name = $labels->{$field} || $field;
-      return "Field $name is required\n"
+    # add fields marked as required in database
+    foreach my $column (
+      qsearch('part_svc_column',{
+        'svcpart' => $self->svcpart,
+        'required' => 'Y'
+      })
+    ) {
+      $required->{$column->columnname} = 1;
+      $labels->{$column->columnname} = $column->columnlabel;
+    }
+    # do the actual checking
+    foreach my $field (keys %$required) {
+      unless (length($self->get($field)) > 0) {
+        my $name = $labels->{$field} || $field;
+        return "Field $name is required\n"
+      }
     }
   }
 
index 790ac34..0181b1e 100644 (file)
@@ -260,6 +260,7 @@ sub table_info {
     'display_weight' => 10,
     'cancel_weight'  => 50, 
     'ip_field' => 'slipip',
+    'manual_require' => 1,
     'fields' => {
         'dir'       => 'Home directory',
         'uid'       => {
index e295f73..38594f0 100755 (executable)
@@ -103,6 +103,7 @@ sub table_info {
     'display_weight' => 50,
     'cancel_weight'  => 70,
     'ip_field' => 'ip_addr',
+    'manual_require' => 1,
     'fields' => {
       'svcnum'      => 'Service',
       'description' => 'Descriptive label',
index 5c9e217..2d249d1 100644 (file)
@@ -63,9 +63,10 @@ sub table_info {
     'name'           => 'Dish service',
     'display_weight' => 58,
     'cancel_weight'  => 85,
+    'manual_require' => 1,
     'fields' => {
       'svcnum'    =>  { label => 'Service' },
-      'acctnum'   =>  { label => 'DISH account#', %opts },
+      'acctnum'   =>  { label => 'DISH account#', required => 1, %opts },
       'installdate' => { label => 'Install date', %opts },
       'note'      => { label => 'Installation notes', %opts },
     }
index 78556cf..b01d673 100644 (file)
@@ -134,10 +134,7 @@ sub table_info {
     'display_weight' => 20,
     'cancel_weight'  => 60,
     'fields' => {
-      'domain' => {
-                  label => 'Domain',
-                  required => 1,
-                },
+      'domain' => 'Domain',
       'parent_svcnum' => { 
                          label => 'Parent domain / Communigate administrator domain',
                          type  => 'select',
index 16a5ea9..dbb8b68 100644 (file)
@@ -75,6 +75,7 @@ sub table_info {
     'name_plural'    => 'Hardware',
     'display_weight' => 59,
     'cancel_weight'  => 86,
+    'manual_require' => 1,
     'fields' => {
       'svcnum'    => { label => 'Service' },
       'typenum'   => { label => 'Device type',
@@ -83,6 +84,7 @@ sub table_info {
                        disable_fixed     => 1,
                        disable_default   => 1,
                        disable_inventory => 1,
+                       required => 1,
                      },
       'serial'    => { label => 'Serial number', %opts },
       'hw_addr'   => { label => 'Hardware address', %opts },
index 76df820..7b02994 100644 (file)
@@ -418,6 +418,7 @@ Example:
 %                      'value' => $opt{curr_value},
 %                      'label' => $label,
 %                      'noinit' => $f->{noinit},
+%           'required' => $f->{'required'},
 %              }
 %      );
 %     }
index 23a6deb..bc679e5 100644 (file)
@@ -76,7 +76,7 @@ my %communigate_fields = (
     <TH BGCOLOR="#cccccc">Field</TH>
     <TH BGCOLOR="#cccccc">Label</TH>
     <TH BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>
-    <TH BGCOLOR="#cccccc">Required?</TH>
+    <TH BGCOLOR="#cccccc"><% $manual_require ? 'Required?' : '' %></TH>
   </TR>
 % $part_svc->set('svcpart' => $opt{'clone'}) if $opt{'clone'}; # for now
 % my $i = 0;
@@ -211,7 +211,9 @@ my %communigate_fields = (
 %   }
     </TD>
     <TD>
-%   if (!$def->{'type'} || !(grep {$_ eq $def->{'type'}} ('checkbox','disabled'))) {
+%   if ($manual_require && 
+%       (!$def->{'type'} || !(grep {$_ eq $def->{'type'}} ('checkbox','disabled')))
+%   ) {
       <INPUT ID="<% $name.'_required' %>" TYPE="checkbox" NAME="<% $svcdb %>__<% $field %>_required" VALUE="Y" 
         <% ($part_svc_column->required || $def->{'required'}) ? 'CHECKED' : '' %> 
         <% $def->{'required'} ? 'DISABLED' : '' %>
@@ -309,4 +311,5 @@ if ( $svcdb eq 'svc_acct'
 }
 
 my @defs = map { FS::part_svc->svc_table_fields($svcdb)->{$_} } @fields;
+my $manual_require = FS::part_svc->svc_table_info($svcdb)->{'manual_require'};
 </%init>
index 97b630f..a4e345e 100644 (file)
                    my $columndef = $part_svc->part_svc_column($f->{'field'});
                    my $flag = $columndef->columnflag;
 
+                   $f->{'required'} = 1
+                     if $columndef->required;
+
                    if ( $flag eq 'F' ) { #fixed
                      $f->{'value'} = $columndef->columnvalue;
                      if (length($columndef->columnvalue)) {
index 2c694a8..31678a9 100755 (executable)
@@ -30,8 +30,9 @@
   <TD BGCOLOR="#eeeeee"><% $part_svc->svc %></TD>
 </TR>
 
-<TR>
-  <TD ALIGN="right"><% mt('Username') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Username'),
+     'required' => $part_svc->part_svc_column('username')->required ) %>
 % if ( $svcnum && $conf->exists('svc_acct-no_edit_username') ) {
     <TD BGCOLOR="#eeeeee"><% $svc_acct->username() %></TD>
     <INPUT TYPE="hidden" NAME="username" VALUE="<% $username %>">
 </TR>
 
 %if ( $part_svc->part_svc_column('_password')->columnflag ne 'F' ) {
-<TR>
 % #XXX eventually should require "Edit Password" ACL
-  <TD ALIGN="right"><% mt('Password') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Password'),
+     'required' => $part_svc->part_svc_column('_password')->required ) %>
   <TD>
     <INPUT TYPE="text" ID="clear_password" NAME="clear_password" VALUE="<% $password %>" SIZE=<% $pmax2 %> MAXLENGTH=<% $pmax %>>
     <& /elements/random_pass.html, 'clear_password' &>
@@ -60,8 +62,9 @@
 %if ( $conf->exists('security_phrase') 
 %  && $part_svc->part_svc_column('sec_phrase')->columnflag ne 'F' ) {
 
-  <TR>
-    <TD ALIGN="right"><% mt('Security phrase') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Security phrase'),
+     'required' => $part_svc->part_svc_column('sec_phrase')->required ) %>
     <TD>
       <INPUT TYPE="text" NAME="sec_phrase" VALUE="<% $sec_phrase %>" SIZE=32>
       (<% mt('for forgotten passwords') |h %>)
 %                                                )
 %                );
 
-  <TR>
-    <TD ALIGN="right"><% mt('Domain') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Domain'),
+     'required' => $part_svc->part_svc_column('domsvc')->required ) %>
     <TD>
       <SELECT NAME="domsvc" SIZE=1>
 % foreach my $svcnum (
   <INPUT TYPE="hidden" NAME="popnum" VALUE="<% $popnum %>">
 % } else { 
 
-  <TR>
-    <TD ALIGN="right"><% mt('Access number') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Access number'),
+     'required' => $part_svc->part_svc_column('popnum')->required ) %>
     <TD><% FS::svc_acct_pop::popselector($popnum) %></TD>
   </TR>
 % } 
          'curr_value' => $svc_acct->sectornum,
          #'part_svc'   => $part_svc,
          #'cust_pkg'   => $cust_pkg,
+         'required'   => $part_svc->part_svc_column('sectornum')->required,
     &>
 %} else {
     <INPUT TYPE="hidden" NAME="sectornum" VALUE="<% $svc_acct->sectornum %>">
 %  
 % if ( length($svc_acct->$xid()) ) { 
 
+<% include('/elements/tr-td-label.html',
+     'label'    => uc($xid),
+     'required' => $part_svc->part_svc_column($xid)->required ) %>
       <TR>
         <TD ALIGN="right"><% uc($xid) %></TD>
           <TD BGCOLOR="#eeeeee"><% $svc_acct->$xid() %></TD>
     <INPUT TYPE="hidden" NAME="<% $xid %>" VALUE="<% $svc_acct->$xid() %>">
 % } else { 
   
-    <TR>
-      <TD ALIGN="right"><% uc($xid) %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => uc($xid),
+     'required' => $part_svc->part_svc_column($xid)->required ) %>
       <TD>
         <INPUT TYPE="text" NAME="<% $xid %>" SIZE=8 MAXLENGTH=6 VALUE="<% $svc_acct->$xid() %>">
       </TD>
 % } else { 
 
 
-  <TR>
-    <TD ALIGN="right"><% mt('Real Name') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Real Name'),
+     'required' => $part_svc->part_svc_column('finger')->required ) %>
     <TD>
       <INPUT TYPE="text" NAME="finger" VALUE="<% $svc_acct->finger %>">
     </TD>
 % } else {
 
 
-  <TR>
-    <TD ALIGN="right"><% mt('Home directory') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Home directory'),
+     'required' => $part_svc->part_svc_column('dir')->required ) %>
     <TD><INPUT TYPE="text" NAME="dir" VALUE="<% $svc_acct->dir %>"></TD>
   </TR>
 % } 
 % } else { 
 
 
-  <TR>
-    <TD ALIGN="right"><% mt('Shell') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('Shell'),
+     'required' => $part_svc->part_svc_column('shell')->required ) %>
     <TD>
       <SELECT NAME="shell" SIZE=1>
 %
 %   # (should we show this if slipip is fixed?)
 <& /elements/tr-select-router_block_ip.html, 
   'object' => $svc_acct,
-  'ip_field' => 'slipip'
+  'ip_field' => 'slipip',
+  'required' => $part_svc->part_svc_column('routernum')->required,
+  'ip_addr_required' => $part_svc->part_svc_column('slipip')->required,
 &>
 % } else {
 %   # don't expose these to the user--they're only useful in the other case
 %   if ( $part_svc->part_svc_column('slipip')->columnflag =~ /^[FA]$/ ) { 
     <INPUT TYPE="hidden" NAME="slipip" VALUE="<% $svc_acct->slipip %>">
 %   } else { 
-    <TR>
-      <TD ALIGN="right"><% mt('IP') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('IP'),
+     'required' => $part_svc->part_svc_column('slipip')->required ) %>
       <TD><INPUT TYPE="text" NAME="slipip" VALUE="<% $svc_acct->slipip %>"></TD>
     </TR>
 %   }
 % } 
 
 
-<TR>
-  <TD ALIGN="right"><% mt('RADIUS groups') |h %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => mt('RADIUS groups'),
+     'required' => $part_svc->part_svc_column('usergroup')->required ) %>
 % if ( $part_svc_usergroup->columnflag eq 'F' ) { 
     <TD BGCOLOR="#eeeeee"><% join('<BR>', @groupnames) %></TD>
 % } else { 
index 6370a54..370bfb0 100644 (file)
@@ -47,8 +47,9 @@
   <INPUT TYPE="hidden" NAME="quota" VALUE="<% $svc_acct->quota %>">
 % } else {
 %   my $quota_label = $communigate ? 'Mail storage limit' : 'Quota';
-    <TR>
-      <TD ALIGN="right"><% $quota_label %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => $quota_label,
+     'required' => $part_svc->part_svc_column('quota')->required ) %>
       <TD><INPUT TYPE="text" NAME="quota" VALUE="<% $svc_acct->quota %>"></TD>
     </TR>
 % }
index 1b85460..81c694a 100644 (file)
@@ -102,7 +102,16 @@ END
 my @fields = (
   qw( description speed_down speed_up ),
   { field=>'sectornum', type=>'select-tower_sector', },
-  { field=>'routernum', type=>'select-router_block_ip' },
+  { field=>'routernum', type=>'select-router_block_ip', 
+    include_opt_callback => sub { 
+      my $svc_broadband = shift;
+      my $part_svc = $svc_broadband->part_svc;
+      return () unless $part_svc; #sanity check
+      my $col = $part_svc->part_svc_column('ip_addr');
+      return () unless $col; #sanity check
+      return ('ip_addr_required' => $col->required);
+    },
+  },
   { field=>'mac_addr' , type=>'input-mac_addr' },
   qw(
       latitude longitude altitude
index ff98551..f2a570b 100644 (file)
@@ -13,6 +13,7 @@ Example:
           'usedatetime' => 1, #use DateTime->strftime to format the date
                               # instead of Date::Format->time2str
           'noinit'      => 1,          #first one on the page is enough
+          'required'    => 1,
        },
   &>
 
@@ -24,8 +25,9 @@ Example:
 <SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/calendar-setup.js"></SCRIPT>
 % }
 
-<TR>
-  <TD ALIGN="right"><% $label %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => $label,
+     'required' => $required ) %>
   <TD COLSPAN=<% $colspan %>>
     <INPUT TYPE="text" NAME="<% $name %>" ID="<% $name %>_text" VALUE="<% $value %>">
     <IMG SRC="<%$fsurl%>images/calendar.png" ID="<% $name  %>_button" STYLE="cursor: pointer" TITLE="<% mt('Select date') |h %>">
@@ -48,7 +50,7 @@ Example:
 
 <%init>
 
-my($name, $value, $label, $format, $usedatetime, $noinit, $colspan);
+my($name, $value, $label, $format, $usedatetime, $noinit, $colspan, $required);
 if ( ref($_[0]) ) {
   my $opt = shift;
   $name        = $opt->{'name'};
@@ -58,6 +60,7 @@ if ( ref($_[0]) ) {
   $usedatetime = $opt->{'usedatetime'};
   $noinit      = $opt->{'noinit'};
   $colspan     = $opt->{'colspan'} || 1;
+  $required    = $opt->{'required'};
 } else {
   ($name, $value, $label, $format, $usedatetime) = @_;
   $colspan = 1;
index c306641..b51afc0 100644 (file)
@@ -1,5 +1,6 @@
-<TR>
-  <TD ALIGN="right"><% $opt{'label'} || 'Device type: ' %></TD>
+<% include('/elements/tr-td-label.html',
+     'label'    => $opt{'label'} || 'Device type: ',
+     'required' => $opt{'required'} ) %>
   <TD><% include('select-hardware_type.html', %opt) %></TD>
 </TR>
 
index 11f7c48..ee13568 100644 (file)
@@ -30,7 +30,7 @@ function clearhint_ip_addr (what) {
     what.value = '';
 }
 </script>
-<& /elements/tr-td-label.html, label => ($opt{'label'} || 'Router') &>
+<& /elements/tr-td-label.html, label => ($opt{'label'} || 'Router'), required => $opt{'required'} &>
 <td>
   <& /elements/select-tiered.html, prefix => 'router_', tiers => [
   {
@@ -56,9 +56,9 @@ function clearhint_ip_addr (what) {
 ]
 &>
 </td></tr>
-<& /elements/tr-td-label.html, label => 'IP address' &>
+<& /elements/tr-td-label.html, label => 'IP address', required => $opt{'ip_addr_required'} &>
 <td>
-% warn Dumper \%fixed;
+% #warn Dumper \%fixed;
 % if ( exists $fixed{$ip_field} ) {
   <input type="hidden" id="input_ip_addr" name="<% $ip_field %>" 
     value="<% $opt{'ip_addr'} |h%>"><% $opt{'ip_addr'} || '' %>
index cd400ee..68f0f6e 100644 (file)
@@ -55,6 +55,7 @@ unless ( $error ) { # if ($access_user) {
                       enable_fuzzy_on_exact
                       disable_html_editor disable_enter_submit_onetimecharge
                       enable_mask_clipboard_hack dashboard_customers
+                      customer_view_emails
                       email_address
                       snom-ip snom-username snom-password
                       vonage-fromnumber vonage-username vonage-password
index 5e722b0..ffc90fd 100644 (file)
@@ -151,6 +151,15 @@ Interface
     </TD>
   </TR>
 
+  <TR>
+    <TH ALIGN="right">How many recent outbound emails to show in customer view</TH>
+    <TD ALIGN="left" COLSPAN=2>
+      <INPUT TYPE="text" NAME="customer_view_emails" VALUE="<% $curuser->option('customer_view_emails') %>"></TD>
+    </TD>
+  </TR>
+
+
+
 </TABLE>
 <BR>
 
index d5b865c..401f52e 100644 (file)
@@ -47,7 +47,7 @@
                           ],
        'html_init'     => $html_init,
        'really_disable_download' => 1,
-       @_ #why?
+       'order_by'      => '_date DESC',
 &>
 <%init>
 #hmm...
index 62a0e47..64f3a66 100644 (file)
@@ -386,10 +386,7 @@ unless ( $type =~ /^(csv|xml|\w*.xls)$/) {
 }
 
 #order by override
-my $order_by = '';
-#if ( $cgi->param('order_by') =~ /^([\w\, ]+)$/ ) {
-#  $order_by = $1;
-#}
+my $order_by = $opt{order_by} || '';
 $order_by = $cgi->param('order_by') if $cgi->param('order_by');
 
 # run the query
@@ -415,6 +412,8 @@ if ( ref($opt{query}) ) {
       }
     }
 
+    $opt{query}->{'order_by'} .= " $limit";
+
   } elsif (ref($opt{query}) eq 'ARRAY') {
     @query = @{ $opt{query} };
   } else {
@@ -434,7 +433,7 @@ if ( ref($opt{query}) ) {
                            }
                        @query
                      ],
-                     'order_by' => $opt{order_by}. " ". $limit,
+                     #'order_by' => $opt{order_by}. " ". $limit,
                    )
           ]; 
 } else {
index 1cd6e09..deba956 100755 (executable)
 % if ( $curuser->access_right('View email logs')
 %      and FS::cust_msg->count("custnum = $custnum")) {
 <BR>
-%   if (!$cgi->param('order_by')) {
-%     my $order_by = '_date';
-%     $order_by .= ' DESC' if $curuser->option('history_order') eq 'newest';
-%     $cgi->param('order_by', $order_by);
-%   }
-<& /search/cust_msg.html,
-  nohtmlheader  => 1,
-  html_init     => mt('Mail sent to this customer: '),
-&>
+<& notes/email.html, 'cust_main' => $cust_main &>
+<BR>
 % }
 <%init>
 
diff --git a/httemplate/view/cust_main/notes/email.html b/httemplate/view/cust_main/notes/email.html
new file mode 100644 (file)
index 0000000..da2c352
--- /dev/null
@@ -0,0 +1,106 @@
+% if ( scalar(@rows) ) {
+<STYLE type="text/css">
+#cust_msg td.grid a:link {text-decoration: none}
+#cust_msg td.grid a:visited {text-decoration: none}
+#cust_msg td.grid a:hover {text-decoration: underline}
+#cust_msg th {background-color: #cccccc}
+.row0 {background-color: #eeeeee}
+.row1 {background-color: #ffffff}
+</STYLE>
+<DIV id="cust_msg">
+<FONT SIZE="+1"> <% mt('Email sent to this customer') %> </FONT><BR>
+%   if ($maxrecords < $total) {
+<% mt('Showing [_1] most recent of [quant,_2,total message]', $maxrecords, $total) %>
+  <A HREF="<%$p%>search/cust_msg.html?custnum=<%$custnum%>">
+  <i>(<% mt('view all') %>)</i>
+  </A>
+%   } else {
+<% mt('[quant,_1,total message]', $total) %>
+%   }
+<BR>
+<& /elements/table-grid.html &>
+  <TR>
+    <TH CLASS="grid"><% mt('Date') %></TH>
+    <TH CLASS="grid"><% mt('Type') %></TH>
+    <TH CLASS="grid"><% mt('Destination') %></TH>
+    <TH CLASS="grid"><% mt('Subject') %></TH>
+    <TH CLASS="grid"></TH>
+  </TR>
+%   my $i = 0;
+%   foreach my $row (@rows) {
+%     my $onclick = $sub_popup_link->($row);
+%     my $link = qq!<A onclick="$onclick">!;
+  <TR CLASS="row<%$i%>">
+    <TD CLASS="grid"><% $link %>
+      <% $row->_date ? time2str('%Y-%m-%d %T', $row->_date) : '' %>
+    </A></TD>
+    <TD CLASS="grid" STYLE="color: <% $typecolor->($row) %>"><% $link %>
+      <% ucfirst($row->msgtype) || $row->msgname %>
+    </A></TD>
+    <TD CLASS="grid"><% $link %>
+      <% join('<BR>', split(/,\s*/, $row->env_to)) %>
+    </A></TD>
+    <TD CLASS="grid" STYLE="color: <% $statuscolor->($row) %>">
+      <% $row->status %>
+    </TD>
+    <TD CLASS="grid">
+      <% $row->error |h %>
+    </TD>
+  </TR>
+%     $i = 1 - $i;
+%   }
+</TABLE>
+</DIV>
+% }
+<%init>
+my %opt = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+my $cust_main = $opt{'cust_main'}
+  or die "cust_main required";
+my $custnum = $cust_main->custnum;
+
+my $where = "WHERE cust_msg.custnum = $custnum";
+my $maxrecords = $curuser->option('customer_view_emails') || 10;
+
+my $order_by = '_date DESC';
+
+my $query = {
+  'table'     => 'cust_msg',
+  'select'    => join(', ',
+                   'cust_msg.*',
+                   'msg_template.msgname',
+                 ),
+  'addl_from' => ' LEFT JOIN msg_template USING ( msgnum ) ',
+  'hashref'   => {},
+  'extra_sql' => $where,
+  'order_by'  => "ORDER BY $order_by LIMIT $maxrecords",
+};
+my $count_query = "SELECT COUNT(*) FROM cust_msg $where";
+
+my @rows = qsearch($query);
+my $total = FS::Record->scalar_sql($count_query);
+
+my $sub_popup_link = sub {
+  my $custmsgnum = $_[0]->custmsgnum;
+  include('/elements/popup_link_onclick.html',
+    'action'      => $p. 'view/cust_msg.html?' . $custmsgnum,
+    'actionlabel' => 'Message detail',
+    'width'       => 680,
+    'height'      => 550,
+  );
+};
+
+my %color = (
+  'failed'   => '#FF0000',
+  'sent'     => '#000000',
+
+  'invoice'  => '#00CC00',
+  'receipt'  => '#0000CC',
+  'admin'    => '#CC0000',
+  ''         => '#000000',
+);
+my $statuscolor = sub { $color{$_[0]->status} };
+my $typecolor = sub { $color{$_[0]->msgtype} };
+
+</%init>