[freeside-commits] branch FREESIDE_3_BRANCH updated. e2f23d0d3110ccff9dadf523d150a0d747130b43

Mark Wells mark at 420.am
Mon Apr 27 00:06:50 PDT 2015


The branch, FREESIDE_3_BRANCH has been updated
       via  e2f23d0d3110ccff9dadf523d150a0d747130b43 (commit)
       via  67c00bb4c9309c1ae314aa5b8657273f24539270 (commit)
       via  89776e0f215a6ccc42f49a3323bce87b26b5b221 (commit)
       via  37d0fe4165cbfaf57d82f3aff926508d565759f6 (commit)
       via  35fef4f60229db2bc540522cce1815d4a05ff283 (commit)
       via  89b934cfce5226556eb5f2ebb8377fb87d278a63 (commit)
       via  23d1a5787502e9e76338f6a7878b131f04741575 (commit)
      from  06cb92dc485e9f46de39307f971907bfdef119a3 (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 e2f23d0d3110ccff9dadf523d150a0d747130b43
Author: Mark Wells <mark at freeside.biz>
Date:   Mon Apr 27 00:04:37 2015 -0700

    disable quotation after ordering, #33852

diff --git a/FS/FS/ClientAPI/MyAccount/quotation.pm b/FS/FS/ClientAPI/MyAccount/quotation.pm
index f3067f1..f19071a 100644
--- a/FS/FS/ClientAPI/MyAccount/quotation.pm
+++ b/FS/FS/ClientAPI/MyAccount/quotation.pm
@@ -58,7 +58,6 @@ Returns a hashref describing the current quotation, containing:
 
 =cut
 
-use Data::Dumper;
 sub quotation_info {
   my $p = shift;
 
@@ -84,7 +83,6 @@ sub quotation_info {
       'detail_items' => \@items
     }
   ];
-  warn Dumper $sections;
 
   return { 'error' => '', 'sections' => $sections }
 }
@@ -225,6 +223,9 @@ sub quotation_order {
 
   my $error = $quotation->order;
 
+  $quotation->set('disabled' => 'Y');
+  $error ||= $quotation->replace;
+
   return { 'error' => $error };
 }
 

commit 67c00bb4c9309c1ae314aa5b8657273f24539270
Author: Mark Wells <mark at freeside.biz>
Date:   Sun Apr 26 23:58:08 2015 -0700

    adjustments for 3.x, #33852

diff --git a/FS/FS/ClientAPI/MyAccount/quotation.pm b/FS/FS/ClientAPI/MyAccount/quotation.pm
index 90c2ace..f3067f1 100644
--- a/FS/FS/ClientAPI/MyAccount/quotation.pm
+++ b/FS/FS/ClientAPI/MyAccount/quotation.pm
@@ -5,7 +5,7 @@ use FS::Record qw(qsearch qsearchs);
 use FS::quotation;
 use FS::quotation_pkg;
 
