RT#40806: Enter invoice details from order package page
authorJonathan Prykop <jonathan@freeside.biz>
Fri, 11 Mar 2016 06:10:13 +0000 (00:10 -0600)
committerJonathan Prykop <jonathan@freeside.biz>
Fri, 11 Mar 2016 06:10:13 +0000 (00:10 -0600)
FS/FS/cust_main/Packages.pm
FS/FS/quotation_pkg.pm
httemplate/edit/cust_pkg_detail.html
httemplate/edit/elements/detail-table.html [new file with mode: 0644]
httemplate/edit/process/quick-cust_pkg.cgi
httemplate/edit/quotation_pkg_detail.html
httemplate/misc/order_pkg.html

index 5a14e2e..1c921d6 100644 (file)
@@ -74,6 +74,14 @@ Optional subject for a ticket created and attached to this customer
 
 Optional queue name for ticket additions
 
+=item invoice_details
+
+Optional arrayref of invoice detail strings to add (creates cust_pkg_detail detailtype 'I')
+
+=item package_comments
+
+Optional arrayref of package comment strings to add (creates cust_pkg_detail detailtype 'C')
+
 =back
 
 =cut
@@ -208,6 +216,22 @@ sub order_pkg {
     }
   }
 
+  # add details/comments
+  if ($opt->{'invoice_details'}) {
+    $error = $cust_pkg->set_cust_pkg_detail('I', @{$opt->{'invoice_details'}});
+  }
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "setting invoice details: $error";
+  }
+  if ($opt->{'package_comments'}) {
+    $error = $cust_pkg->set_cust_pkg_detail('C', @{$opt->{'package_comments'}});
+  }
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "setting package comments: $error";
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   ''; #no error
 
index 1e5a0da..b9b3799 100644 (file)
@@ -106,7 +106,11 @@ sub detail_table          { 'quotation_pkg_detail'; }
 =item insert
 
 Adds this record to the database.  If there is an error, returns the error,
-otherwise returns false.
+otherwise returns false.  Accepts the following options:
+
+quotation_details - optional arrayref of detail strings to add (creates quotation_pkg_detail records)
+
+copy_on_order - value for this field when creating quotation_pkg_detail records (same for all details)
 
 =cut
 
@@ -128,10 +132,22 @@ sub insert {
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
-  } else {
-    $dbh->commit if $oldAutoCommit;
-    return '';
   }
