[freeside-commits] branch master updated. c8cfa4829c828793e26082d0ce1dfb9733bbcef0

Mark Wells mark at 420.am
Tue Apr 28 12:01:29 PDT 2015


The branch, master has been updated
       via  c8cfa4829c828793e26082d0ce1dfb9733bbcef0 (commit)
       via  d129179308646fb4eba078f1afe1fa2ddad51fbb (commit)
      from  babd7a6af0d1853ca0df76c6773f1383766344b6 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c8cfa4829c828793e26082d0ce1dfb9733bbcef0
Author: Mark Wells <mark at freeside.biz>
Date:   Tue Apr 28 11:31:34 2015 -0700

    explicitly pass quotationnum as an API param and other fixes, #33852

diff --git a/FS/FS/ClientAPI/MyAccount/quotation.pm b/FS/FS/ClientAPI/MyAccount/quotation.pm
index 787a099..df2b37e 100644
--- a/FS/FS/ClientAPI/MyAccount/quotation.pm
+++ b/FS/FS/ClientAPI/MyAccount/quotation.pm
@@ -11,40 +11,123 @@ sub _custoragent_session_custnum {
   FS::ClientAPI::MyAccount::_custoragent_session_custnum(@_);
 }
 
+# _quotation(session, quotationnum)
+# returns that quotation, or '' if it doesn't exist and belong to this
+# customer
+
 sub _quotation {
-  # the currently active quotation
   my $session = shift;
+  my $quotationnum = shift;
   my $quotation;
-  if ( my $quotationnum = $session->{'quotationnum'} ) {
-    $quotation = FS::quotation->by_key($quotationnum);
-  } 
-  if ( !$quotation ) {
-    # find the last quotation created through selfservice
+
+  if ( $quotationnum =~ /^(\d+)$/ ) {
     $quotation = qsearchs( 'quotation', {
-        'custnum'   => $session->{'custnum'},
-        'usernum'   => $FS::CurrentUser::CurrentUser->usernum,
-        'disabled'  => '',
+        'custnum'       => $session->{'custnum'},
+        'usernum'       => $FS::CurrentUser::CurrentUser->usernum,
+        'disabled'      => '',
+        'quotationnum'  => $1,
     }); 
     warn "found selfservice quotation #". $quotation->quotationnum."\n"
       if $quotation and $DEBUG;
-  } 
-  if ( !$quotation ) {
-    $quotation = FS::quotation->new({
-        'custnum'   => $session->{'custnum'},
-        'usernum'   => $FS::CurrentUser::CurrentUser->usernum,
-        '_date'     => time,
-    }); 
-    $quotation->insert; # what to do on error? call the police?
-    warn "started new selfservice quotation #". $quotation->quotationnum."\n"
+
+    return $quotation;
+  }
+  '';
+}
+
+=item list_quotations { session }
+
+Returns a hashref listing this customer's active self-service quotations.
+Contents are:
+
+- 'quotations', an arrayref containing an element for each quotation.
+  - quotationnum, the primary key
+  - _date, the date it was started
+  - num_pkgs, the number of packages
+  - total_setup, the sum of setup fees
+  - total_recur, the sum of recurring charges
+
+=cut
+
+sub list_quotations {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  my @quotations = qsearch('quotation', {
+      'custnum'   => $session->{'custnum'},
+      'usernum'   => $FS::CurrentUser::CurrentUser->usernum,
+      'disabled'  => '',
+  });
+  my @q;
+  foreach my $quotation (@quotations) {
+    warn "found selfservice quotation #". $quotation->quotationnum."\n"
       if $quotation and $DEBUG;
-  } 
-  $session->{'quotationnum'} = $quotation->quotationnum;
-  return $quotation;
+    push @q, { 'quotationnum' => $quotation->quotationnum,
+               '_date'        => $quotation->_date,
+               'num_pkgs'     => scalar($quotation->quotation_pkg),
+               'total_setup'  => $quotation->total_setup,
+               'total_recur'  => $quotation->total_recur,
+             };
+  }
+  return { 'quotations' => \@q, 'error' => '' };
 }
 
-=item quotation_info { session }
+=item quotation_new { session }
+
+Creates a quotation and returns its quotationnum.
+
+=cut
 
