disable quotations, RT#20688, RT#22232
authorIvan Kohler <ivan@freeside.biz>
Sun, 18 Jan 2015 22:03:07 +0000 (14:03 -0800)
committerIvan Kohler <ivan@freeside.biz>
Sun, 18 Jan 2015 22:03:07 +0000 (14:03 -0800)
FS/FS/AccessRight.pm
FS/FS/Record.pm
FS/FS/access_right.pm
FS/FS/quotation.pm
httemplate/misc/disable-quotation.html [new file with mode: 0644]
httemplate/misc/enable-quotation.html [new file with mode: 0644]
httemplate/search/elements/search.html
httemplate/search/quotation.html
httemplate/view/cust_main.cgi
httemplate/view/quotation.html

index 4a1f89a..121f83c 100644 (file)
@@ -97,6 +97,7 @@ tie my %rights, 'Tie::IxHash',
     #'New contact',
     #'View customer contacts',
     'Generate quotation',
+    'Disable quotation',
   ],
   
   ###
index 25e61d0..4546741 100644 (file)
@@ -743,72 +743,74 @@ sub _from_hashref {
   return @return;
 }
 
-## makes this easier to read
-
 sub get_real_fields {
   my $table = shift;
   my $record = shift;
   my $real_fields = shift;
 
-   ## this huge map was previously inline, just broke it out to help read the qsearch method, should be optimized for readability
-      return ( 
-      map {
+  ## could be optimized more for readability
+  return ( 
+    map {
 
       my $op = '=';
       my $column = $_;
+      my $table_column = "$table.$column";
       my $type = dbdef->table($table)->column($column)->type;
       my $value = $record->{$column};
       $value = $value->{'value'} if ref($value);
-      if ( ref($record->{$_}) ) {
-        $op = $record->{$_}{'op'} if $record->{$_}{'op'};
+
+      if ( ref($record->{$column}) ) {
+        $op = $record->{$column}{'op'} if $record->{$column}{'op'};
         #$op = 'LIKE' if $op =~ /^ILIKE$/i && driver_name ne 'Pg';
         if ( uc($op) eq 'ILIKE' ) {
           $op = 'LIKE';
-          $record->{$_}{'value'} = lc($record->{$_}{'value'});
-          $column = "LOWER($_)";
+          $record->{$column}{'value'} = lc($record->{$column}{'value'});
+          $table_column = "LOWER($table_column)";
         }
-        $record->{$_} = $record->{$_}{'value'}
+        $record->{$column} = $record->{$column}{'value'}
       }
 
-      if ( ! defined( $record->{$_} ) || $record->{$_} eq '' ) {
+      if ( ! defined( $record->{$column} ) || $record->{$column} eq '' ) {
         if ( $op eq '=' ) {
           if ( driver_name eq 'Pg' ) {
             if ( $type =~ /(int|numeric|real|float4|(big)?serial)/i ) {
-              qq-( $column IS NULL )-;
+              qq-( $table_column IS NULL )-;
             } else {
-              qq-( $column IS NULL OR $column = '' )-;
+              qq-( $table_column IS NULL OR $table_column = '' )-;
             }
           } else {
-            qq-( $column IS NULL OR $column = "" )-;
+            qq-( $table_column IS NULL OR $table_column = "" )-;
           }
         } elsif ( $op eq '!=' ) {
           if ( driver_name eq 'Pg' ) {
             if ( $type =~ /(int|numeric|real|float4|(big)?serial)/i ) {
-              qq-( $column IS NOT NULL )-;
+              qq-( $table_column IS NOT NULL )-;
             } else {
-              qq-( $column IS NOT NULL AND $column != '' )-;
+              qq-( $table_column IS NOT NULL AND $table_column != '' )-;
             }
           } else {
-            qq-( $column IS NOT NULL AND $column != "" )-;
+            qq-( $table_column IS NOT NULL AND $table_column != "" )-;
           }
         } else {
           if ( driver_name eq 'Pg' ) {
-            qq-( $column $op '' )-;
+            qq-( $table_column $op '' )-;
           } else {
-            qq-( $column $op "" )-;
+            qq-( $table_column $op "" )-;
           }
         }
       } elsif ( $op eq '!=' ) {
-        qq-( $column IS NULL OR $column != ? )-;
+        qq-( $table_column IS NULL OR $table_column != ? )-;
       #if this needs to be re-enabled, it needs to use a custom op like
       #"APPROX=" or something (better name?, not '=', to avoid affecting other
       # searches
       #} elsif ( $op eq 'APPROX=' && _is_fs_float( $type, $value ) ) {
-      #  ( "$column <= ?", "$column >= ?" );
+      #  ( "$table_column <= ?", "$table_column >= ?" );
       } else {
-        "$column $op ?";
+        "$table_column $op ?";
       }
-    } @{ $real_fields } );  
+
+    } @{ $real_fields }
+  );  
 }
 
 =item by_key PRIMARY_KEY_VALUE
index e5a5781..d5e3b8b 100644 (file)
@@ -250,6 +250,7 @@ sub _upgrade_data { # class method
     'List prospects' => 'List contacts',
     'List customers' => 'List contacts',
     'Backdate payment' => 'Backdate credit',
+    'Generate quotation' => 'Disable quotation',
   );
 
 #  foreach my $old_acl ( keys %onetime ) {
index e72e6cf..5710b38 100644 (file)
@@ -6,6 +6,7 @@ use strict;
 use Tie::RefHash;
 use FS::CurrentUser;
 use FS::UID qw( dbh );
+use FS::Maketext qw( emt );
 use FS::cust_main;
 use FS::cust_pkg;
 
@@ -166,6 +167,38 @@ sub _total {
 
 }
 
+=item cust_or_prospect_label_link P
+
+HTML links to either the customer or prospect.
+
+Returns a list consisting of two elements.  The first is a text label for the
+link, and the second is the URL.
+
+=cut
+
+sub cust_or_prospect_label_link {
+  my( $self, $p ) = @_;
+
+  if ( my $custnum = $self->custnum ) {
+    my $display_custnum = $self->cust_main->display_custnum;
+    my $target = $FS::CurrentUser::CurrentUser->default_customer_view eq 'jumbo'
+                   ? '#quotations'
+                   : ';show=quotations';
+    (
+      emt("View this customer (#[_1])",$display_custnum) =>
+        "${p}view/cust_main.cgi?custnum=$custnum$target"
+    );
+  } elsif ( my $prospectnum = $self->prospectnum ) {
+    (
+      emt("View this prospect (#[_1])",$prospectnum) =>
+        "${p}view/prospect_main.html?$prospectnum"
+    );
+  } else { #die?
+    ( '', '' );
+  }
+
+}
+
 #prevent things from falsely showing up as taxes, at least until we support
 # quoting tax amounts..
 sub _items_tax {
@@ -271,6 +304,35 @@ sub order {
 
 }
 
+=item disable
+
+Disables this quotation (sets disabled to Y, which hides the quotation on
+prospects and customers).
+
+If there is an error, returns an error message, otherwise returns false.
+
+=cut
+
+sub disable {
+  my $self = shift;
+  $self->disabled('Y');
+  $self->replace();
+}
+
+=item enable
+
+Enables this quotation.
+
+If there is an error, returns an error message, otherwise returns false.
+
+=cut
+
+sub enable {
+  my $self = shift;
+  $self->disabled('');
+  $self->replace();
+}
+
 =back
 
 =head1 CLASS METHODS
diff --git a/httemplate/misc/disable-quotation.html b/httemplate/misc/disable-quotation.html
new file mode 100644 (file)
index 0000000..a6c4829
--- /dev/null
@@ -0,0 +1,21 @@
+%if ( $error ) {
+%  errorpage($error);
+%} else {
+<% $cgi->redirect($url) %>
+%}
+<%init>
+
+die "access deined"
+  unless $FS::CurrentUser::CurrentUser->access_right('Disable quotation');
+
+$cgi->param('quotationnum') =~ /^(\d+)$/ or die 'illegal quotationnum';
+my $quotationnum = $1;
+
+my $quotation =
+  qsearchs('quotation', { 'quotationnum' => $quotationnum } );
+
+my $error = $quotation->disable;
+
+my( $label, $url ) = $quotation->cust_or_prospect_label_link( popurl(2) );
+
+</%init>
diff --git a/httemplate/misc/enable-quotation.html b/httemplate/misc/enable-quotation.html
new file mode 100644 (file)
index 0000000..e5bb499
--- /dev/null
@@ -0,0 +1,21 @@
+%if ( $error ) {
+%  errorpage($error);
+%} else {
+<% $cgi->redirect(popurl(2)."view/quotation.html?quotationnum=$quotationnum") %>
+%}
+<%init>
+
+die "access deined"
+  unless $FS::CurrentUser::CurrentUser->access_right('Disable quotation');
+
+$cgi->param('quotationnum') =~ /^(\d+)$/ or die 'illegal quotationnum';
+my $quotationnum = $1;
+
+my $quotation =
+  qsearchs('quotation', { 'quotationnum' => $quotationnum } );
+
+my $error = $quotation->enable;
+
+#my( $label, $url ) = $quotation->cust_or_prospect_label_link( popurl(2) );
+
+</%init>
index 3fb1e3e..62a0e47 100644 (file)
@@ -307,9 +307,11 @@ if ( $opt{'disableable'} ) {
     $opt{'query'}{'hashref'}{'disabled'} = '';
     $opt{'query'}{'extra_sql'} =~ s/^\s*WHERE/ AND/i;
 
+    my $table = $opt{'query'}{'table'};
+
     $opt{'count_query'} .=
       ( $opt{'count_query'} =~ /WHERE/i ? ' AND ' : ' WHERE ' ).
-      "( disabled = '' OR disabled IS NULL )";
+      "( $table.disabled = '' OR $table.disabled IS NULL )";
 
   } elsif (    $opt{'disabled_statuspos'}
             || $opt{'disabled_statuspos'} eq '0' ) { #add status column
@@ -360,12 +362,6 @@ unless ( $type =~ /^(csv|xml|\w*.xls)$/) {
       s/^\s*SELECT\s*(.*?)\s+FROM\s/SELECT COUNT(*) FROM /i; #silly vim:/
   }
 
-  if ( $opt{disableable} && ! $cgi->param('showdisabled') ) {
-    $opt{count_query} .=
-      ( ( $opt{count_query} =~ /WHERE/i ) ? ' AND ' : ' WHERE ' ).
-      "( disabled = '' OR disabled IS NULL )";
-  }
-
   unless ( $type eq 'html-print' ) {
 
     #setup some pagination things if we're in html mode
index fbc35be..6badb13 100755 (executable)
@@ -1,20 +1,22 @@
 <& elements/search.html,
-                 'title'       => emt('Quotation Search Results'),
-                 'html_init'   => $html_init,
-                 'menubar'     => $menubar,
-                 'name'        => 'quotations',
-                 'query'       => $sql_query,
-                 'count_query' => $count_query,
-                 'count_addl'  => $count_addl,
-                 'redirect'    => $link,
-                 'header'      => [ emt('Quotation #'),
-                                    emt('Setup'),
-                                    emt('Recurring'),
-                                    emt('Date'),
-                                    emt('Prospect'),
-                                    emt('Customer'),
-                                  ],
-                 'fields'      => [
+                 'title'              => emt('Quotation Search Results'),
+                 'html_init'          => $html_init,
+                 'menubar'            => $menubar,
+                 'name'               => 'quotations',
+                 'query'              => $sql_query,
+                 'count_query'        => $count_query,
+                 'count_addl'         => $count_addl,
+                 'redirect'           => $link,
+                 'disableable'        => 1,
+                 'disabled_statuspos' => 1,
+                 'header'             => [ emt('Quotation #'),
+                                           emt('Setup'),
+                                           emt('Recurring'),
+                                           emt('Date'),
+                                           emt('Prospect'),
+                                           emt('Customer'),
+                                         ],
+                 'fields'             => [
                    'quotationnum',
                    sub { $money_char. shift->total_setup },
                    sub { $money_char. shift->total_recur },
@@ -27,7 +29,7 @@
                        },
                    #\&FS::UI::Web::cust_fields,
                  ],
-                 'sort_fields' => [
+                 'sort_fields'        => [
                    'quotationnum',
                    '', #FS::quotation->total_setup_sql,
                    '', #FS::quotation->total_recur_sql,
@@ -43,7 +45,7 @@
                    $link,
                    $prospect_link,
                    $cust_link,
-                   #( map { $_ ne 'Cust. Status' ? $clink : '' }
+                   #( map { $_ ne 'Cust. Status' ? $cust_link : '' }
                    #      FS::UI::Web::cust_header()
                    #),
                  ],
index 833b6d0..d18c7f7 100755 (executable)
@@ -239,7 +239,7 @@ function areyousure(href, message) {
 % ###
 
 % if ( $view eq 'jumbo' && $curuser->access_right('Generate quotation') ) { 
-  <A NAME="quotation"><FONT SIZE="+2"><% mt('Quotations') |h %></FONT></A><BR>
+  <A NAME="quotations"><FONT SIZE="+2"><% mt('Quotations') |h %></FONT></A><BR>
 % }
 
 % if ( $view eq 'quotations' || $view eq 'jumbo' ) {
index 4c91325..b8dc1d1 100755 (executable)
@@ -7,47 +7,58 @@ function areyousure(href, message) {
 }
 </SCRIPT>
 
-%#XXX link to order...
+% unless ( $quotation->disabled eq 'Y' ) {
 
-<%doc>
+%   if ( $curuser->access_right('Order customer package') ) {
+      <& /elements/order_pkg_link.html,
+           'label'       => emt('Add package'),
+           'actionlabel' => emt('Add package'),
+           map { $_ => $quotation->$_ } qw( quotationnum custnum prospectnum )
+      &>
+      <BR><BR>
+%   }
 
-XXX resending quotations
+%   if ( 1 ) { #if ( $curuser->access_right('Send quotations') )
 
-% if ( $curuser->access_right('Resend invoices') ) {
+%     #if ( grep { $_ ne 'POST' } $cust_bill->cust_main->invoicing_list ) { 
+%#      <A HREF="<% $p %>misc/email-quotation.html?<% $link %>"><% mt('Email this quotation') |h %></A>
+%     #} 
 
-    <A HREF="<% $p %>misc/send-invoice.cgi?method=print;<% $link %>"><% mt('Re-print this invoice') |h %></A>
+%#      <A HREF="<% $p %>misc/send-invoice.cgi?method=print;<% $link %>"><% mt('Re-print this invoice') |h %></A>
 
-%   if ( grep { $_ ne 'POST' } $cust_bill->cust_main->invoicing_list ) { 
-        | <A HREF="<% $p %>misc/send-invoice.cgi?method=email;<% $link %>"><% mt('Re-email this invoice') |h %></A>
-%   } 
+%#%     if ( $conf->exists('hylafax') && length($cust_bill->cust_main->fax) ) { 
+%#           | <A HREF="<% $p %>misc/send-invoice.cgi?method=fax;<% $link %>"><% mt('Re-fax this invoice') |h %></A>
+%#%     } 
 
-%   if ( $conf->exists('hylafax') && length($cust_bill->cust_main->fax) ) { 
-        | <A HREF="<% $p %>misc/send-invoice.cgi?method=fax;<% $link %>"><% mt('Re-fax this invoice') |h %></A>
-%   } 
+%   }
 
-    <BR><BR>
+%   if ( $conf->exists('quotation_latex') ) { 
+      | <A HREF="<% $p %>view/quotation-pdf.cgi?<% $link %>"><% mt('View typeset quotation PDF') |h %></A>
+%   }
 
-% } 
+    <BR><BR>
 
-</%doc>
+%   if ( $curuser->access_right('New customer') && $quotation->quotation_pkg ) {
+      <A HREF="<%$p%>edit/process/quotation_convert.html?quotationnum=<% $quotation->quotationnum %>">Place order</A>
+      <BR><BR>
+%   }
 
-% if ( $curuser->access_right('Order customer package') ) {
-  <& /elements/order_pkg_link.html,
-       'label'       => emt('Add package'),
-       'actionlabel' => emt('Add package'),
-       map { $_ => $quotation->$_ } qw( quotationnum custnum prospectnum )
-  &>
 % }
 
-% if ( $conf->exists('quotation_latex') ) { 
-  | <A HREF="<% $p %>view/quotation-pdf.cgi?<% $link %>"><% mt('View typeset quotation PDF') |h %></A>
+% if ( $curuser->access_right('Disable quotation') ) {
+%   if ( $quotation->disabled eq 'Y' ) {
+      <A HREF="<%$p%>misc/enable-quotation.html?quotationnum=<% $quotation->quotationnum %>" TITLE="<% emt('Enable this quotation') %>"><% emt('Enable this quotation') %></A>
+%   } else {
+      <% areyousure_link(
+           "${p}misc/disable-quotation.html?quotationnum=". $quotation->quotationnum,
+           emt('Are you sure you want to disable this quotation?'),
+           emt('Disable this quotation'), #tooltip
+           emt('Disable this quotation'), #link
+      ) %>
+%   }
+  <BR><BR>
 % }
 
-% if ( $curuser->access_right('New customer') && $quotation->quotation_pkg ) {
-  | <A HREF="<%$p%>edit/process/quotation_convert.html?quotationnum=<% $quotation->quotationnum %>">Place order</A>
-% }
-
-<BR><BR>
 
 % if ( $conf->exists('quotation_html') ) { 
     <% join('', $quotation->print_html( preref_callback=>$preref_callback )) %>
@@ -83,17 +94,7 @@ my $quotation = qsearchs({
 });
 die "Quotation #$quotationnum not found!" unless $quotation;
 
-my $menubar;
-if ( my $custnum = $quotation->custnum ) {
-  my $display_custnum = $quotation->cust_main->display_custnum;
-  $menubar = menubar(
-    emt("View this customer (#[_1])",$display_custnum) => "${p}view/cust_main.cgi?$custnum",
-  );
-} elsif ( my $prospectnum = $quotation->prospectnum ) {
-  $menubar = menubar(
-    emt("View this prospect (#[_1])",$prospectnum) => "${p}view/prospect_main.html?$prospectnum",
-  );
-}
+my $menubar = menubar( $quotation->cust_or_prospect_label_link($p) );
 
 my $link = "quotationnum=$quotationnum";
 #$link .= ';template='. uri_escape($template) if $template;