Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Sun, 17 Aug 2014 22:38:22 +0000 (15:38 -0700)
committerIvan Kohler <ivan@freeside.biz>
Sun, 17 Aug 2014 22:38:22 +0000 (15:38 -0700)
13 files changed:
FS/FS/cust_pkg/Search.pm
FS/FS/part_export/broadband_snmp.pm
FS/FS/pay_batch/eft_canada.pm
httemplate/browse/part_pkg.cgi
httemplate/edit/elements/part_export/broadband_snmp.html
httemplate/edit/process/part_export.cgi
httemplate/elements/select-mib-popup.html
httemplate/misc/xmlhttp-pay_batch-note.html [new file with mode: 0644]
httemplate/search/elements/cust_pay_batch_top.html
httemplate/view/cust_main/packages/contact.html
httemplate/view/cust_main/packages/hidden.html
httemplate/view/cust_main/packages/section.html
httemplate/view/cust_pkg-popup.html [new file with mode: 0644]

index 543ef1a..1a9132d 100644 (file)
@@ -17,13 +17,15 @@ Valid parameters are
 
 =item agentnum
 
-=item magic
+=item status
 
-on hold, active, inactive (or one-time charge), suspended, cancel (or cancelled)
+on hold, active, inactive (or one-time charge), suspended, canceled (or cancelled)
 
-=item status
+=item magic
 
-on hold, active, inactive (or one-time charge), suspended, cancel (or cancelled)
+Equivalent to "status", except that "canceled"/"cancelled" will exclude 
+packages that were changed into a new package with the same pkgpart (i.e.
+location or quantity changes).
 
 =item custom
 
@@ -208,6 +210,19 @@ sub search {
     push @where, FS::cust_pkg->cancelled_sql();
 
   }
+  
+  ### special case: "magic" is used in detail links from browse/part_pkg,
+  # where "cancelled" has the restriction "and not replaced with a package
+  # of the same pkgpart".  Be consistent with that.
+  ###
+
+  if ( $params->{'magic'} =~ /^cancell?ed$/ ) {
+    my $new_pkgpart = "SELECT pkgpart FROM cust_pkg AS cust_pkg_next ".
+                      "WHERE cust_pkg_next.change_pkgnum = cust_pkg.pkgnum";
+    # ...may not exist, if this was just canceled and not changed; in that
+    # case give it a "new pkgpart" that never equals the old pkgpart
+    push @where, "COALESCE(($new_pkgpart), 0) != cust_pkg.pkgpart";
+  }
 
   ###
   # parse package class
index 9afca08..0ba2756 100644 (file)
@@ -34,9 +34,10 @@ tie my %options, 'Tie::IxHash',
    },
   'community' => { label=>'Community', default=>'public' },
 
-  'action' => { multiple=>1 },
-  'oid'    => { multiple=>1 },
-  'value'  => { multiple=>1 },
+  'action'  => { multiple=>1 },
+  'oid'     => { multiple=>1 },
+  'value'   => { multiple=>1 },
+  'datatype'=> { multiple=>1 },
 
   'ip_addr_change_to_new' => { 
     label=>'Send IP address changes to new address',
index 64fd2f9..310c400 100644 (file)
@@ -66,23 +66,9 @@ my %holiday = (
       @config = $conf->config('batchconfig-eft_canada');
     }
     # SFTP login, password, trans code, delay time
-    my $process_delay;
-    ($trans_code, $process_delay) = @config[2,3];
-    $process_delay ||= 1; # days
-
-    my $pt = time + ($process_delay * 86400);
-    my @lt = localtime($pt);
-    while (    $lt[6] == 0 #Sunday
-            || $lt[6] == 6 #Saturday
-            || $holiday_yearly{ $lt[4]+1 }{ $lt[3] }
-            || $holiday{ $lt[5]+1900 }{ $lt[4]+1 }{ $lt[3] }
-          )
-    {
-      $pt += 86400;
-      @lt = localtime($pt);
-    }
+    ($trans_code) = $config[2];
 
-    $process_date = time2str('%D', $pt);
+    $process_date = time2str('%D', process_date($conf, $agentnum));
   },
 
   delimiter => '', # avoid blank lines for header/footer