-our $DEBUG = 1;
+our $DEBUG = 0;
 
 sub _custoragent_session_custnum {
   FS::ClientAPI::MyAccount::_custoragent_session_custnum(@_);
@@ -58,6 +58,7 @@ Returns a hashref describing the current quotation, containing:
 
 =cut
 
+use Data::Dumper;
 sub quotation_info {
   my $p = shift;
 
@@ -69,13 +70,22 @@ sub quotation_info {
   warn "quotation_info #".$quotation->quotationnum
     if $DEBUG;
 
-  # code reuse ftw
   my $null_escape = sub { @_ };
-  my ($sections) = $quotation->_items_sections(escape => $null_escape);
-  foreach my $section (@$sections) {
-    $section->{'detail_items'} =
-      [ $quotation->_items_pkg('section' => $section, escape_function => $null_escape) ]; 
-  }
+  # 3.x only; 4.x quotation redesign uses actual sections for this
+  # and isn't a weird hack
+  my @items =
+    map { $_->{'pkgnum'} = $_->{'preref_html'}; $_ }
+    $quotation->_items_pkg(escape_function => $null_escape,
+                           preref_callback => sub { shift->quotationpkgnum });
+  push @items, $quotation->_items_total();
+
+  my $sections = [
+    { 'description' => 'Estimated Charges',
+      'detail_items' => \@items
+    }
+  ];
+  warn Dumper $sections;
+
   return { 'error' => '', 'sections' => $sections }
 }
 
diff --git a/ng_selfservice/quotation.php b/ng_selfservice/quotation.php
index cf45543..acccf9c 100644
--- a/ng_selfservice/quotation.php
+++ b/ng_selfservice/quotation.php
@@ -58,34 +58,46 @@ if ( isset($quotation['sections']) and count($quotation['sections']) > 0 ) {
     );
     $row = 0;
     foreach ( $section['detail_items'] as $detail ) {
-      print(
-        '<TR CLASS="row' . $row . '">'.
-        '<TD>'
-      );
-      if ( $detail['pkgnum'] ) {
+      if (isset($detail['description'])) {
+        print(
+          '<TR CLASS="row' . $row . '">'.
+          '<TD>'
+        );
+        if ( $detail['pkgnum'] ) {
+          print(
+            '<A HREF="quotation_remove_pkg.php?pkgnum=' .
+            $detail['pkgnum'] . '">'.
+            '<IMG SRC="images/cross.png" /></A>'
+          );
+        }
+        print(
+          '</TD>'.
+          '<TD>'. htmlspecialchars($detail['description']). '</TD>'.
+          '<TD CLASS="amount">'. $detail['amount']. '</TD>'.
+          '</TR>'. "\n"
+        );
+        $row = 1 - $row;
+      } else {
+        # total rows; a 3.x-ism
         print(
-          '<A HREF="quotation_remove_pkg.php?pkgnum=' .
-          $detail['pkgnum'] . '">'.
-          '<IMG SRC="images/cross.png" /></A>'
+          '<TR CLASS="total">'.
+          '<TD></TD>'.
+          '<TD>'. htmlspecialchars($detail['total_item']). '</TD>'.
+          '<TD CLASS="amount">'. $detail['total_amount']. '</TD>'.
+          '</TR>'."\n"
         );
       }
+    }
+    if (isset($section['subtotal'])) {
       print(
-        '</TD>'.
-        '<TD>'. htmlspecialchars($detail['description']). '</TD>'.
-        '<TD CLASS="amount">'. $detail['amount']. '</TD>'.
-        '</TR>'. "\n"
+        '<TR CLASS="total">'.
+        '<TD></TD>'.
+        '<TD>Total</TD>'.
+        '<TD CLASS="amount">'. $section['subtotal']. '</TD>'.
+        '</TR>'
       );
-      $row = 1 - $row;
     }
-    print(
-      '<TR CLASS="total">'.
-      '<TD></TD>'.
-      '<TD>Total</TD>'.
-      '<TD CLASS="amount">'. $section['subtotal']. '</TD>'.
-      '</TR>'.
-      '</TABLE>'.
-      "\n"
-    );
+    print "</TABLE>\n";
   } # foreach $section
 }
 

commit 89776e0f215a6ccc42f49a3323bce87b26b5b221
Author: Mark Wells <mark at freeside.biz>
Date:   Sun Apr 26 23:58:01 2015 -0700

    missing file

diff --git a/ng_selfservice/images/cross.png b/ng_selfservice/images/cross.png
index e69de29..1514d51 100644
Binary files a/ng_selfservice/images/cross.png and b/ng_selfservice/images/cross.png differ

commit 37d0fe4165cbfaf57d82f3aff926508d565759f6
Author: Mark Wells <mark at freeside.biz>
Date:   Sun Apr 26 23:26:50 2015 -0700

    allow all legal packages to be chosen in selfservice quotations

diff --git a/FS/FS/ClientAPI/MyAccount/quotation.pm b/FS/FS/ClientAPI/MyAccount/quotation.pm
index ce2debd..90c2ace 100644
--- a/FS/FS/ClientAPI/MyAccount/quotation.pm
+++ b/FS/FS/ClientAPI/MyAccount/quotation.pm
@@ -136,7 +136,10 @@ sub quotation_add_pkg {
 
   my $part_pkg = FS::part_pkg->by_key($pkgpart);
 
-  if (!$part_pkg or !$allowed_pkgpart->{$pkgpart}) {
+  if (!$part_pkg or
+      (!$allowed_pkgpart->{$pkgpart} and 
+       $cust_main->agentnum != ($part_pkg->agentnum || 0))
+  ) {
     warn "disallowed quotation_pkg pkgpart $pkgpart\n"
       if $DEBUG;
     return { 'error' => "unknown package $pkgpart" };

commit 35fef4f60229db2bc540522cce1815d4a05ff283
Author: Mark Wells <mark at freeside.biz>
Date:   Sun Apr 26 13:54:25 2015 -0700

    cleanup

diff --git a/ng_selfservice/.freeside.class.php.swp b/ng_selfservice/.freeside.class.php.swp
deleted file mode 100644
index 5c39524..0000000
Binary files a/ng_selfservice/.freeside.class.php.swp and /dev/null differ
diff --git a/ng_selfservice/.index.php.swp b/ng_selfservice/.index.php.swp
deleted file mode 100644
index 50c9cfb..0000000
Binary files a/ng_selfservice/.index.php.swp and /dev/null differ
diff --git a/ng_selfservice/.logout.php.swp b/ng_selfservice/.logout.php.swp
deleted file mode 100644
index ec27faa..0000000
Binary files a/ng_selfservice/.logout.php.swp and /dev/null differ
diff --git a/ng_selfservice/.main.php.swp b/ng_selfservice/.main.php.swp
deleted file mode 100644
index cc55626..0000000
Binary files a/ng_selfservice/.main.php.swp and /dev/null differ
diff --git a/ng_selfservice/.password.php.swp b/ng_selfservice/.password.php.swp
deleted file mode 100644
index e1e968f..0000000
Binary files a/ng_selfservice/.password.php.swp and /dev/null differ
diff --git a/ng_selfservice/.payment.php.swp b/ng_selfservice/.payment.php.swp
deleted file mode 100644
index 2b705a3..0000000
Binary files a/ng_selfservice/.payment.php.swp and /dev/null differ
diff --git a/ng_selfservice/.payment_ach.php.swp b/ng_selfservice/.payment_ach.php.swp
deleted file mode 100644
index 1a87a2d..0000000
Binary files a/ng_selfservice/.payment_ach.php.swp and /dev/null differ
diff --git a/ng_selfservice/.payment_cc.php.swp b/ng_selfservice/.payment_cc.php.swp
deleted file mode 100644
index 369d104..0000000
Binary files a/ng_selfservice/.payment_cc.php.swp and /dev/null differ
diff --git a/ng_selfservice/.payment_paypal.php.swp b/ng_selfservice/.payment_paypal.php.swp
deleted file mode 100644
index 3abff2f..0000000
Binary files a/ng_selfservice/.payment_paypal.php.swp and /dev/null differ
diff --git a/ng_selfservice/.payment_webpay.php.swp b/ng_selfservice/.payment_webpay.php.swp
deleted file mode 100644
index 6ef3df9..0000000
Binary files a/ng_selfservice/.payment_webpay.php.swp and /dev/null differ
diff --git a/ng_selfservice/.personal.php.swp b/ng_selfservice/.personal.php.swp
deleted file mode 100644
index f5e8c23..0000000
Binary files a/ng_selfservice/.personal.php.swp and /dev/null differ
diff --git a/ng_selfservice/.process_login.php.swp b/ng_selfservice/.process_login.php.swp
deleted file mode 100644
index c530f11..0000000
Binary files a/ng_selfservice/.process_login.php.swp and /dev/null differ
diff --git a/ng_selfservice/.process_ticket_create.php.swp b/ng_selfservice/.process_ticket_create.php.swp
deleted file mode 100644
index c286792..0000000
Binary files a/ng_selfservice/.process_ticket_create.php.swp and /dev/null differ
diff --git a/ng_selfservice/.services.php.swp b/ng_selfservice/.services.php.swp
deleted file mode 100644
index e063e40..0000000
Binary files a/ng_selfservice/.services.php.swp and /dev/null differ
diff --git a/ng_selfservice/.services_new.php.swp b/ng_selfservice/.services_new.php.swp
deleted file mode 100644
index 8d0c657..0000000
Binary files a/ng_selfservice/.services_new.php.swp and /dev/null differ
diff --git a/ng_selfservice/.ticket.php.swp b/ng_selfservice/.ticket.php.swp
deleted file mode 100644
index e9b2503..0000000
Binary files a/ng_selfservice/.ticket.php.swp and /dev/null differ
diff --git a/ng_selfservice/.ticket_create.php.swp b/ng_selfservice/.ticket_create.php.swp
deleted file mode 100644
index 65b00fe..0000000
Binary files a/ng_selfservice/.ticket_create.php.swp and /dev/null differ
diff --git a/ng_selfservice/.tickets.php.swp b/ng_selfservice/.tickets.php.swp
deleted file mode 100644
index 7b4d67b..0000000
Binary files a/ng_selfservice/.tickets.php.swp and /dev/null differ
diff --git a/ng_selfservice/.tickets_resolved.php.swp b/ng_selfservice/.tickets_resolved.php.swp
deleted file mode 100644
index 1b3c634..0000000
Binary files a/ng_selfservice/.tickets_resolved.php.swp and /dev/null differ
diff --git a/ng_selfservice/.usage.php.swp b/ng_selfservice/.usage.php.swp
deleted file mode 100644
index 61fd4fa..0000000
Binary files a/ng_selfservice/.usage.php.swp and /dev/null differ
diff --git a/ng_selfservice/.usage_cdr.php.swp b/ng_selfservice/.usage_cdr.php.swp
deleted file mode 100644
index 83c270a..0000000
Binary files a/ng_selfservice/.usage_cdr.php.swp and /dev/null differ
diff --git a/ng_selfservice/.usage_data.php.swp b/ng_selfservice/.usage_data.php.swp
deleted file mode 100644
index e5a9272..0000000
Binary files a/ng_selfservice/.usage_data.php.swp and /dev/null differ

commit 89b934cfce5226556eb5f2ebb8377fb87d278a63
Author: Mark Wells <mark at freeside.biz>
Date:   Sun Apr 26 13:52:36 2015 -0700

    selfservice quotations, #33852

diff --git a/FS/FS/ClientAPI/MasonComponent.pm b/FS/FS/ClientAPI/MasonComponent.pm
index 695b4ca..b6f8aa4 100644
--- a/FS/FS/ClientAPI/MasonComponent.pm
+++ b/FS/FS/ClientAPI/MasonComponent.pm
@@ -27,6 +27,7 @@ my %allowed_comps = map { $_=>1 } qw(
 my %session_comps = map { $_=>1 } qw(
   /elements/location.html
   /elements/tr-amount_fee.html
+  /elements/select-part_pkg.html
   /edit/cust_main/first_pkg/select-part_pkg.html
 );
 
@@ -106,6 +107,26 @@ my %session_callbacks = (
 
   },
 
+  '/elements/select-part_pkg.html' => sub {
+    my( $custnum, $argsref ) = @_;
+    my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+      or return "unknown custnum $custnum";
+
+    my $pkgpart = $cust_main->agent->pkgpart_hashref;
+
+    #false laziness w/ edit/cust_main/first_pkg.html
+    my @first_svc = ( 'svc_acct', 'svc_phone' );
+
+    my @part_pkg =
+      grep { $pkgpart->{ $_->pkgpart } 
+                  || ( $_->agentnum && $_->agentnum == $cust_main->agentnum )
+           }
+      qsearch( 'part_pkg', { 'disabled' => '' }, '', 'ORDER BY pkg' ); # case?
+
+    push @$argsref, 'part_pkg' =>  \@part_pkg;
+    '';
+  },
+
 );
 
 my $outbuf;
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index 751af3f..d05abde 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -48,6 +48,8 @@ use FS::msg_template;
 use FS::contact;
 use FS::cust_location;
 
+use FS::ClientAPI::MyAccount::quotation; # just for code organization
+
 $DEBUG = 0;
 $me = '[FS::ClientAPI::MyAccount]';
 
diff --git a/FS/FS/ClientAPI/MyAccount/quotation.pm b/FS/FS/ClientAPI/MyAccount/quotation.pm
new file mode 100644
index 0000000..ce2debd
--- /dev/null
+++ b/FS/FS/ClientAPI/MyAccount/quotation.pm
@@ -0,0 +1,218 @@
+package FS::ClientAPI::MyAccount::quotation;
+
+use strict;
+use FS::Record qw(qsearch qsearchs);
+use FS::quotation;
+use FS::quotation_pkg;
+
+our $DEBUG = 1;
+
+sub _custoragent_session_custnum {
+  FS::ClientAPI::MyAccount::_custoragent_session_custnum(@_);
+}
+
+sub _quotation {
+  # the currently active quotation
+  my $session = shift;
+  my $quotation;
+  if ( my $quotationnum = $session->{'quotationnum'} ) {
+    $quotation = FS::quotation->by_key($quotationnum);
+  } 
+  if ( !$quotation ) {
+    # find the last quotation created through selfservice
+    $quotation = qsearchs( 'quotation', {
+        'custnum'   => $session->{'custnum'},
+        'usernum'   => $FS::CurrentUser::CurrentUser->usernum,
+        'disabled'  => '',
+    }); 
+    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"
+      if $quotation and $DEBUG;
+  } 
+  $session->{'quotationnum'} = $quotation->quotationnum;
+  return $quotation;
+}
+
+=item quotation_info { session }
+
+Returns a hashref describing the current quotation, containing:
+
+- "sections", an arrayref containing one section for each billing frequency.
+  Each one will have:
+  - "description"
+  - "subtotal"
+  - "detail_items", an arrayref of detail items, each with:
+    - "pkgnum", the reference number (actually the quotationpkgnum field)
+    - "description", the package name (or tax name)
+    - "quantity"
+    - "amount"
+
+=cut
+
+sub quotation_info {
+  my $p = shift;
+
+  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;
+  warn "quotation_info #".$quotation->quotationnum
+    if $DEBUG;
+
+  # code reuse ftw
+  my $null_escape = sub { @_ };
+  my ($sections) = $quotation->_items_sections(escape => $null_escape);
+  foreach my $section (@$sections) {
+    $section->{'detail_items'} =
+      [ $quotation->_items_pkg('section' => $section, escape_function => $null_escape) ]; 
+  }
+  return { 'error' => '', 'sections' => $sections }
+}
+
+=item quotation_print { session, 'format' }
+
+Renders the quotation. 'format' can be either 'html' or 'pdf'; the resulting
+hashref will contain 'document' => the HTML or PDF contents.
+
+=cut
+
+sub quotation_print {
+  my $p = shift;
+
+  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;
+  warn "quotation_print #".$quotation->quotationnum
+    if $DEBUG;
+
+  my $format = $p->{'format'}
+   or return { 'error' => "No rendering format specified" };
+
+  my $document;
+  if ($format eq 'html') {
+    $document = $quotation->print_html;
+  } elsif ($format eq 'pdf') {
+    $document = $quotation->print_pdf;
+  }
+  warn "$format, ".length($document)." bytes\n"
+    if $DEBUG;
+  return { 'error' => '', 'document' => $document };
+}
+
+=item quotation_add_pkg { session, 'pkgpart', 'quantity', [ location opts ] }
+
+Adds a package to the user's current quotation. Session info and 'pkgpart' are
+required. 'quantity' defaults to 1.
+
+Location can be specified as 'locationnum' to use an existing location, or
+'address1', 'address2', 'city', 'state', 'zip', 'country' to create a new one,
+or it will default to the customer's service location.
+
+=cut
+
+sub quotation_add_pkg {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+  
+  my $quotation = _quotation($session);
+  my $cust_main = $quotation->cust_main;
+
+  my $pkgpart = $p->{'pkgpart'};
+  my $allowed_pkgpart = $cust_main->agent->pkgpart_hashref;
+
+  my $part_pkg = FS::part_pkg->by_key($pkgpart);
+
+  if (!$part_pkg or !$allowed_pkgpart->{$pkgpart}) {
+    warn "disallowed quotation_pkg pkgpart $pkgpart\n"
+      if $DEBUG;
+    return { 'error' => "unknown package $pkgpart" };
+  }
+
+  warn "creating quotation_pkg with pkgpart $pkgpart\n"
+    if $DEBUG;
+  my $quotation_pkg = FS::quotation_pkg->new({
+    'quotationnum'  => $quotation->quotationnum,
+    'pkgpart'       => $p->{'pkgpart'},
+    'quantity'      => $p->{'quantity'} || 1,
+  });
+  if ( $p->{locationnum} > 0 ) {
+    $quotation_pkg->set('locationnum', $p->{locationnum});
+  } elsif ( $p->{address1} ) {
+    my $location = FS::cust_location->find_or_insert(
+      'custnum' => $cust_main->custnum,
+      map { $_ => $p->{$_} }
+        qw( address1 address2 city county state zip country )
+    );
+    $quotation_pkg->set('locationnum', $location->locationnum);
+  }
+
+  my $error = $quotation_pkg->insert
+           || $quotation->estimate;
+
+  { 'error'         => $error,
+    'quotationnum'  => $quotation->quotationnum };
+}
+ 
+=item quotation_remove_pkg { session, 'pkgnum' }
+
+Removes the package from the user's current quotation. 'pkgnum' is required.
+
+=cut
+
+sub quotation_remove_pkg {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+  
+  my $quotation = _quotation($session);
+  my $quotationpkgnum = $p->{pkgnum};
+  my $quotation_pkg = FS::quotation_pkg->by_key($quotationpkgnum);
+  if (!$quotation_pkg
+      or $quotation_pkg->quotationnum != $quotation->quotationnum) {
+    return { 'error' => "unknown quotation item $quotationpkgnum" };
+  }
+  warn "removing quotation_pkg with pkgpart ".$quotation_pkg->pkgpart."\n"
+    if $DEBUG;
+
+  my $error = $quotation_pkg->delete
+           || $quotation->estimate;
+
+  { 'error'         => $error,
+    'quotationnum'  => $quotation->quotationnum };
+}
+
+=item quotation_order
+
+Convert the current quotation to a package order.
+
+=cut
+
+sub quotation_order {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+  
+  my $quotation = _quotation($session);
+
+  my $error = $quotation->order;
+
+  return { 'error' => $error };
+}
+
+1;
diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm
index 6ebdcec..960a1bd 100644
--- a/FS/FS/ClientAPI_XMLRPC.pm
+++ b/FS/FS/ClientAPI_XMLRPC.pm
@@ -52,6 +52,7 @@ our %typefix = (
   'login_info'         => \%typefix_skin_info,
   'invoice_logo'       => { 'logo' => 'base64', },
   'login_banner_image' => { 'image' => 'base64', },
+  'quotation_print'    => { 'document' => 'base64' },
 );
 
 sub AUTOLOAD {
@@ -185,6 +186,12 @@ sub ss2clientapi {
   'call_time'                 => 'PrepaidPhone/call_time',
   'call_time_nanpa'           => 'PrepaidPhone/call_time_nanpa',
   'phonenum_balance'          => 'PrepaidPhone/phonenum_balance',
+
+  'quotation_info'            => 'MyAccount/quotation/quotation_info',
+  'quotation_print'           => 'MyAccount/quotation/quotation_print',
+  'quotation_add_pkg'         => 'MyAccount/quotation/quotation_add_pkg',
+  'quotation_remove_pkg'      => 'MyAccount/quotation/quotation_remove_pkg',
+  'quotation_order'           => 'MyAccount/quotation/quotation_order',
   };
 }
 
diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm
index 36d7fb6..c20808e 100644
--- a/fs_selfservice/FS-SelfService/SelfService.pm
+++ b/fs_selfservice/FS-SelfService/SelfService.pm
@@ -114,6 +114,13 @@ $socket .= '.'.$tag if defined $tag && length($tag);
 
   'start_thirdparty'          => 'MyAccount/start_thirdparty',
   'finish_thirdparty'         => 'MyAccount/finish_thirdparty',
+
+  'quotation_info'            => 'MyAccount/quotation/quotation_info',
+  'quotation_print'           => 'MyAccount/quotation/quotation_print',
+  'quotation_add_pkg'         => 'MyAccount/quotation/quotation_add_pkg',
+  'quotation_remove_pkg'      => 'MyAccount/quotation/quotation_remove_pkg',
+  'quotation_order'           => 'MyAccount/quotation/quotation_order',
+
 );
 @EXPORT_OK = (
   keys(%autoload),
diff --git a/ng_selfservice/images/cross.png b/ng_selfservice/images/cross.png
new file mode 100644
index 0000000..e69de29
diff --git a/ng_selfservice/quotation.php b/ng_selfservice/quotation.php
new file mode 100644
index 0000000..cf45543
--- /dev/null
+++ b/ng_selfservice/quotation.php
@@ -0,0 +1,130 @@
+<STYLE>
+td.amount {
+    text-align: right;
+}
+td.amount:before {
+    content: "$";
+}
+tr.total * {
+    background-color: #ddf;
+    font-weight: bold;
+}
+table.section {
+    width: 100%;
+    border-collapse: collapse;
+}
+table.section td {
+    font-size: small;
+    padding: 1ex 1ex;
+}
+table.section th {
+    text-align: left;
+    padding: 1ex;
+}
+.row0 td {
+    background-color: #eee;
+}
+.row1 td {
+    background-color: #fff;
+}
+</STYLE>
+
+<? $title ='Plan a new service order'; include('elements/header.php'); ?>
+<? $current_menu = 'services_new.php'; include('elements/menu.php'); ?>
+<?
+
+$quotation = $freeside->quotation_info(array(
+  'session_id'  => $_COOKIE['session_id'],
+));
+
+$can_order = 0;
+
+if ( isset($quotation['sections']) and count($quotation['sections']) > 0 ) {
+  $can_order = 1;
+  # there are other ways this could be formatted, yes.
+  # if you want the HTML-formatted quotation, use quotation_print().
+  print(
+    '<INPUT STYLE="float: right" TYPE="button" onclick="window.location.href=\'quotation_print.php\'" value="Download a quotation" />'.
+    '<H3>Order summary</H3>'.
+    "\n"
+  );
+  foreach ( $quotation['sections'] as $section ) {
+    print(
+      '<TABLE CLASS="section">'.
+      '<TR>'.
+      '<TH COLSPAN=4>'.  htmlspecialchars($section['description']).'</TH>'.
+      '</TR>'.
+      "\n"
+    );
+    $row = 0;
+    foreach ( $section['detail_items'] as $detail ) {
+      print(
+        '<TR CLASS="row' . $row . '">'.
+        '<TD>'
+      );
+      if ( $detail['pkgnum'] ) {
+        print(
+          '<A HREF="quotation_remove_pkg.php?pkgnum=' .
+          $detail['pkgnum'] . '">'.
+          '<IMG SRC="images/cross.png" /></A>'
+        );
+      }
+      print(
+        '</TD>'.
+        '<TD>'. htmlspecialchars($detail['description']). '</TD>'.
+        '<TD CLASS="amount">'. $detail['amount']. '</TD>'.
+        '</TR>'. "\n"
+      );
+      $row = 1 - $row;
+    }
+    print(
+      '<TR CLASS="total">'.
+      '<TD></TD>'.
+      '<TD>Total</TD>'.
+      '<TD CLASS="amount">'. $section['subtotal']. '</TD>'.
+      '</TR>'.
+      '</TABLE>'.
+      "\n"
+    );
+  } # foreach $section
+}
+
+$pkgselect = $freeside->mason_comp( array(
+    'session_id' => $_COOKIE['session_id'],
+    'comp'       => '/elements/select-part_pkg.html',
+    'args'       => array( 'onchange'       , 'enable_order_pkg()',
+                           'empty_label'    , 'Select package',
+                           'form_name'      , 'AddPkgForm',
+                         ),
+));
+if ( isset($pkgselect['error']) && $pkgselect['error'] ) {
+  $error = $pkgselect['error'];
+  header('Location:index.php?error='. urlencode($pkgselect));
+  die();
+}
+
+?>
+<SCRIPT TYPE="text/javascript">
+function enable_order_pkg () {
+    document.AddPkgForm.submit.disabled =
+        (document.AddPkgForm.pkgpart.value == '');
+}
+</SCRIPT>
+
+<DIV STYLE="border-top: 1px solid; padding: 1ex">
+<? $error = $_REQUEST['error']; include('elements/error.php'); ?>
+
+<FORM NAME="AddPkgForm" ACTION="quotation_add_pkg.php" METHOD=POST>
+<? echo $pkgselect['output']; ?>
+<INPUT NAME="submit" TYPE="submit" VALUE="Add package" <? if ( ! isset($_REQUEST['pkgpart']) ) { echo 'DISABLED'; } ?>>
+</FORM>
+
+<? if ( $can_order ) { ?>
+<FORM NAME="OrderQuoteForm" ACTION="quotation_order.php" METHOD=POST>
+<INPUT TYPE="submit" VALUE="Confirm this order" <? if ( !$can_order ) { echo 'DISABLED'; } ?>>
+<? } ?>
+
+</DIV>
+
+<? include('elements/menu_footer.php'); ?>
+<? include('elements/footer.php'); ?>
diff --git a/ng_selfservice/quotation_add_pkg.php b/ng_selfservice/quotation_add_pkg.php
new file mode 100644
index 0000000..1e7e71f
--- /dev/null
+++ b/ng_selfservice/quotation_add_pkg.php
@@ -0,0 +1,31 @@
+<? require('elements/session.php');
+
+$dest = 'quotation.php';
+
+if ( isset($_REQUEST['pkgpart']) ) {
+
+  $results = array();
+
+  $params = array( 'custnum', 'pkgpart' );
+
+  $matches = array();
+  if ( preg_match( '/^(\d+)$/', $_REQUEST['pkgpart'] ) ) {
+
+    $args = array(
+        'session_id' => $_COOKIE['session_id'],
+        'pkgpart'    => $_REQUEST['pkgpart'],
+    );
+
+    $results = $freeside->quotation_add_pkg($args);
+
+  }
+
+  if ( isset($results['error']) && $results['error'] ) {
+    $dest .= '?error=' . $results['error'] . ';pkgpart=' . $_REQUEST['pkgpart'];
+  }
+}
+
+header("Location:$dest");
+
+?>
+
diff --git a/ng_selfservice/quotation_order.php b/ng_selfservice/quotation_order.php
new file mode 100644
index 0000000..d35eacb
--- /dev/null
+++ b/ng_selfservice/quotation_order.php
@@ -0,0 +1,15 @@
+<? require('elements/session.php');
+
+$dest = 'services.php';
+
+$args = array( 'session_id' => $_COOKIE['session_id'] );
+
+$results = $freeside->quotation_order($args);
+
+if ( isset($results['error']) && $results['error'] ) {
+    $dest = 'quotation.php?error=' . $results['error'];
+}
+
+header("Location:$dest");
+
+?>
diff --git a/ng_selfservice/quotation_print.php b/ng_selfservice/quotation_print.php
new file mode 100644
index 0000000..9676405
--- /dev/null
+++ b/ng_selfservice/quotation_print.php
@@ -0,0 +1,17 @@
+<? require('elements/session.php');
+
+$args = array(
+    'session_id' => $_COOKIE['session_id'],
+    'format'     => 'pdf'
+);
+
+$results = $freeside->quotation_print($args);
+if ( isset($results['document']) ) {
+    header('Content-Type: application/pdf');
+    header('Content-Disposition: filename=quotation.pdf');
+    print($results['document']->scalar);
+} else {
+    header("Location: quotation.php?error=" . $results['error']);
+}
+
+?>
diff --git a/ng_selfservice/quotation_remove_pkg.php b/ng_selfservice/quotation_remove_pkg.php
new file mode 100644
index 0000000..07548c7
--- /dev/null
+++ b/ng_selfservice/quotation_remove_pkg.php
@@ -0,0 +1,31 @@
+<? require('elements/session.php');
+
+$dest = 'quotation.php';
+
+if ( isset($_REQUEST['pkgnum']) ) {
+
+  $results = array();
+
+  $params = array( 'custnum', 'pkgnum' );
+
+  $matches = array();
+  if ( preg_match( '/^(\d+)$/', $_REQUEST['pkgnum'] ) ) {
+
+    $args = array(
+        'session_id' => $_COOKIE['session_id'],
+        'pkgnum'     => $_REQUEST['pkgnum'],
+    );
+
+    $results = $freeside->quotation_remove_pkg($args);
+
+  }
+
+  if ( isset($results['error']) && $results['error'] ) {
+    $dest .= '?error=' . $results['error'];
+  }
+
+}
+
+header("Location:$dest");
+
+?>

commit 23d1a5787502e9e76338f6a7878b131f04741575
Author: Mark Wells <mark at freeside.biz>
Date:   Sun Apr 26 13:38:53 2015 -0700

    fix bad commit?

diff --git a/ng_selfservice/process_login.php b/ng_selfservice/process_login.php
index ac03d0f..4212a26 100644
--- a/ng_selfservice/process_login.php
+++ b/ng_selfservice/process_login.php
@@ -4,7 +4,8 @@ require('freeside.class.php');
 $freeside = new FreesideSelfService();
 
 $response = $freeside->login( array(
-+  'email'    => strtolower($_POST['email']),                                     'username' => strtolower($_POST['username']),
+  'email'    => strtolower($_POST['email']),
+  'username' => strtolower($_POST['username']),
   'domain'   => strtolower($_POST['domain']),
   'password' => $_POST['password'],
 ) );

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

Summary of changes:
 FS/FS/ClientAPI/MasonComponent.pm                  |   21 ++
 FS/FS/ClientAPI/MyAccount.pm                       |    2 +
 FS/FS/ClientAPI/MyAccount/quotation.pm             |  232 ++++++++++++++++++++
 FS/FS/ClientAPI_XMLRPC.pm                          |    7 +
 fs_selfservice/FS-SelfService/SelfService.pm       |    7 +
 ng_selfservice/.freeside.class.php.swp             |  Bin 12288 -> 0 bytes
 ng_selfservice/.index.php.swp                      |  Bin 12288 -> 0 bytes
 ng_selfservice/.logout.php.swp                     |  Bin 12288 -> 0 bytes
 ng_selfservice/.main.php.swp                       |  Bin 12288 -> 0 bytes
 ng_selfservice/.password.php.swp                   |  Bin 12288 -> 0 bytes
 ng_selfservice/.payment.php.swp                    |  Bin 12288 -> 0 bytes
 ng_selfservice/.payment_ach.php.swp                |  Bin 12288 -> 0 bytes
 ng_selfservice/.payment_cc.php.swp                 |  Bin 12288 -> 0 bytes
 ng_selfservice/.payment_paypal.php.swp             |  Bin 12288 -> 0 bytes
 ng_selfservice/.payment_webpay.php.swp             |  Bin 12288 -> 0 bytes
 ng_selfservice/.personal.php.swp                   |  Bin 12288 -> 0 bytes
 ng_selfservice/.process_login.php.swp              |  Bin 12288 -> 0 bytes
 ng_selfservice/.process_ticket_create.php.swp      |  Bin 12288 -> 0 bytes
 ng_selfservice/.services.php.swp                   |  Bin 12288 -> 0 bytes
 ng_selfservice/.services_new.php.swp               |  Bin 20480 -> 0 bytes
 ng_selfservice/.ticket.php.swp                     |  Bin 12288 -> 0 bytes
 ng_selfservice/.ticket_create.php.swp              |  Bin 12288 -> 0 bytes
 ng_selfservice/.tickets.php.swp                    |  Bin 12288 -> 0 bytes
 ng_selfservice/.tickets_resolved.php.swp           |  Bin 12288 -> 0 bytes
 ng_selfservice/.usage.php.swp                      |  Bin 12288 -> 0 bytes
 ng_selfservice/.usage_cdr.php.swp                  |  Bin 12288 -> 0 bytes
 ng_selfservice/.usage_data.php.swp                 |  Bin 12288 -> 0 bytes
 .../cgi => ng_selfservice}/images/cross.png        |  Bin 655 -> 655 bytes
 ng_selfservice/process_login.php                   |    3 +-
 ng_selfservice/quotation.php                       |  142 ++++++++++++
 ng_selfservice/quotation_add_pkg.php               |   31 +++
 ng_selfservice/quotation_order.php                 |   15 ++
 ng_selfservice/quotation_print.php                 |   17 ++
 ng_selfservice/quotation_remove_pkg.php            |   31 +++
 34 files changed, 507 insertions(+), 1 deletion(-)
 create mode 100644 FS/FS/ClientAPI/MyAccount/quotation.pm
 delete mode 100644 ng_selfservice/.freeside.class.php.swp
 delete mode 100644 ng_selfservice/.index.php.swp
 delete mode 100644 ng_selfservice/.logout.php.swp
 delete mode 100644 ng_selfservice/.main.php.swp
 delete mode 100644 ng_selfservice/.password.php.swp
 delete mode 100644 ng_selfservice/.payment.php.swp
 delete mode 100644 ng_selfservice/.payment_ach.php.swp
 delete mode 100644 ng_selfservice/.payment_cc.php.swp
 delete mode 100644 ng_selfservice/.payment_paypal.php.swp
 delete mode 100644 ng_selfservice/.payment_webpay.php.swp
 delete mode 100644 ng_selfservice/.personal.php.swp
 delete mode 100644 ng_selfservice/.process_login.php.swp
 delete mode 100644 ng_selfservice/.process_ticket_create.php.swp
 delete mode 100644 ng_selfservice/.services.php.swp
 delete mode 100644 ng_selfservice/.services_new.php.swp
 delete mode 100644 ng_selfservice/.ticket.php.swp
 delete mode 100644 ng_selfservice/.ticket_create.php.swp
 delete mode 100644 ng_selfservice/.tickets.php.swp
 delete mode 100644 ng_selfservice/.tickets_resolved.php.swp
 delete mode 100644 ng_selfservice/.usage.php.swp
 delete mode 100644 ng_selfservice/.usage_cdr.php.swp
 delete mode 100644 ng_selfservice/.usage_data.php.swp
 copy {fs_selfservice/FS-SelfService/cgi => ng_selfservice}/images/cross.png (100%)
 create mode 100644 ng_selfservice/quotation.php
 create mode 100644 ng_selfservice/quotation_add_pkg.php
 create mode 100644 ng_selfservice/quotation_order.php
 create mode 100644 ng_selfservice/quotation_print.php
 create mode 100644 ng_selfservice/quotation_remove_pkg.php




More information about the freeside-commits mailing list