RT#39831 Quotation extra information for line items [v3 merge]
authorJonathan Prykop <jonathan@freeside.biz>
Sat, 30 Jan 2016 02:24:46 +0000 (20:24 -0600)
committerJonathan Prykop <jonathan@freeside.biz>
Sat, 30 Jan 2016 22:03:22 +0000 (16:03 -0600)
FS/FS/Schema.pm
FS/FS/quotation.pm
FS/FS/quotation_pkg.pm
FS/FS/quotation_pkg_detail.pm
httemplate/edit/process/quotation_pkg_detail.html
httemplate/edit/quotation_pkg_detail.html

index a71b902..774a11f 100644 (file)
@@ -1389,6 +1389,7 @@ sub tables_hashref {
         'quotationpkgnum', 'int', '', '', '', '',
         'format',  'char', 'NULL', 1, '', '',       # not used for anything
         'detail',  'varchar', '', 255, '', '',
         'quotationpkgnum', 'int', '', '', '', '',
         'format',  'char', 'NULL', 1, '', '',       # not used for anything
         'detail',  'varchar', '', 255, '', '',
+        'copy_on_order',        'char', 'NULL',  1, '', '', # 'Y' to copy when ordering
       ],
       'primary_key'  => 'detailnum',
       'unique'       => [],
       ],
       'primary_key'  => 'detailnum',
       'unique'       => [],
index 669a254..6a7c9c4 100644 (file)
@@ -421,7 +421,7 @@ sub convert_cust_main {
 
 }
 
 
 }
 
-=item order
+=item order [ HASHREF ]
 
 This method is for use with quotations which are already associated with a customer.
 
 
 This method is for use with quotations which are already associated with a customer.
 
@@ -429,14 +429,27 @@ Orders this quotation's packages as real packages for the customer.
 
 If there is an error, returns an error message, otherwise returns false.
 
 
 If there is an error, returns an error message, otherwise returns false.
 
+If HASHREF is passed, it will be filled with a hash mapping the 
+C<quotationpkgnum> of each quoted package to the C<pkgnum> of the package
+as ordered.
+
 =cut
 
 sub order {
   my $self = shift;
 =cut
 
 sub order {
   my $self = shift;
+  my $pkgnum_map = shift || {};
+  my $details_map = {};
 
   tie my %all_cust_pkg, 'Tie::RefHash';
   foreach my $quotation_pkg ($self->quotation_pkg) {
     my $cust_pkg = FS::cust_pkg->new;
 
   tie my %all_cust_pkg, 'Tie::RefHash';
   foreach my $quotation_pkg ($self->quotation_pkg) {
     my $cust_pkg = FS::cust_pkg->new;
+    $pkgnum_map->{ $quotation_pkg->quotationpkgnum } = $cust_pkg;
+
+    # details will be copied below, after package is ordered
+    $details_map->{ $quotation_pkg->quotationpkgnum } = [ 
+      map { $_->copy_on_order ? $_->detail : () } $quotation_pkg->quotation_pkg_detail
+    ];
+
     foreach (qw(pkgpart locationnum start_date contract_end quantity waive_setup)) {
       $cust_pkg->set( $_, $quotation_pkg->get($_) );
     }
     foreach (qw(pkgpart locationnum start_date contract_end quantity waive_setup)) {
       $cust_pkg->set( $_, $quotation_pkg->get($_) );
     }
@@ -450,7 +463,44 @@ sub order {
     $all_cust_pkg{$cust_pkg} = []; # no services
   }
 
     $all_cust_pkg{$cust_pkg} = []; # no services
   }
 
-  $self->cust_main->order_pkgs( \%all_cust_pkg );
+  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;
+
+  my $error = $self->cust_main->order_pkgs( \%all_cust_pkg );
+  
+  unless ($error) {
+    # copy details (copy_on_order filtering handled above)
+    foreach my $quotationpkgnum (keys %$details_map) {
+      next unless @{$details_map->{$quotationpkgnum}};
+      $error = $pkgnum_map->{$quotationpkgnum}->set_cust_pkg_detail(
+        'I',
+        @{$details_map->{$quotationpkgnum}}
+      );
+      last if $error;
+    }
+  }
+
+  foreach my $quotationpkgnum (keys %$pkgnum_map) {
+    # convert the objects to just pkgnums
+    my $cust_pkg = $pkgnum_map->{$quotationpkgnum};
+    $pkgnum_map->{$quotationpkgnum} = $cust_pkg->pkgnum;
+  }
+
+  if ($error) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  ''; #no error
 
 }
 
 
 }
 
index 1a2fadc..f3356b5 100644 (file)
@@ -416,16 +416,27 @@ sub delete_details {
 
 }
 
 
 }
 
