[freeside-commits] branch FREESIDE_3_BRANCH updated. d5461ef7f534030b662ce5c6ee81eafd5f18cbec

Jonathan Prykop jonathan at 420.am
Wed Aug 31 20:33:35 PDT 2016


The branch, FREESIDE_3_BRANCH has been updated
       via  d5461ef7f534030b662ce5c6ee81eafd5f18cbec (commit)
       via  259777e4667fc8a45496ba2805d1f7e01c75ac7b (commit)
       via  f61619b95f05b576518ea698ad7e22267b4c36c4 (commit)
      from  b8a0fbd814bd8e1ba3a8b8c58c5f162af8dc9f00 (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 d5461ef7f534030b662ce5c6ee81eafd5f18cbec
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Wed Aug 31 21:49:04 2016 -0500

    71890: SelfService API: Return monthly recurring fee

diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index 630346a..23fbf6c 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -645,6 +645,29 @@ sub customer_info_short {
          };
 }
 
+sub customer_recurring {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  my %return;
+
+  my $conf = new FS::Conf;
+
+  my $search = { 'custnum' => $custnum };
+  $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent';
+  my $cust_main = qsearchs('cust_main', $search )
+    or return { 'error' => "customer_info_short: unknown custnum $custnum" };
+
+  $return{'display_recurring'} = [ $cust_main->display_recurring ];
+
+  return { 'error'          => '',
+           'custnum'        => $custnum,
+           %return,
+         };
+}
+
 sub billing_history {
   my $p = shift;
 
diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm
index 97019d1..7a1fc3e 100644
--- a/FS/FS/ClientAPI_XMLRPC.pm
+++ b/FS/FS/ClientAPI_XMLRPC.pm
@@ -111,6 +111,7 @@ sub ss2clientapi {
   'switch_acct'               => 'MyAccount/switch_acct',
   'customer_info'             => 'MyAccount/customer_info',
   'customer_info_short'       => 'MyAccount/customer_info_short',
+  'customer_recurring'        => 'MyAccount/customer_recurring',
 
   'contact_passwd'            => 'MyAccount/contact/contact_passwd',
   'list_contacts'             => 'MyAccount/contact/list_contacts',
diff --git a/bin/xmlrpc-customer_recurring b/bin/xmlrpc-customer_recurring
new file mode 100755
index 0000000..18dd3e8
--- /dev/null
+++ b/bin/xmlrpc-customer_recurring
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+use strict;
+use Frontier::Client;
+use Data::Dumper;
+
+my( $email, $password ) = @ARGV;
+die "Usage: xmlrpc-customer_recurring email password\n"
+  unless $email && length($password);
+
+my $uri = new URI 'http://localhost:8080/';
+
+my $server = new Frontier::Client ( 'url' => $uri );
+
+my $login_result = $server->call(
+  'FS.ClientAPI_XMLRPC.login',
+    'email'    => $email,
+    'password' => $password,
+);
+die $login_result->{'error'}."\n" if $login_result->{'error'};
+
+my $list_result = $server->call(
+  'FS.ClientAPI_XMLRPC.customer_recurring',
+    'session_id'   => $login_result->{'session_id'},
+);
+die $list_result->{'error'}."\n" if $list_result->{'error'};
+
+print Dumper($list_result);
+
+1;
diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm
index ecbb6e9..32b2ded 100644
--- a/fs_selfservice/FS-SelfService/SelfService.pm
+++ b/fs_selfservice/FS-SelfService/SelfService.pm
@@ -32,6 +32,7 @@ $socket .= '.'.$tag if defined $tag && length($tag);
   'switch_acct'               => 'MyAccount/switch_acct',
   'customer_info'             => 'MyAccount/customer_info',
   'customer_info_short'       => 'MyAccount/customer_info_short',
+  'customer_recurring'        => 'MyAccount/customer_recurring',
 
   'contact_passwd'            => 'MyAccount/contact/contact_passwd',
   'list_contacts'             => 'MyAccount/contact/list_contacts',
@@ -479,6 +480,31 @@ first last company address1 address2 city county state zip country daytime night
 
 =back
 
+=item customer_recurring HASHREF
+
+Takes a hash reference as parameter with a single key B<session_id>
+or keys B<agent_session_id> and B<custnum>.
+
+Returns a hash reference with the keys error, custnum and display_recurring.
+
+display_recurring is an arrayref of hashrefs with the following keys:
+
+=over 4
+
+=item freq
+
+frequency of charge, in months unless units are specified
+
+=item freq_pretty
+
+frequency of charge, suitable for display
+
+=item amount
+
+amount charged at this frequency
+
+=back
+
 =item edit_info HASHREF
 
 Takes a hash reference as parameter with any of the following keys:

commit 259777e4667fc8a45496ba2805d1f7e01c75ac7b
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Wed Aug 31 22:26:32 2016 -0500

    RT#71890: SelfService API: Return monthly recurring fee [display_recurring, v3 reconcile bug fix]

diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html
index eed3baf..7be3201 100644
--- a/httemplate/view/cust_main/billing.html
+++ b/httemplate/view/cust_main/billing.html
@@ -30,8 +30,8 @@
 % if ( $cust_main->num_ncancelled_pkgs < 54 ) {
 %   foreach my $freq_info ($cust_main->display_recurring) {
       <TR>
-        <TH ALIGN="right"><% emt( ucfirst($freq_info->{'freq_pretty'}). ' recurring' ) %></TH>
-        <TD><% $money_char. sprintf('%.2f', $freq_info->{'amount'}) %></TD>
+        <TD ALIGN="right"><% emt( ucfirst($freq_info->{'freq_pretty'}). ' recurring' ) %></TD>
+        <TD BGCOLOR="#ffffff"><% $money_char. sprintf('%.2f', $freq_info->{'amount'}) %></TD>
       </TR>
 %   }
 % }

commit f61619b95f05b576518ea698ad7e22267b4c36c4
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Tue Aug 9 00:55:45 2016 -0500

    RT#71890: SelfService API: Return monthly recurring fee [display_recurring, v3 reconcile]

diff --git a/FS/FS/cust_main/Packages.pm b/FS/FS/cust_main/Packages.pm
index 8f96f81..4d0eee7 100644
--- a/FS/FS/cust_main/Packages.pm
+++ b/FS/FS/cust_main/Packages.pm
@@ -706,6 +706,104 @@ sub num_usage_pkgs {
   FS::Record->scalar_sql($sql, $self->custnum);
 }
 
+=item display_recurring
+
+Returns an array of hash references, one for each recurring freq
+on billable customer packages, with keys of freq, freq_pretty and amount
+(the amount that this customer will next be charged at the given frequency.)
+
+Results will be numerically sorted by freq.
+
+Only intended for display purposes, not used for actual billing.
+
+=cut
+
+sub display_recurring {
+  my $cust_main = shift;
+
+  my $sth = dbh->prepare("
+    SELECT DISTINCT freq FROM cust_pkg LEFT JOIN part_pkg USING (pkgpart)
+      WHERE freq IS NOT NULL AND freq != '0'
+        AND ( cancel IS NULL OR cancel = 0 )
+        AND custnum = ?
+  ") or die $DBI::errstr;
+
+  $sth->execute($cust_main->custnum) or die $sth->errstr;
+
+  #not really a numeric sort because freqs can actually be all sorts of things
+  # but good enough for the 99% cases of ordering monthly quarterly annually
+  my @freqs = sort { $a <=> $b } map { $_->[0] } @{ $sth->fetchall_arrayref };
+
+  $sth->finish;
+
+  my @out;
+
+  foreach my $freq (@freqs) {
+
+    my @cust_pkg = qsearch({
+      'table'     => 'cust_pkg',
+      'addl_from' => 'LEFT JOIN part_pkg USING (pkgpart)',
+      'hashref'   => { 'custnum' => $cust_main->custnum, },
+      'extra_sql' => 'AND ( cancel IS NULL OR cancel = 0 )
+                      AND freq = '. dbh->quote($freq),
+      'order_by'  => 'ORDER BY COALESCE(start_date,0), pkgnum', # to ensure old pkgs come before change_to_pkg
+    }) or next;
+
+    my $freq_pretty = $cust_pkg[0]->part_pkg->freq_pretty;
+
+    my $amount = 0;
+    my $skip_pkg = {};
+    foreach my $cust_pkg (@cust_pkg) {
+      my $part_pkg = $cust_pkg->part_pkg;
+      next if $cust_pkg->susp
+           && ! $cust_pkg->option('suspend_bill')
+           && ( ! $part_pkg->option('suspend_bill')
+                || $cust_pkg->option('no_suspend_bill')
+              );
+
+      #pkg change handling
+      next if $skip_pkg->{$cust_pkg->pkgnum};
+      if ($cust_pkg->change_to_pkgnum) {
+        #if change is on or before next bill date, use new pkg
+        next if $cust_pkg->expire <= $cust_pkg->bill;
+        #if change is after next bill date, use old (this) pkg
+        $skip_pkg->{$cust_pkg->change_to_pkgnum} = 1;
+      }
+
+      my $pkg_amount = 0;
+
+      #add recurring amounts for this package and its billing add-ons
+      foreach my $l_part_pkg ( $part_pkg->self_and_bill_linked ) {
+        $pkg_amount += $l_part_pkg->base_recur($cust_pkg);
+      }
+
+      #subtract amounts for any active discounts
+      #(there should only be one at the moment, otherwise this makes no sense)
+      foreach my $cust_pkg_discount ( $cust_pkg->cust_pkg_discount_active ) {
+        my $discount = $cust_pkg_discount->discount;
+        #and only one of these for each
+        $pkg_amount -= $discount->amount;
+        $pkg_amount -= $amount * $discount->percent/100;
+      }
+
+      $pkg_amount *= ( $cust_pkg->quantity || 1 );
+
+      $amount += $pkg_amount;
+
+    } #foreach $cust_pkg
+
+    next unless $amount;
+    push @out, {
+      'freq'        => $freq,
+      'freq_pretty' => $freq_pretty,
+      'amount'      => $amount,
+    };
+
+  } #foreach $freq
+
+  return @out;
+}
+
 =back
 
 =head1 BUGS
diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html
index 3d0983e..eed3baf 100644
--- a/httemplate/view/cust_main/billing.html
+++ b/httemplate/view/cust_main/billing.html
@@ -28,79 +28,12 @@
 % # customer base, and compare it to a graph of the overhead for generating this
 % # information.  (and optimize it better, we could get it more from SQL)
 % if ( $cust_main->num_ncancelled_pkgs < 54 ) {
-%   my $sth = dbh->prepare("
-%     SELECT DISTINCT freq FROM cust_pkg LEFT JOIN part_pkg USING (pkgpart)
-%       WHERE freq IS NOT NULL AND freq != '0'
-%         AND ( cancel IS NULL OR cancel = 0 )
-%         AND custnum = ?
-%   ") or die $DBI::errstr;
-% 
-%   $sth->execute($cust_main->custnum) or die $sth->errstr;
-
-%   #not really a numeric sort because freqs can actually be all sorts of things
-%   # but good enough for the 99% cases of ordering monthly quarterly annually
-%   my @freqs = sort { $a <=> $b } map { $_->[0] } @{ $sth->fetchall_arrayref };
-% 
-%   foreach my $freq (@freqs) {
-%     my @cust_pkg = qsearch({
-%       'table'     => 'cust_pkg',
-%       'addl_from' => 'LEFT JOIN part_pkg USING (pkgpart)',
-%       'hashref'   => { 'custnum' => $cust_main->custnum, },
-%       'extra_sql' => 'AND ( cancel IS NULL OR cancel = 0 )
-%                       AND freq = '. dbh->quote($freq),
-%       'order_by'  => 'ORDER BY COALESCE(start_date,0), pkgnum', # to ensure old pkgs come before change_to_pkg
-%     }) or next;
-% 
-%     my $freq_pretty = $cust_pkg[0]->part_pkg->freq_pretty;
-%
-%     my $amount = 0;
-%     my $skip_pkg = {};
-%     foreach my $cust_pkg (@cust_pkg) {
-%       my $part_pkg = $cust_pkg->part_pkg;
-%       next if $cust_pkg->susp
-%            && ! $cust_pkg->option('suspend_bill')
-%            && ( ! $part_pkg->option('suspend_bill')
-%                 || $cust_pkg->option('no_suspend_bill')
-%               );
-%
-%       #pkg change handling
-%       next if $skip_pkg->{$cust_pkg->pkgnum};
-%       if ($cust_pkg->change_to_pkgnum) {
-%         #if change is on or before next bill date, use new pkg
-%         next if $cust_pkg->expire <= $cust_pkg->bill;
-%         #if change is after next bill date, use old (this) pkg
-%         $skip_pkg->{$cust_pkg->change_to_pkgnum} = 1;
-%       }
-%
-%       my $pkg_amount = 0;
-%
-%       #add recurring amounts for this package and its billing add-ons
-%       foreach my $l_part_pkg ( $part_pkg->self_and_bill_linked ) {
-%         $pkg_amount += $l_part_pkg->base_recur($cust_pkg);
-%       }
-%
-%       #subtract amounts for any active discounts
-%       #(there should only be one at the moment, otherwise this makes no sense)
-%       foreach my $cust_pkg_discount ( $cust_pkg->cust_pkg_discount_active ) {
-%         my $discount = $cust_pkg_discount->discount;
-%         #and only one of these for each
-%         $pkg_amount -= $discount->amount;
-%         $pkg_amount -= $amount * $discount->percent/100;
-%       }
-%
-%       $pkg_amount *= ( $cust_pkg->quantity || 1 );
-%
-%       $amount += $pkg_amount;
-%
-%     }
-   
+%   foreach my $freq_info ($cust_main->display_recurring) {
       <TR>
-        <TD ALIGN="right"><% emt( ucfirst($freq_pretty). ' recurring' ) %></TD>
-        <TD BGCOLOR="#ffffff"><% $money_char. sprintf('%.2f', $amount) %></TD>
-        </TD>
+        <TH ALIGN="right"><% emt( ucfirst($freq_info->{'freq_pretty'}). ' recurring' ) %></TH>
+        <TD><% $money_char. sprintf('%.2f', $freq_info->{'amount'}) %></TD>
       </TR>
 %   }
-
 % }
 
 % if ( $conf->exists('cust_main-select-prorate_day') ) {

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

Summary of changes:
 FS/FS/ClientAPI/MyAccount.pm                       |   23 +++++
 FS/FS/ClientAPI_XMLRPC.pm                          |    1 +
 FS/FS/cust_main/Packages.pm                        |   98 ++++++++++++++++++++
 ...rpc-list_contacts => xmlrpc-customer_recurring} |    4 +-
 fs_selfservice/FS-SelfService/SelfService.pm       |   26 ++++++
 httemplate/view/cust_main/billing.html             |   73 +--------------
 6 files changed, 154 insertions(+), 71 deletions(-)
 copy bin/{xmlrpc-list_contacts => xmlrpc-customer_recurring} (80%)




More information about the freeside-commits mailing list