-Returns a hashref describing the current quotation, containing:
+sub quotation_new {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  my $quotation = FS::quotation->new({
+      'custnum'   => $session->{'custnum'},
+      'usernum'   => $FS::CurrentUser::CurrentUser->usernum,
+      '_date'     => time,
+  }); 
+  my $error = $quotation->insert;
+  if ( $error ) {
+    warn "failed to create selfservice quotation for custnum #" .
+      $session->{custnum} . "\n";
+    return { 'error' => $error };
+  } else {
+    warn "started new selfservice quotation #". $quotation->quotationnum."\n"
+      if $DEBUG;
+    return { 'error' => $error, 'quotationnum' => $quotation->quotationnum };
+  }
+}
+
+=item quotation_delete { session, quotationnum }
+
+Disables (doesn't actually delete) the specified quotationnum.
+
+=cut
+
+sub quotation_delete {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  my $quotation = _quotation($session, $p->{quotationnum})
+    or return { 'error' => "Quotation not found" };
+  warn "quotation_delete #".$quotation->quotationnum
+    if $DEBUG;
+
+  $quotation->set('disabled' => 'Y');
+  my $error = $quotation->replace;
+  return { 'error' => $error };
+}
+
+=item quotation_info { session, quotationnum }
+
+Returns a hashref describing the specified quotation, containing:
 
 - "sections", an arrayref containing one section for each billing frequency.
   Each one will have:
@@ -55,6 +138,9 @@ Returns a hashref describing the current quotation, containing:
     - "description", the package name (or tax name)
     - "quantity"
     - "amount"
+- "num_pkgs", the number of packages in the quotation
+- "total_setup", the sum of setup/one-time charges and their taxes
+- "total_recur", the sum of all recurring charges and their taxes
 
 =cut
 
@@ -64,8 +150,8 @@ sub quotation_info {
   my($context, $session, $custnum) = _custoragent_session_custnum($p);
   return { 'error' => $session } if $context eq 'error';
 
-  my $quotation = _quotation($session);
-  return { 'error' => "No current quotation for this customer" } if !$quotation;
+  my $quotation = _quotation($session, $p->{quotationnum})
+    or return { 'error' => "Quotation not found" };
   warn "quotation_info #".$quotation->quotationnum
     if $DEBUG;
 
@@ -76,7 +162,12 @@ sub quotation_info {
     $section->{'detail_items'} =
       [ $quotation->_items_pkg('section' => $section, escape_function => $null_escape) ]; 
   }
-  return { 'error' => '', 'sections' => $sections }
+  return { 'error'        => '',
+           'sections'     => $sections,
+           'num_pkgs'     => scalar($quotation->quotation_pkg),
+           'total_setup'  => $quotation->total_setup,
+           'total_recur'  => $quotation->total_recur,
+         };
 }
 
 =item quotation_print { session, 'format' }
@@ -92,8 +183,8 @@ sub quotation_print {
   my($context, $session, $custnum) = _custoragent_session_custnum($p);
   return { 'error' => $session } if $context eq 'error';
 
-  my $quotation = _quotation($session);
-  return { 'error' => "No current quotation for this customer" } if !$quotation;
+  my $quotation = _quotation($session, $p->{quotationnum})
+    or return { 'error' => "Quotation not found" };
   warn "quotation_print #".$quotation->quotationnum
     if $DEBUG;
 
@@ -128,7 +219,8 @@ sub quotation_add_pkg {
   my($context, $session, $custnum) = _custoragent_session_custnum($p);
   return { 'error' => $session } if $context eq 'error';
   
-  my $quotation = _quotation($session);
+  my $quotation = _quotation($session, $p->{quotationnum})
+    or return { 'error' => "Quotation not found" };
   my $cust_main = $quotation->cust_main;
 
   my $pkgpart = $p->{'pkgpart'};
@@ -161,7 +253,8 @@ sub quotation_add_pkg {
   }
 
   my $error = $quotation_pkg->insert
-           || $quotation->estimate;
+           || $quotation->estimate
+           || '';
 
   { 'error'         => $error,
     'quotationnum'  => $quotation->quotationnum };
@@ -179,7 +272,8 @@ sub quotation_remove_pkg {
   my($context, $session, $custnum) = _custoragent_session_custnum($p);
   return { 'error' => $session } if $context eq 'error';
   
-  my $quotation = _quotation($session);
+  my $quotation = _quotation($session, $p->{quotationnum})
+    or return { 'error' => "Quotation not found" };
   my $quotationpkgnum = $p->{pkgnum};
   my $quotation_pkg = FS::quotation_pkg->by_key($quotationpkgnum);
   if (!$quotation_pkg
@@ -208,7 +302,8 @@ sub quotation_order {
   my($context, $session, $custnum) = _custoragent_session_custnum($p);
   return { 'error' => $session } if $context eq 'error';
   
-  my $quotation = _quotation($session);
+  my $quotation = _quotation($session, $p->{quotationnum})
+    or return { 'error' => "Quotation not found" };
 
   my $error = $quotation->order;
   $quotation->set('disabled' => 'Y');
diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm
index 5f1b38c..757f764 100644
--- a/FS/FS/ClientAPI_XMLRPC.pm
+++ b/FS/FS/ClientAPI_XMLRPC.pm
@@ -188,6 +188,9 @@ sub ss2clientapi {
   'call_time_nanpa'           => 'PrepaidPhone/call_time_nanpa',
   'phonenum_balance'          => 'PrepaidPhone/phonenum_balance',
 
+  'list_quotations'           => 'MyAccount/quotation/list_quotations',
+  'quotation_new'             => 'MyAccount/quotation/quotation_new',
+  'quotation_delete'          => 'MyAccount/quotation/quotation_delete',
   'quotation_info'            => 'MyAccount/quotation/quotation_info',
   'quotation_print'           => 'MyAccount/quotation/quotation_print',
   'quotation_add_pkg'         => 'MyAccount/quotation/quotation_add_pkg',
diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm
index 765d611..939596e 100644
--- a/fs_selfservice/FS-SelfService/SelfService.pm
+++ b/fs_selfservice/FS-SelfService/SelfService.pm
@@ -116,6 +116,9 @@ $socket .= '.'.$tag if defined $tag && length($tag);
   'start_thirdparty'          => 'MyAccount/start_thirdparty',
   'finish_thirdparty'         => 'MyAccount/finish_thirdparty',
 
+  'list_quotations'           => 'MyAccount/quotation/list_quotations',
+  'quotation_new'             => 'MyAccount/quotation/quotation_new',
+  'quotation_delete'          => 'MyAccount/quotation/quotation_delete',
   'quotation_info'            => 'MyAccount/quotation/quotation_info',
   'quotation_print'           => 'MyAccount/quotation/quotation_print',
   'quotation_add_pkg'         => 'MyAccount/quotation/quotation_add_pkg',
@@ -283,6 +286,31 @@ FS::SelfService - Freeside self-service API
                       }
                     );
 
+  #quoting a package, then ordering after confirmation
+
+  my $rv = quotation_new({ 'session_id' => $session_id });
+  my $qnum = $rv->{quotationnum};
+  #  add packages to the quotation
+  $rv = quotation_add_pkg({ 'session_id'   => $session_id,
+                            'quotationnum' => $qnum,
+                            'pkgpart'      => $pkgpart,
+                            'quantity'     => $quantity, # defaults to 1
+                          });
+  #  repeat until all packages are added
+  #  view the pricing information
+  $rv = quotation_info({ 'session_id'   => $session_id,
+                         'quotationnum' => $qnum,
+                      });
+  print "Total setup charges: ".$rv->{total_setup}."\n".
+        "Total recurring charges: ".$rv->{total_recur}."\n";
+  #  quotation_info also provides a detailed breakdown of charges, in
+  #  $rv->{sections}.
+
+  #  ask customer for confirmation, then:
+  $rv = quotation_order({ 'session_id'   => $session_id,
+                          'quotationnum' => $qnum,
+                        });
+
   #!!! cancel_pkg example
 
   # signup functionality
@@ -1283,6 +1311,147 @@ svcpart or service definition to provision
 
 =back
 
+=head2 "MY ACCOUNT" QUOTATION FUNCTIONS
+
+All of these functions require the user to be logged in, and the 'session_id'
+key to be included in the argument hashref.`
+
+=over 4
+
+=item list_quotations HASHREF
+
+Returns a hashref listing this customer's active self-service quotations.
+Contents are:
+
+- 'quotations', an arrayref containing an element for each quotation.
+  - quotationnum, the primary key
+  - _date, the date it was started
+  - num_pkgs, the number of packages
+  - total_setup, the sum of setup fees
+  - total_recur, the sum of recurring charges
+
+=item quotation_new HASHREF
+
+Creates an empty quotation and returns a hashref containing 'quotationnum',
+the primary key of the new quotation.
+
+=item quotation_delete HASHREF
+
+Disables (does not really delete) a quotation. Takes the following arguments:
+
+=over 4
+
+=item session_id
+
+=item quotationnum - the quotation to delete
+
+=back
+
+Returns 'error' => a string, which will be empty on success.
+
+=item quotation_info HASHREF
+
+Returns total and detailed pricing information on a quotation.
+
+Takes the following arguments:
+
+=over 4
+
+=item session_id
+
+=item quotationnum - the quotation to return
+
+=back
+
+Returns a hashref containing:
+
+- total_setup, the total of setup fees (and their taxes)
+- total_recur, the total of all recurring charges (and their taxes)
+- sections, an arrayref containing an element for each quotation section.
+  - description, a line of text describing the group of charges
+  - subtotal, the total of charges in this group (if appropriate)
+  - detail_items, an arrayref of line items
+    - pkgnum, the reference number of the package
+    - description, the package name (or tax name)
+    - quantity
+    - amount, the amount charged
+    If the detail item represents a subtotal, it will instead contain:
+    - total_item: description of the subtotal
+    - total_amount: the subtotal amount
+
+
+=item quotation_print HASHREF
+
+Renders the quotation as HTML or PDF. Takes the following arguments:
+
+=over 4
+
+=item session_id
+
+=item quotationnum - the quotation to return
+
+=item format - 'html' or 'pdf'
+
+=back
+
+Returns a hashref containing 'document', the contents of the file.
+
+=item quotation_add_pkg HASHREF
+
+Adds a package to a quotation. Takes the following arguments:
+
+=over 4
+
+=item session_id
+
+=item pkgpart - the package to add
+
+=item quotationnum - the quotation to add it to
+
+=item quantity - the package quantity (defaults to 1)
+
+=item address1, address2, city, state, zip, country - address fields to set
+the service location
+
+=back
+
+Returns 'error' => a string, which will be empty on success.
+
+=item quotation_remove_pkg HASHREF
+
+Removes a package from a quotation. Takes the following arguments:
+
+=over 4
+
+=item session_id
+
+=item pkgnum - the primary key (quotationpkgnum) of the package to remove
+
+=item quotationnum - the quotation to remove it from
+
+=back
+
+Returns 'error' => a string, which will be empty on success.
+
+=back
+
+=item quotation_order HASHREF
+
+Converts the packages in a quotation into real packages. Takes the following
+arguments:
+
+Takes the following arguments:
+
+=over 4
+
+=item session_id
+
+=item quotationnum - the quotation to order
+
+=back
+
+=back
+
 =head1 SIGNUP FUNCTIONS
 
 =over 4

commit d129179308646fb4eba078f1afe1fa2ddad51fbb
Author: Mark Wells <mark at freeside.biz>
Date:   Tue Apr 28 11:30:59 2015 -0700

    fix syntax errors

diff --git a/httemplate/view/cust_main/packages/section.html b/httemplate/view/cust_main/packages/section.html
index e38c34f..ce965c5 100755
--- a/httemplate/view/cust_main/packages/section.html
+++ b/httemplate/view/cust_main/packages/section.html
@@ -21,7 +21,7 @@
             no_services
         )),
         #for status.html
-        'has_cust_payby_auto' => $cust_main->has_cust_payby_auto,
+        'has_cust_payby_auto' => $opt{cust_main}->has_cust_payby_auto,
     &>
 %   }
 % } else { # there are no packages
diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html
index 3515b38..5dbffb2 100644
--- a/httemplate/view/cust_main/packages/status.html
+++ b/httemplate/view/cust_main/packages/status.html
@@ -495,7 +495,7 @@ sub pkg_status_row_detached {
 sub pkg_status_row_noauto {
   my( $cust_pkg, %opt ) = @_;
 
-  return '' unless ( $cust_pkg->no_auto || $opt{'part_pkg'}->no_auto );
+  return '' unless ( $cust_pkg->no_auto || $opt{'part_pkg'}->no_auto )
                 && $opt{'has_cust_payby_auto'};
 
   pkg_status_row_colspan( $cust_pkg, emt("No automatic charge"), '');

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/ClientAPI/MyAccount/quotation.pm          |  159 ++++++++++++++++-----
 FS/FS/ClientAPI_XMLRPC.pm                       |    3 +
 fs_selfservice/FS-SelfService/SelfService.pm    |  169 +++++++++++++++++++++++
 httemplate/view/cust_main/packages/section.html |    2 +-
 httemplate/view/cust_main/packages/status.html  |    2 +-
 5 files changed, 301 insertions(+), 34 deletions(-)




More information about the freeside-commits mailing list