-=item set_details [ DETAIL, DETAIL, ... ]
+=item set_details PARAM
 
 
-Sets quotation details for this package (see L<FS::quotation_pkg_detail>).
+Sets new quotation details for this package (see L<FS::quotation_pkg_detail>),
+removing existing details.
+
+Recognizes the following parameters:
+
+details - arrayref of strings, one for each new detail
+
+copy_on_order - if true, sets copy_on_order flag on new details
 
 If there is an error, returns the error, otherwise returns false.
 
 =cut
 
 sub set_details {
 
 If there is an error, returns the error, otherwise returns false.
 
 =cut
 
 sub set_details {
-  my( $self, @details ) = @_;
+  my $self = shift;
+  my %opt = @_;
+
+  $opt{'details'} ||= [];
+  my @details = @{$opt{'details'}};
 
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
 
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
@@ -441,6 +452,7 @@ sub set_details {
     my $quotation_pkg_detail = new FS::quotation_pkg_detail {
       'quotationpkgnum' => $self->quotationpkgnum,
       'detail' => $detail,
     my $quotation_pkg_detail = new FS::quotation_pkg_detail {
       'quotationpkgnum' => $self->quotationpkgnum,
       'detail' => $detail,
+      'copy_on_order' => $opt{'copy_on_order'} ? 'Y' : '',
     };
     $error = $quotation_pkg_detail->insert;
     if ( $error ) {
     };
     $error = $quotation_pkg_detail->insert;
     if ( $error ) {
@@ -519,6 +531,12 @@ sub quotation {
   FS::quotation->by_key($self->quotationnum);
 }
 
   FS::quotation->by_key($self->quotationnum);
 }
 
+sub quotation_pkg_detail {
+  my $self = shift;
+  sort { $a->detailnum <=> $b->detailnum }
+    qsearch('quotation_pkg_detail', { quotationpkgnum => $self->quotationpkgnum });
+}
+
 sub quotation_pkg_discount {
   my $self = shift;
   qsearch('quotation_pkg_discount', { quotationpkgnum => $self->quotationpkgnum });
 sub quotation_pkg_discount {
   my $self = shift;
   qsearch('quotation_pkg_discount', { quotationpkgnum => $self->quotationpkgnum });
index ce13589..76e2fd1 100644 (file)
@@ -42,6 +42,10 @@ for the relevant L<FS::quotation_pkg>
 
 detail text
 
 
 detail text
 
+=item copy_on_order
+
+flag, indicates detail should be copied over when ordering
+
 =cut
 
 # 'format' field isn't used, there for TemplateItem_Mixin
 =cut
 
 # 'format' field isn't used, there for TemplateItem_Mixin
@@ -109,6 +113,7 @@ sub check {
     $self->ut_numbern('detailnum')
     || $self->ut_foreign_key('quotationpkgnum', 'quotation_pkg', 'quotationpkgnum')
     || $self->ut_text('detail')
     $self->ut_numbern('detailnum')
     || $self->ut_foreign_key('quotationpkgnum', 'quotation_pkg', 'quotationpkgnum')
     || $self->ut_text('detail')
+    || $self->ut_flag('copy_on_order')
   ;
   return $error if $error;
 
   ;
   return $error if $error;
 
index 2fc4202..9e4ac32 100644 (file)
@@ -40,6 +40,9 @@ for ( my $row = 0; exists($param->{"detail$row"}); $row++ ) {
     if $param->{"detail$row"} =~ /\S/;
 }
 
     if $param->{"detail$row"} =~ /\S/;
 }
 
-my $error = $quotation_pkg->set_details(@details);
+my $error = $quotation_pkg->set_details( 
+              details => \@details,
+              copy_on_order => scalar($cgi->param('copy_on_order')) ? 'Y' : ''
+            );
 
 </%init>
 
 </%init>
index 80a9044..ae09b9c 100644 (file)
     <TD BGCOLOR="#ffffff"><% $part_pkg->comment |h %></TD>
   </TR>
 
     <TD BGCOLOR="#ffffff"><% $part_pkg->comment |h %></TD>
   </TR>
 
+  <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>
+
 % my $row = 0;
 % for ( @details ) { 
 
 % my $row = 0;
 % for ( @details ) { 
 
@@ -111,6 +125,21 @@ my $part_pkg = $quotation_pkg->part_pkg;
 
 my @details = $quotation_pkg->details;
 
 
 my @details = $quotation_pkg->details;
 
+my $copy_on_order = 0;
+if (@details) {
+
+  # currently, they should either all have this flag, or none
+  # but just in case, erring on the side of not copying to invoice 
+  #   unless every existing detail has copy_on_order
+  # (anyway, user has to submit change, this is just for autofill)
+
+  my @quotation_pkg_detail = $quotation_pkg->quotation_pkg_detail;
+  my @copy_on_order = grep { $_->copy_on_order } @quotation_pkg_detail;
+  $copy_on_order = 1 if @copy_on_order;
+  my @no_copy_on_order = grep { !$_->copy_on_order } @quotation_pkg_detail;
+  $copy_on_order = 0 if @no_copy_on_order;  
+}
+
 my $title = ( scalar(@details) ? 'Edit ' : 'Add ' ). 'Quotation Details';
 
 </%init>
 my $title = ( scalar(@details) ? 'Edit ' : 'Add ' ). 'Quotation Details';
 
 </%init>