+
+  if ($options{'quotation_details'}) {
+    $error = $self->set_details(
+                details => $options{'quotation_details'},
+                copy_on_order => $options{'copy_on_order'} ? 'Y' : '',
+             );
+    if ( $error ) {
+      $error .= ' (setting details)';
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  $dbh->commit if $oldAutoCommit;
+  return '';
 }
 
 =item delete
index b1e60da..a1a6db6 100644 (file)
@@ -1,9 +1,4 @@
-<% include("/elements/header-popup.html", $title, '',
-            ( $cgi->param('error') ? '' : 'onload="addRow()"' ),
-          )
-%>
-
-%# <% include('/elements/error.html') %>
+<& /elements/header-popup.html, $title &>
 
 <FORM ACTION="process/cust_pkg_detail.html" NAME="DetailForm" ID="DetailForm" METHOD="POST">
 
     <TD COLSPAN=2><% ucfirst($name{$detailtype}) %>: </TD>
   </TR>
 
-% my $row = 0;
-% for ( @details ) { 
-
-    <TR>
-      <TD></TD>
-      <TD>
-        <INPUT TYPE="text" NAME="detail<% $row %>" SIZE="60" MAXLENGTH="65" VALUE="<% $_->detail |h %>" rownum="<% $row++ %>" onkeyup="possiblyAddRow" onchange="possiblyAddRow" >
-      </TD>
-    </TR>
-
-% } 
+<& elements/detail-table.html, 
+     id      => 'DetailTable',
+     details => \@details,
+ &>
 
 </TABLE>
 
 
 </FORM>
 
-<SCRIPT TYPE="text/javascript">
-
-  var rownum = <% $row %>;
-
-  function possiblyAddRow() {
-    if ( ( rownum - this.getAttribute('rownum') ) == 1 ) {
-      addRow();
-    }
-  }
-
-  function addRow() {
-
-    var table = document.getElementById('DetailTable');
-    var tablebody = table.getElementsByTagName('tbody').item(0);
-
-    var row = document.createElement('TR');
-
-    var empty_cell = document.createElement('TD');
-    row.appendChild(empty_cell);
-
-    var detail_cell = document.createElement('TD');
-
-      var detail_input = document.createElement('INPUT');
-      detail_input.setAttribute('name', 'detail'+rownum);
-      detail_input.setAttribute('id',   'detail'+rownum);
-      detail_input.setAttribute('size', 60);
-      detail_input.setAttribute('maxLength', 65);
-      detail_input.setAttribute('rownum',   rownum);
-      detail_input.onkeyup = possiblyAddRow;
-      detail_input.onchange = possiblyAddRow;
-      detail_cell.appendChild(detail_input);
-
-    row.appendChild(detail_cell);
-
-    tablebody.appendChild(row);
-
-    rownum++;
-
-  }
-
-</SCRIPT>
-
 </BODY>
 </HTML>
 <%init>
@@ -136,7 +82,7 @@ my $cust_pkg = qsearchs({
 
 my $part_pkg = $cust_pkg->part_pkg;
 
-my @details = $cust_pkg->cust_pkg_detail($detailtype);
+my @details = map { $_->detail } $cust_pkg->cust_pkg_detail($detailtype);
 
 my $title = ( scalar(@details) ? 'Edit ' : 'Add ' ). $name{$detailtype};
 
diff --git a/httemplate/edit/elements/detail-table.html b/httemplate/edit/elements/detail-table.html
new file mode 100644 (file)
index 0000000..496ba31
--- /dev/null
@@ -0,0 +1,85 @@
+<%doc>
+Common code for editing invoice/quotation details/comments.
+
+Expects to be the last element in a two-column table with specified id
+
+  <& /edit/elements/detail-table.html, 
+       id      => 'element_id', # required
+       details => \@details,    # plain text strings, existing details
+       label   => 'Comments',   # optional, shows on first row only
+       field   => 'comment',    # input field name/id, appended with rownum, default 'detail'
+  &>
+
+</%doc>
+
+<SCRIPT>
+% unless ($detail_table_init) {
+%   $detail_table_init = 1;
+
+  var detail_table_info = {};
+  detail_table_info.rownum = {};
+  detail_table_info.label  = {};
+  detail_table_info.field  = {};
+
+  function possiblyAddDetailRow(tableid,rownum) {
+    if (( detail_table_info.rownum[tableid] - rownum == 1 ) || !detail_table_info.rownum[tableid]) {
+      addDetailRow(tableid);
+    }
+  }
+
+  function addDetailRow(tableid,newtext) {
+
+    var table = document.getElementById(tableid);
+    var newrownum = detail_table_info.rownum[tableid];
+    var newfield  = detail_table_info.field[tableid] + newrownum;
+
+    var row = document.createElement('TR');
+
+    var empty_cell = document.createElement('TD');
+    if (!newrownum) {
+      empty_cell.innerHTML = detail_table_info.label[tableid];
+      empty_cell.style.textAlign = 'right';
+    }
+    row.appendChild(empty_cell);
+
+    var detail_cell = document.createElement('TD');
+
+    var detail_input = document.createElement('INPUT');
+    detail_input.setAttribute('name', newfield);
+    detail_input.setAttribute('id',   newfield);
+    detail_input.setAttribute('size', 60);
+    detail_input.setAttribute('maxLength', 65);
+    detail_input.onkeyup = function () { possiblyAddDetailRow(tableid,newrownum) };
+    detail_input.onchange = function () { possiblyAddDetailRow(tableid,newrownum) };
+    detail_input.value = newtext || '';
+    detail_cell.appendChild(detail_input);
+
+    row.appendChild(detail_cell);
+
+    table.appendChild(row);
+
+    detail_table_info.rownum[tableid]++;
+
+  }
+% } # end init
+  detail_table_info.label['<% $id %>'] = '<% emt($label) %>';
+  detail_table_info.field['<% $id %>'] = '<% $field %>';
+  detail_table_info.rownum['<% $id %>'] = 0;
+% foreach my $detail ( @details ) { 
+  addDetailRow('<% $id %>','<% $detail %>');
+% } 
+</SCRIPT>
+
+<%shared>
+my $detail_table_init = 0;
+</%shared>
+<%init>
+my %opt = @_;
+
+my @details = $opt{'details'} ? @{ $opt{'details'} } : ();
+push(@details,'') if $details[$#details] || !@details;
+my $id = $opt{'id'} or die "No id specified";
+my $label = $opt{'label'} || '';
+my $field = $opt{'field'} || 'detail';
+
+</%init>
index 6035215..5afddde 100644 (file)
@@ -159,14 +159,38 @@ foreach my $quantity_param ( grep { $cgi->param($_) && $cgi->param($_) > 0 }
 }
 $hash{cust_pkg_usageprice} = \@cust_pkg_usageprice;
 
+# extract details (false laziness with /misc/order_pkg.html)
+my $details = {
+  'invoice_detail' => [],
+  'package_comment' => [],
+  'quotation_detail' => [],
+};
+foreach my $field ( $cgi->param ) {
+  foreach my $detailtype ( keys %$details ) {
+    if ($field =~ /^$detailtype(\d+)$/) {
+      $details->{$detailtype}->[$1] = $cgi->param($field);
+    }
+  }
+}
+foreach my $detailtype ( keys %$details ) {
+  @{ $details->{$detailtype} } = grep { length($_) } @{ $details->{$detailtype} };
+}
+
 if ( $quotationnum ) {
 
   $quotation_pkg = new FS::quotation_pkg \%hash;
   $quotation_pkg->quotationnum($quotationnum);
   $quotation_pkg->prospectnum($prospect_main->prospectnum) if $prospect_main;
 
+  my %opt = @{ $details->{'quotation_detail'} }
+  ? (
+    quotation_details => $details->{'quotation_detail'},
+    copy_on_order     => scalar($cgi->param('copy_on_order')) ? 'Y' : '',
+  )
+  : ();
+
   #XXX handle new location
-  $error = $quotation_pkg->insert;
+  $error = $quotation_pkg->insert(%opt);
 
 } else {
 
@@ -194,6 +218,9 @@ if ( $quotationnum ) {
     $opt{'locationnum'} = $locationnum;
   }
 
+  $opt{'invoice_details'} = $details->{'invoice_detail'} if @{ $details->{'invoice_detail'} };
+  $opt{'package_comments'} = $details->{'package_comment'} if @{ $details->{'package_comment'} };
+
   $error = $cust_main->order_pkg( \%opt );
 
 }
index ae09b9c..036bffd 100644 (file)
@@ -1,9 +1,4 @@
-<% include("/elements/header-popup.html", $title, '',
-            ( $cgi->param('error') ? '' : 'onload="addRow()"' ),
-          )
-%>
-
-%# <% include('/elements/error.html') %>
+<& /elements/header-popup.html, $title &>
 
 <FORM ACTION="process/quotation_pkg_detail.html" NAME="DetailForm" ID="DetailForm" METHOD="POST">
 
     </TD>
   </TR>
 
-% my $row = 0;
-% for ( @details ) { 
-
-    <TR>
-      <TD ALIGN="right"><% $row ? '' : 'Detail' %></TD>
-      <TD>
-        <INPUT TYPE="text" NAME="detail<% $row %>" SIZE="60" MAXLENGTH="65" VALUE="<% $_ |h %>" rownum="<% $row++ %>" onkeyup="possiblyAddRow" onchange="possiblyAddrow">
-      </TD>
-    </TR>
-
-% } 
+<& elements/detail-table.html, 
+     id      => 'DetailTable',
+     details => \@details,
+     label   => 'Details',
+ &>
 
 </TABLE>
 
 
 </FORM>
 
-<SCRIPT TYPE="text/javascript">
-% # abject false laziness with edit/cust_pkg_detail.html
-
-  var rownum = <% $row %>;
-
-  function possiblyAddRow() {
-    if ( ( rownum - this.getAttribute('rownum') ) == 1 ) {
-      addRow();
-    }
-  }
-
-  function addRow() {
-
-    var table = document.getElementById('DetailTable');
-    var tablebody = table.getElementsByTagName('tbody').item(0);
-
-    var row = document.createElement('TR');
-
-    var empty_cell = document.createElement('TD');
-    if (!rownum) {
-      empty_cell.innerHTML = 'Detail:'
-      empty_cell.style.textAlign = 'right';
-    }
-    row.appendChild(empty_cell);
-
-    var detail_cell = document.createElement('TD');
-
-      var detail_input = document.createElement('INPUT');
-      detail_input.setAttribute('name', 'detail'+rownum);
-      detail_input.setAttribute('id',   'detail'+rownum);
-      detail_input.setAttribute('size', 60);
-      detail_input.setAttribute('maxLength', 65);
-      detail_input.setAttribute('rownum',   rownum);
-      detail_input.onkeyup = possiblyAddRow;
-      detail_input.onchange = possiblyAddRow;
-      detail_cell.appendChild(detail_input);
-
-    row.appendChild(detail_cell);
-
-    tablebody.appendChild(row);
-
-    rownum++;
-
-  }
-
-</SCRIPT>
-
 </BODY>
 </HTML>
 <%init>
index 4e061e2..39cb2f4 100644 (file)
 
 % }
 
+% if ($quotationnum) {
+<BR>
+<FONT CLASS="fsinnerbox-title"><% mt('Quotation details') |h %></FONT>
+<TABLE ID="QuotationDetailTable" BORDER="0" BGCOLOR="#cccccc">
+  <TR>
+    <TD></TD>
+    <TD>
+      <SELECT NAME="copy_on_order">
+        <OPTION VALUE=""<% $copy_on_order ? '' : ' SELECTED' %>>
+          <% emt('Details will only appear on quotation') %>
+        </OPTION>
+        <OPTION VALUE="Y"<% $copy_on_order ? ' SELECTED' : '' %>>
+          <% emt('Copy details to invoice when placing order') %>
+        </OPTION>
+      </SELECT>
+    </TD>
+  </TR>
+<& /edit/elements/detail-table.html, 
+     id      => 'QuotationDetailTable',
+     details => $details->{'quotation_detail'},
+     field   => 'quotation_detail',
+ &>
+</TABLE>
+% } else {
+<BR>
+<FONT CLASS="fsinnerbox-title"><% mt('Invoice details') |h %></FONT>
+<TABLE ID="InvoiceDetailTable" BORDER="0" BGCOLOR="#cccccc">
+<& /edit/elements/detail-table.html, 
+     id      => 'InvoiceDetailTable',
+     details => $details->{'invoice_detail'},
+     field   => 'invoice_detail',
+ &>
+</TABLE>
+
+<BR>
+<FONT CLASS="fsinnerbox-title"><% mt('Package comments') |h %></FONT>
+<TABLE ID="PackageCommentTable" BORDER="0" BGCOLOR="#cccccc">
+<& /edit/elements/detail-table.html, 
+     id      => 'PackageCommentTable',
+     details => $details->{'package_comment'},
+     field   => 'package_comment',
+ &>
+</TABLE>
+% }
+
+
 <BR>
 % my $onclick = $cgi->param('lock_locationnum')
 %                 ? 'document.OrderPkgForm.submit()'
@@ -245,6 +291,23 @@ if ( $cgi->param('quotationnum') =~ /^(\d+)$/ ) {
   $quotationnum = $1;
 }
 
+my $details = {
+  'invoice_detail' => [],
+  'package_comment' => [],
+  'quotation_detail' => [],
+};
+foreach my $field ( $cgi->param ) {
+  foreach my $detailtype ( keys %$details ) {
+    if ($field =~ /^$detailtype(\d+)$/) {
+      $details->{$detailtype}->[$1] = $cgi->param($field);
+    }
+  }
+}
+foreach my $detailtype ( keys %$details ) {
+  @{ $details->{$detailtype} } = grep { length($_) } @{ $details->{$detailtype} };
+}
+my $copy_on_order = $cgi->param('copy_on_order');
+
 die 'no custnum or prospectnum' unless $cust_main || $prospect_main;
 
 my $agent =  $cust_main ? $cust_main->agent