@@ -124,4 +110,61 @@ my %holiday = (
 
 );
 
+sub download_note { # is a class method
+  my $class = shift;
+  my $pay_batch = shift;
+  my $conf = FS::Conf->new;
+  my $agentnum = $pay_batch->agentnum;
+  my $tomorrow = (localtime(time))[2] >= 10;
+  my $process_date = process_date($conf, $agentnum);
+  my $upload_date = $process_date - 86400;
+  my $date_format = $conf->config('date_format') || '%D';
+
+  my $note = '';
+  if ( $process_date - time < 86400*2 ) {
+    $note = 'Upload this file before 11:00 AM '. 
+            ($tomorrow ? 'tomorrow' : 'today') .
+            ' (' . time2str($date_format, $upload_date) . '). ';
+  } else {
+    $note = 'Upload this file before 11:00 AM on '.
+      time2str($date_format, $upload_date) . '. ';
+  }
+  $note .= 'Payments will be processed on '.
+    time2str($date_format, $process_date) . '.';
+
+  $note;
+}
+
+sub process_date {
+  my ($conf, $agentnum) = @_;
+  my @config;
+  if ( $conf->exists('batch-spoolagent') ) {
+    @config = $conf->config('batchconfig-eft_canada', $agentnum);
+  } else {
+    @config = $conf->config('batchconfig-eft_canada');
+  }
+
+  my $process_delay = $config[3] || 1;
+
+  if ( (localtime(time))[2] >= 10 and $process_delay == 1 ) {
+    # If downloading the batch after 10:00 local time, it likely won't make
+    # the cutoff for next-day turnaround, and EFT will reject it.
+    $process_delay++;
+  }
+
+  my $pt = time + ($process_delay * 86400);
+  my @lt = localtime($pt);
+  while (    $lt[6] == 0 #Sunday
+          || $lt[6] == 6 #Saturday
+          || $holiday_yearly{ $lt[4]+1 }{ $lt[3] }
+          || $holiday{ $lt[5]+1900 }{ $lt[4]+1 }{ $lt[3] }
+        )
+  {
+    $pt += 86400;
+    @lt = localtime($pt);
+  }
+
+  $pt;
+}
+
 1;
index 63822c7..1eb55c8 100755 (executable)
@@ -108,6 +108,14 @@ my $count_cust_pkg = "
     WHERE cust_pkg.pkgpart = part_pkg.pkgpart
       AND $agentnums_sql
 ";
+my $count_cust_pkg_cancel = "
+  SELECT COUNT(*) FROM cust_pkg LEFT JOIN cust_main USING ( custnum )
+    LEFT JOIN cust_pkg AS cust_pkg_next
+      ON (cust_pkg.pkgnum = cust_pkg_next.change_pkgnum)
+    WHERE cust_pkg.pkgpart = part_pkg.pkgpart
+      AND $agentnums_sql
+      AND cust_pkg.cancel IS NOT NULL AND cust_pkg.cancel != 0
+";
 
 $select = "
 
@@ -137,11 +145,16 @@ $select = "
       AND ( setup IS NULL OR setup = 0 )
   ) AS num_on_hold,
 
