[freeside-commits] branch FREESIDE_3_BRANCH updated. a8b3b00457aba6ac267ad74e8a130fb5173c66b0

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


The branch, FREESIDE_3_BRANCH has been updated
       via  a8b3b00457aba6ac267ad74e8a130fb5173c66b0 (commit)
      from  f23f9340aeaa5e128d4319a9e824dfe94f1e1a3a (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 a8b3b00457aba6ac267ad74e8a130fb5173c66b0
Author: Mark Wells <mark at freeside.biz>
Date:   Tue Apr 28 11:47:13 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 f19071a..6c2b702 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;
 
@@ -84,7 +170,12 @@ sub quotation_info {
     }
   ];
 
-  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' }
@@ -100,8 +191,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;
 
@@ -136,7 +227,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'};
@@ -172,7 +264,8 @@ sub quotation_add_pkg {
   }
 
   my $error = $quotation_pkg->insert
-           || $quotation->estimate;
+           || $quotation->estimate
+           || '';
 
   { 'error'         => $error,
     'quotationnum'  => $quotation->quotationnum };
@@ -190,7 +283,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
@@ -219,7 +313,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;
 
diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm
index 960a1bd..7d97f3a 100644
--- a/FS/FS/ClientAPI_XMLRPC.pm
+++ b/FS/FS/ClientAPI_XMLRPC.pm
@@ -187,6 +187,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 c20808e..7cc7c03 100644
--- a/fs_selfservice/FS-SelfService/SelfService.pm
+++ b/fs_selfservice/FS-SelfService/SelfService.pm
@@ -115,6 +115,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',
@@ -259,6 +262,31 @@ FS::SelfService - Freeside self-service API
 
   #!!! order_pkg example
 
+  #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
@@ -1259,6 +1287,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

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

Summary of changes:
 FS/FS/ClientAPI/MyAccount/quotation.pm       |  159 +++++++++++++++++++-----
 FS/FS/ClientAPI_XMLRPC.pm                    |    3 +
 fs_selfservice/FS-SelfService/SelfService.pm |  169 ++++++++++++++++++++++++++
 3 files changed, 299 insertions(+), 32 deletions(-)




More information about the freeside-commits mailing list