-  ( $count_cust_pkg
-      AND cancel IS NOT NULL AND cancel != 0
+  ( $count_cust_pkg_cancel
+      AND (cust_pkg_next.pkgnum IS NULL
+           OR cust_pkg_next.pkgpart != cust_pkg.pkgpart)
   ) AS num_cancelled
 
 ";
+# About the num_cancelled expression: packages that were changed, but 
+# kept the same pkgpart, are considered "moved", not "canceled" (because
+# this is the part_pkg UI).  We could show the count of those but it's 
+# probably not interesting.
 
 my $html_init = qq!
     One or more service definitions are grouped together into a package 
index 4c0367c..ebb765d 100644 (file)
@@ -29,7 +29,7 @@
 function open_select_mib(obj) {
   nd(1); // if there's already one open, close it
   var rownum = obj.rownum;
-  var curr_oid = obj.value || '';
+  var curr_oid = obj.form.elements['oid' + rownum].value || '';
   var url = '<%$fsurl%>/elements/select-mib-popup.html?' +
             'callback=receive_mib;' +
             'arg=' + rownum +
@@ -66,10 +66,11 @@ function receive_mib(obj, rownum) {
     </SELECT>
   </TD>
   <TD>
-    <INPUT NAME="oid" ID="oid" SIZE="60" onclick="open_select_mib(this)">
+    <INPUT NAME="oid" ID="oid" SIZE="54">
+    <INPUT TYPE="button" VALUE="..." ID="openselector" onclick="open_select_mib(this)">
   </TD>
   <TD>
-    <INPUT TYPE="text" NAME="datatype" ID="datatype" READONLY=1>
+    <INPUT TYPE="text" NAME="datatype" ID="datatype">
   </TD>
   <TD>
     <INPUT NAME="value" ID="value">
index e0c4706..7fe3d03 100644 (file)
@@ -41,7 +41,7 @@ foreach my $option (split(',', $cgi->param('multi_options'))) {
 foreach my $option (split(',', $cgi->param('multi_options'))) {
   my $value = '';
   foreach my $row (sort keys %{$optionrows{_ALL_}}) {
-    $value .= ($optionrows{$option}{$row} || '') . "\n";
+    $value .= ($optionrows{$option}{$row} // '') . "\n";
   }
   chomp($value);
   $options{$option} = $value;
index bd485ef..f95ce2b 100644 (file)
@@ -7,7 +7,7 @@
 </TR>
 <TR>
   <TD ALIGN="right">Object:</TD>
-  <TD><INPUT TYPE="text" NAME="path" ID="input_path" WIDTH="100%"></TD>
+  <TD><INPUT TYPE="text" NAME="path" ID="input_path" SIZE=50 WIDTH="100%"></TD>
 </TR>
 <TR>
   <TD COLSPAN=2>
diff --git a/httemplate/misc/xmlhttp-pay_batch-note.html b/httemplate/misc/xmlhttp-pay_batch-note.html
new file mode 100644 (file)
index 0000000..ef59016
--- /dev/null
@@ -0,0 +1,18 @@
+<% $note %>\
+<%init>
+
+my ($batchnum, $format) = $cgi->param('arg');
+
+my $note = '';
+if ( $batchnum =~ /^(\d+)$/ ) {
+  my $pay_batch = FS::pay_batch->by_key($batchnum);
+  if ( $pay_batch and $format =~ /^(\w+)$/ ) {
+    my $class = "FS::pay_batch::$format";
+    if ( $class->can('download_note') ) {
+      # now we can actually do something
+      $note = $class->download_note($pay_batch);
+    }
+  }
+}
+
+</%init>
index bf30477..a773dd0 100644 (file)
@@ -1,24 +1,43 @@
+<& /elements/xmlhttp.html,
+  'url'   => $p.'misc/xmlhttp-pay_batch-note.html',
+  'subs'  => [ 'get_note' ]
+&>
+<script type="text/javascript">
+function format_changed() {
+  var form = document.forms['download'];
+  get_note( <% $batchnum %>, form.elements['format'].value,
+    //callback
+    function(text) {
+      document.getElementById('download_note').textContent = text;
+    }
+  );
+}
+<&| /elements/onload.js &>format_changed()</&>
+</script>
 % # Download batch
 % if ( $status eq 'O'
 %   or ( $status eq 'I' and $curuser->access_right('Reprocess batches') )
 %   or ( $status eq 'R' and $curuser->access_right('Redownload resolved batches') )
 %   ) {
-<TABLE>
-<TR><FORM ACTION="<%$p%>misc/download-batch.cgi" METHOD="POST">
-<INPUT TYPE="hidden" NAME="batchnum" VALUE="<%$batchnum%>">
+<FORM ACTION="<%$p%>misc/download-batch.cgi" NAME="download" METHOD="POST">
+    <INPUT TYPE="hidden" NAME="batchnum" VALUE="<%$batchnum%>">
 %   if ( $fixed ) {
-<INPUT TYPE="hidden" NAME="format" VALUE="<%$fixed%>">
+    <INPUT TYPE="hidden" NAME="format" VALUE="<%$fixed%>">
 %   }
 %   else {
-Download batch in format <SELECT NAME="format">
+    Download batch in format <SELECT NAME="format" onchange="format_changed()">
 %     foreach ( keys %download_formats ) {
-<OPTION VALUE="<%$_%>"><% $download_formats{$_} %></OPTION>
+      <OPTION VALUE="<%$_%>"><% $download_formats{$_} %></OPTION>
 %     }
-</SELECT> 
-<& .select_gateway &>
+    </SELECT> 
+    <& .select_gateway &>
 %   }
-<INPUT TYPE="submit" VALUE="Download"></FORM><BR><BR></TR>
+    <BR>
+    <DIV STYLE="color:#ff0000" ID="download_note"></DIV>
+    <INPUT TYPE="submit" VALUE="Download">
 % } # end of download
+</FORM>
+<BR>
 
 % # Upload batch
 % if ( $pay_batch->status eq 'I'
@@ -27,44 +46,42 @@ Download batch in format <SELECT NAME="format">
 %     and $conf->exists('batch-manual_approval')
 %   ) 
 % ) {
-<TR>
-<% include('/elements/form-file_upload.html',
+<& /elements/form-file_upload.html,
               'name'      => 'FileUpload',
               'action'    => "${p}misc/upload-batch.cgi",
               'num_files' => 1,
               'fields'    => [ 'batchnum', 'format', 'gatewaynum' ],
               'url'       => $cgi->self_url,
               'message'   => 'Batch results uploaded.',
-) %>
-Upload results<BR></TR>
-<TR>
-<% include('/elements/file-upload.html',
+&>
+  Upload results<BR>
+  <& /elements/file-upload.html,
               'field'     => 'file',
               'label'     => 'Filename',
               'no_table'  => 1,
-) %>
-<INPUT TYPE="hidden" NAME="batchnum" VALUE="<% $batchnum %>">
-<BR></TR>
+  &>
+  <INPUT TYPE="hidden" NAME="batchnum" VALUE="<% $batchnum %>">
+  <BR>
 %   if ( $fixed ) {
 %     if ( $fixed eq 'td_eft1464' ) { # special case
-<TR>Upload in format <SELECT NAME="format">
-<OPTION VALUE="td_eftack264">TD EFT Acknowledgement</OPTION>
-<OPTION VALUE="td_eftret80">TD EFT Returned Items</OPTION>
-</SELECT> </TR>
+  Upload in format <SELECT NAME="format">
+    <OPTION VALUE="td_eftack264">TD EFT Acknowledgement</OPTION>
+    <OPTION VALUE="td_eftret80">TD EFT Returned Items</OPTION>
+  </SELECT>
 %     }
 %     else {
-<INPUT TYPE="hidden" NAME="format" VALUE="<% $fixed %>">
+  <INPUT TYPE="hidden" NAME="format" VALUE="<% $fixed %>">
 %     }
 %   }
 %   else {
-<TR>Upload in format <SELECT NAME="format">
+  Upload in format <SELECT NAME="format">
 %     foreach ( keys(%upload_formats) ) {
-<OPTION VALUE="<%$_%>"><% $upload_formats{$_} %></OPTION>
+    <OPTION VALUE="<%$_%>"><% $upload_formats{$_} %></OPTION>
 %     }
-</SELECT>
-<& .select_gateway &>
+  </SELECT>
+  <& .select_gateway &>
 %   } # if $fixed
-<TR><INPUT TYPE="submit" VALUE="Upload"></TR>
+  <INPUT TYPE="submit" VALUE="Upload">
 </FORM><BR>
 % } # end upload
 
@@ -74,12 +91,12 @@ Upload results<BR></TR>
 %   and $payby eq 'CHEK'
 %   and $conf->exists('batch-manual_approval')
 %   ) {
-<TR><INPUT TYPE="button" VALUE="Manually approve" onclick="
+<INPUT TYPE="button" VALUE="Manually approve" onclick="
 if ( confirm('Approve all remaining payments in this batch?') ) 
   window.location.href='<%$p%>misc/process/pay_batch-approve.cgi?batchnum=<%$batchnum%>';
-"></TR>
+">
+<BR>
 % } # end manual approval
-</TABLE>
 
 % # summary info
 Batch is <% $statustext{$status} %><BR>
@@ -119,19 +136,19 @@ my $batchnum = $pay_batch->batchnum;
 my $fixed = $conf->config("batch-fixed_format-$payby");
 
 tie my %download_formats, 'Tie::IxHash', (
-'' => 'Default batch mode',
-'NACHA' => '94 byte NACHA',
-'csv-td_canada_trust-merchant_pc_batch' => 
-              'CSV file for TD Canada Trust Merchant PC Batch',
-'csv-chase_canada-E-xactBatch' =>
-              'CSV file for Chase Canada E-xactBatch',
-'PAP' => '80 byte file for TD Canada Trust PAP Batch',
-'BoM' => 'Bank of Montreal ECA batch',
-'ach-spiritone' => 'Spiritone ACH batch',
-'paymentech' => 'XML file for Chase Paymentech',
-'RBC' => 'Royal Bank of Canada PDS batch',
-'td_eft1464' => '1464 byte file for TD Commercial Banking EFT',
-'eft_canada' => 'EFT Canada CSV batch',
+  '' => 'Default batch mode',
+  'NACHA' => '94 byte NACHA',
+  'csv-td_canada_trust-merchant_pc_batch' => 
+                'CSV file for TD Canada Trust Merchant PC Batch',
+  'csv-chase_canada-E-xactBatch' =>
+                'CSV file for Chase Canada E-xactBatch',
+  'PAP' => '80 byte file for TD Canada Trust PAP Batch',
+  'BoM' => 'Bank of Montreal ECA batch',
+  'ach-spiritone' => 'Spiritone ACH batch',
+  'paymentech' => 'XML file for Chase Paymentech',
+  'RBC' => 'Royal Bank of Canada PDS batch',
+  'td_eft1464' => '1464 byte file for TD Commercial Banking EFT',
+  'eft_canada' => 'EFT Canada CSV batch',
 # insert new batch formats here
 );
 
@@ -150,4 +167,5 @@ my $count_query = "SELECT COUNT(*) FROM cust_pay_batch WHERE batchnum=$batchnum"
 my $count = FS::Record->scalar_sql($count_query);
 my $sum_query = "SELECT SUM(amount) FROM cust_pay_batch WHERE batchnum=$batchnum";
 my $total = sprintf("%.2f", FS::Record->scalar_sql($sum_query));
+
 </%init>
index 151da01..88f8afb 100644 (file)
           (&nbsp;<%pkg_detach_link($cust_pkg)%>&nbsp;)
         </FONT>
 %    }
+    <BR>
 % } elsif ( $show_contact_link && ! $opt{no_links} ) {
     <FONT SIZE=-1>
       (&nbsp;<%pkg_add_contact_link($cust_pkg)%>&nbsp;)
     </FONT>
+    <BR>
 % }
 <%init>
 
index e3bd0fa..35eda8c 100644 (file)
       <B><% time2str('%b %o, %Y', $cust_pkg->get('cancel')) %></B>
     </TD><TD>
 %     if ( $pkgpart_change ) {
-      from <B><% $part_pkg->pkg |h %></B></A> - <% $part_pkg->custom_comment |h %>
+      from <% $popup_link |n %><B><% $part_pkg->pkg |h %></B> - <% $part_pkg->custom_comment |h %></A>
 %     }
 %     if ( $pkgpart_change and $location_change ) {
       <BR>
 %     }
 %     if ( $location_change ) {
-      from <I><% $cust_pkg->location_label %></I>
+      from <I><% $popup_link |n %><% $cust_pkg->location_label %></A></I>
 %     }
     </TD>
   </TR>
@@ -52,4 +52,14 @@ my $pkgpart_change = ($next->pkgpart != $cust_pkg->pkgpart);
 my $location_change = ($next->locationnum != $cust_pkg->locationnum);
 my $both_change = $pkgpart_change && $location_change;
 
+my $onclick =
+  include('/elements/popup_link_onclick.html',
+    'action'      => $fsurl.'view/cust_pkg-popup.html?' . $cust_pkg->pkgnum,
+    'actionlabel' => 'Package #'.$cust_pkg->pkgnum,
+    'width'       => '1000',
+    'height'      => '310',
+    'color'       => $cust_pkg->statuscolor,
+  );
+my $popup_link = qq(<A HREF="#" onclick="$onclick">);
+
 </%init>
index 4980fee..217e8c5 100755 (executable)
@@ -4,17 +4,22 @@
   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Package') |h %></TH>
   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Status') |h %></TH>
   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Contact/Location') |h %></TH>
+% if (!$opt{no_services}) {
   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Services') |h %></TH>
+% }
 </TR>
 
 % #$FS::cust_pkg::DEBUG = 2;
 %   foreach my $cust_pkg (@$packages) {
+%    # if requested, this can override cust_pkg-group_by_location
     <& .packagerow, $cust_pkg,
+        %conf_opt,
         ( map { $_ => $opt{$_} } qw(
             cust_main bgcolor no_links cust_location_cache
             before_pkg_callback before_svc_callback after_svc_callback
+            cust_pkg-group_by_location
+            no_services
         )),
-        %conf_opt
     &>
 %   }
 % } else { # there are no packages
     <& package.html, %iopt &>
     <& status.html,  %iopt &>
     <TD CLASS="inv" BGCOLOR="<% $iopt{bgcolor} %>" WIDTH="20%" VALIGN="top">
-      <& contact.html, %iopt &><BR>
+      <& contact.html, %iopt &>
       <& location.html, %iopt &>
     </TD>
+%   if (!$iopt{no_services}) {
     <& services.html, %iopt &>
+%   }
   </TR>
 % # insert hidden predecessors to this package, if any
 % # and a rolldown button to show them
diff --git a/httemplate/view/cust_pkg-popup.html b/httemplate/view/cust_pkg-popup.html
new file mode 100644 (file)
index 0000000..96956c7
--- /dev/null
@@ -0,0 +1,27 @@
+<& /elements/header-popup.html &>
+<TABLE STYLE="width: 100%">
+<& cust_main/packages/section.html,
+  'cust_main' => $cust_main,
+  'packages'  => [ $cust_pkg ],
+  'cust_pkg-group_by_location' => 0,
+  'no_services' => 1,
+&>
+</TABLE>
+</BODY>
+</HTML>
+<%init>
+my $curuser = $FS::CurrentUser::CurrentUser;
+my ($pkgnum) = $cgi->keywords;
+$pkgnum =~ /^\d+$/ or die "bad pkgnum $pkgnum";
+
+my $cust_pkg = qsearchs({
+  'table'     => 'cust_pkg',
+  'addl_from' => 'JOIN cust_main USING (custnum)',
+  'hashref'   => { 'pkgnum' => $pkgnum },
+  'extra_sql' => ' AND '.$curuser->agentnums_sql,
+});
+die "Package not found" unless $cust_pkg;
+my $cust_main = $cust_pkg->cust_main;
+
+my $title = mt('Package [_1]', $pkgnum);
+</%init>