[freeside-commits] branch master updated. 296230b7b4fc12cf532f48fe9253cc94f565d5b5

Ivan ivan at 420.am
Wed Jan 21 01:22:40 PST 2015


The branch, master has been updated
       via  296230b7b4fc12cf532f48fe9253cc94f565d5b5 (commit)
       via  c17d9d4c5fd4a668cafa8ea3a844e5750db974fe (commit)
       via  ddbe06e47316e996f909dc534a9aeabe7b47d0f3 (commit)
       via  908a4522939c0225ef4e7ba4236dab2eebe9daca (commit)
      from  b7ffb750cdfd0eb6d72e50ee1ba783992aa3d391 (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 296230b7b4fc12cf532f48fe9253cc94f565d5b5
Merge: c17d9d4 b7ffb75
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Wed Jan 21 01:22:13 2015 -0800

    Merge branch 'master' of git.freeside.biz:/home/git/freeside


commit c17d9d4c5fd4a668cafa8ea3a844e5750db974fe
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Wed Jan 21 01:22:08 2015 -0800

    credit sources, RT#28917

diff --git a/FS/t/cust_credit_source_bill_pkg.t b/FS/t/cust_credit_source_bill_pkg.t
new file mode 100644
index 0000000..45da433
--- /dev/null
+++ b/FS/t/cust_credit_source_bill_pkg.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_credit_source_bill_pkg;
+$loaded=1;
+print "ok 1\n";

commit ddbe06e47316e996f909dc534a9aeabe7b47d0f3
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Wed Jan 21 01:20:41 2015 -0800

    update api docs for cust_credit_source_bill_pkg changes, RT#32706

diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm
index dde847a..9eb624e 100644
--- a/FS/FS/cust_credit.pm
+++ b/FS/FS/cust_credit.pm
@@ -132,11 +132,27 @@ sub cust_unlinked_msg {
   ' (cust_credit.crednum '. $self->crednum. ')';
 }
 
-=item insert
+=item insert [ OPTION => VALUE ... ]
 
 Adds this credit to the database ("Posts" the credit).  If there is an error,
 returns the error, otherwise returns false.
 
+Ooptions are passed as a list of keys and values.  Available options:
+
+=over 4
+
+=item reason_type
+
+L<FS::reason_type|Reason> type for newly-inserted reason
+
+=item cust_credit_source_bill_pkg
+
+An arrayref of
+L<FS::cust_credit_source_bill_pkg|FS::cust_credit_source_bilL_pkg> objects.
+They will have their crednum set and will be inserted along with this credit.
+
+=back
+
 =cut
 
 sub insert {
diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm
index d2f2f86..540919e 100644
--- a/FS/FS/part_pkg.pm
+++ b/FS/FS/part_pkg.pm
@@ -1638,16 +1638,120 @@ sub _rebless {
   $self;
 }
 
+=item calc_setup CUST_PKG START_DATE DETAILS_ARRAYREF OPTIONS_HASHREF
+
+=item calc_recur CUST_PKG START_DATE DETAILS_ARRAYREF OPTIONS_HASHREF
+
+Calculates and returns the setup or recurring fees, respectively, for this
+package.  Implementation is in the FS::part_pkg:* module specific to this price
+plan.
+
+Adds invoicing details to the passed-in DETAILS_ARRAYREF
+
+Options are passed as a hashref.  Available options:
+
+=over 4
+
+=item freq_override
+
+Frequency override (for calc_recur)
+
+=item discounts
+
+This option is filled in by the method rather than controlling its operation.
+It is an arrayref.  Applicable discounts will be added to the arrayref, as
+L<FS::cust_bill_pkg_discount|FS::cust_bill_pkg_discount records>.
+
+=item real_pkgpart
+
+For package add-ons, is the base L<FS::part_pkg|package definition>, otherwise
+no different than pkgpart.
+
+=item precommit_hooks
+
+This option is filled in by the method rather than controlling its operation.
+It is an arrayref.  Anonymous coderefs will be added to the arrayref.  They
+need to be called before completing the billing operation.  For calc_recur
+only.
+
+=item increment_next_bill
+
+Increment the next bill date (boolean, for calc_recur).  Typically true except
+for particular situations.
+
+=item setup_fee
+
+This option is filled in by the method rather than controlling its operation.
+It indicates a deferred setup fee that is billed at calc_recur time (see price
+plan option prorate_defer_bill).
+
+=back
+
+Note: Don't calculate prices when not actually billing the package.  For that,
+see the L</base_setup|base_setup> and L</base_recur|base_recur> methods.
+
+=cut
+
 #fatal fallbacks
 sub calc_setup { die 'no calc_setup for '. shift->plan. "\n"; }
 sub calc_recur { die 'no calc_recur for '. shift->plan. "\n"; }
 
-#fallback that return 0 for old legacy packages with no plan
+=item calc_remain CUST_PKG [ OPTION => VALUE ... ]
+
+Calculates and returns the remaining value to be credited upon package
+suspension, change, or cancellation, if enabled.
+
+Options are passed as a list of keys and values.  Available options:
+
+=over 4
+
+=item time
+
+Override for the current time
+
+=item cust_credit_source_bill_pkg
+
+This option is filled in by the method rather than controlling its operation.
+It is an arrayref.
+L<FS::cust_credit_source_bill_pkg|FS::cust_credit_source_bill_pkg> records will
+be added to the arrayref indicating the specific line items and amounts which
+are the source of this remaining credit.
+
+=back
+
+Note: Don't calculate prices when not actually suspending or cancelling the
+package.
+
+=cut
+
+#fallback that returns 0 for old legacy packages with no plan
 sub calc_remain { 0; }
+
+=item calc_units CUST_PKG
+
+This returns the number of provisioned svc_phone records, or, of the package
+count_available_phones option is set, the number available to be provisoined
+in the package.
+
+=cut
+
+#fallback that returns 0 for old legacy packages with no plan
 sub calc_units  { 0; }
 
 #fallback for everything not based on flat.pm
 sub recur_temporality { 'upcoming'; }
+
+=item calc_cancel START_DATE DETAILS_ARRAYREF OPTIONS_HASHREF
+
+Runs any necessary billing on cancellation: another recurring cycle for
+recur_temporailty 'preceding' pacakges with the bill_recur_on_cancel option
+set (calc_recur), or, any outstanding usage for pacakges with the
+bill_usage_on_cancel option set (calc_usage).
+
+=cut
+
+#fallback for everything not based on flat.pm, doesn't do this yet (which is
+#okay, nothing of ours not based on flat.pm does usage-on-cancel billing
 sub calc_cancel { 0; }
 
 #fallback for everything except bulk.pm

commit 908a4522939c0225ef4e7ba4236dab2eebe9daca
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Tue Jan 20 21:41:15 2015 -0800

    credit sources, RT#28917

diff --git a/FS/FS.pm b/FS/FS.pm
index b87c166..33105ba 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -452,6 +452,8 @@ L<FS::cust_credit_bill> - Credit application to invoice class
 
 L<FS::cust_credit_bill_pkg> - Line-item specific credit application to invoice class
 
+L<FS::cust_credit_source_bill_pkg> - Line-item sources for triggered package credits
+
 L<FS::cust_pay_refund> - Refund application to payment class
 
 L<FS::pay_batch> - Credit card transaction queue class
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index f51b576..b6358b9 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1526,6 +1526,27 @@ sub tables_hashref {
                         ],
     },
 
+    'cust_credit_source_bill_pkg' => {
+      'columns' => [
+        'creditsourcebillpkgnum', 'serial',     '', '', '', '',
+        'crednum',                   'int',     '', '', '', '',
+        'billpkgnum',                'int',     '', '', '', '',
+        'amount',              @money_type,             '', '',
+        'currency',                 'char', 'NULL',  3, '', '',
+      ],
+      'primary_key'  => 'creditsourcebillpkgnum',
+      'unique'       => [],
+      'index'        => [ ['crednum'], ['billpkgnum'] ],
+      'foreign_keys' => [
+                          { columns => ['billpkgnum'],
+                            table   => 'cust_bill_pkg',
+                          },
+                          { columns => ['crednum'],
+                            table   => 'cust_credit',
+                          },
+                        ],
+    },
+
     'cust_main' => {
       'columns' => [
         'custnum',  'serial',  '',     '', '', '', 
diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm
index 212be7a..dde847a 100644
--- a/FS/FS/cust_credit.pm
+++ b/FS/FS/cust_credit.pm
@@ -176,6 +176,17 @@ sub insert {
     return "error inserting $self: $error";
   }
 
+  if ( $options{'cust_credit_source_bill_pkg'} ) {
+    foreach my $ccsbr ( @{ $options{'cust_credit_source_bill_pkg'} } ) {
+      $ccsbr->crednum( $self->crednum );
+      $error = $ccsbr->insert;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return "error inserting $ccsbr: $error";
+      }
+    }
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
   #false laziness w/ cust_pay::insert
diff --git a/FS/FS/cust_credit_source_bill_pkg.pm b/FS/FS/cust_credit_source_bill_pkg.pm
new file mode 100644
index 0000000..dae0d0f
--- /dev/null
+++ b/FS/FS/cust_credit_source_bill_pkg.pm
@@ -0,0 +1,122 @@
+package FS::cust_credit_source_bill_pkg;
+use base qw( FS::cust_main_Mixin FS::Record );
+
+use strict;
+#use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::cust_credit_source_bill_pkg - Object methods for cust_credit_source_bill_pkg records
+
+=head1 SYNOPSIS
+
+  use FS::cust_credit_source_bill_pkg;
+
+  $record = new FS::cust_credit_source_bill_pkg \%hash;
+  $record = new FS::cust_credit_source_bill_pkg { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_credit_source_bill_pkg object represents the record that a credit
+was triggered by a specific line item.  FS::cust_credit_source_bill_pkg
+inherits from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item creditsourcebillpkgnum
+
+Primary key
+
+=item crednum
+
+Credit (see L<FS::cust_credit>)
+
+=item billpkgnum
+
+Line item (see L<FS::cust_bill_pkg>)
+
+=item amount
+
+Amount specific to this line item.
+
+=item currency
+
+Currency
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record.  To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'cust_credit_source_bill_pkg'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('creditsourcebillpkgnum')
+    || $self->ut_foreign_key('crednum', 'cust_credit', 'crednum')
+    || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum')
+    || $self->ut_money('amount')
+    || $self->ut_currencyn('currency')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+Terminology/documentation surrounding credit "sources" vs. credit
+"applications" is hard to understand.
+
+=head1 SEE ALSO
+
+L<FS::cust_credit>, L<FS::cust_bill_pkg>, L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index d55bd7b..5e070e3 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -1440,7 +1440,11 @@ sub credit_remaining {
       and $next_bill > 0      # the package has a next bill date
       and $next_bill >= $time # which is in the future
   ) {
-    my $remaining_value = $self->calc_remain('time' => $time);
+    my @cust_credit_source_bill_pkg = ();
+    my $remaining_value = $self->calc_remain(
+      'time' => $time, 
+      'cust_credit_source_bill_pkg' => \@cust_credit_source_bill_pkg,
+    );
     if ( $remaining_value > 0 ) {
       warn "Crediting for $remaining_value on package ".$self->pkgnum."\n"
         if $DEBUG;
@@ -1448,6 +1452,7 @@ sub credit_remaining {
         $remaining_value,
         'Credit for unused time on '. $self->part_pkg->pkg,
         'reason_type' => $reason_type,
+        'cust_credit_source_bill_pkg' => \@cust_credit_source_bill_pkg,
       );
       return "Error crediting customer \$$remaining_value for unused time".
         " on ". $self->part_pkg->pkg. ": $error"
diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm
index cb2986e..d9d4588 100644
--- a/FS/FS/part_pkg/flat.pm
+++ b/FS/FS/part_pkg/flat.pm
@@ -7,6 +7,7 @@ use base qw( FS::part_pkg::prorate_Mixin
 use strict;
 use vars qw( %info %usage_recharge_fields @usage_recharge_fieldorder );
 use FS::Record qw( qsearch );
+use FS::cust_credit_source_bill_pkg;
 use Tie::IxHash;
 use List::Util qw( min );
 use FS::UI::bytecount;
@@ -242,7 +243,7 @@ sub calc_remain {
   # Use sdate < $time and edate >= $time because when billing on 
   # cancellation, edate = $time.
   my $credit = 0;
-  foreach my $item ( 
+  foreach my $cust_bill_pkg ( 
     qsearch('cust_bill_pkg', { 
       pkgnum => $cust_pkg->pkgnum,
       sdate => {op => '<' , value => $time},
@@ -250,16 +251,28 @@ sub calc_remain {
       recur => {op => '>' , value => 0},
     })
   ) {
+
     # hack to deal with the weird behavior of edate on package cancellation
-    my $edate = $item->edate;
+    my $edate = $cust_bill_pkg->edate;
     if ( $self->recur_temporality eq 'preceding' ) {
-      $edate = $self->add_freq($item->sdate);
+      $edate = $self->add_freq($cust_bill_pkg->sdate);
     }
-    $credit += ($item->recur - $item->usage) * 
-               ($edate - $time) / ($edate - $item->sdate);
+
+    my $amount = ($cust_bill_pkg->recur - $cust_bill_pkg->usage) * 
+                 ($edate - $time) / ($edate - $cust_bill_pkg->sdate);
+    $credit += $amount;
+
+    push @{ $options{'cust_credit_source_bill_pkg'} },
+      new FS::cust_credit_source_bill_pkg {
+        'billpkgnum' => $cust_bill_pkg->billpkgnum,
+        'amount'     => sprintf('%.2f', $amount),
+        'currency'   => $cust_bill_pkg->cust_bill->currency,
+      }
+        if $options{'cust_credit_source_bill_pkg'};
+
   } 
+
   sprintf('%.2f', $credit);
-  #sprintf("%.2f", $self->base_recur($cust_pkg, \$time) * ( $next_bill - $time ) / $freq_sec );
 
 }
 
diff --git a/FS/MANIFEST b/FS/MANIFEST
index 581ab0d..6e36c33 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -832,3 +832,5 @@ FS/circuit_termination.pm
 t/circuit_termination.t
 FS/svc_circuit.pm
 t/svc_circuit.t
+FS/cust_credit_source_bill_pkg.pm
+t/cust_credit_source_bill_pkg.t
diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html
index 816f74a..5f6921c 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -336,6 +336,7 @@ $report_payments{'Deleted Payments / Payment history table'} = [ $fsurl.'search/
 
 tie my %report_credits, 'Tie::IxHash',
   'Credit Report' => [ $fsurl.'search/report_cust_credit.html', 'Credit report (by employee and/or date range)' ],
+  'Credit package source detail' => [ $fsurl.'search/report_cust_credit_source_bill_pkg.html', 'Line-item detail for triggered package credits' ],
   'Credit application detail' => [ $fsurl.'search/report_cust_credit_bill_pkg.html', 'Line item application detail' ],
   'Unapplied Credits' => [ $fsurl.'search/report_cust_credit.html?unapplied=1', 'Unapplied credit report (by type and/or date range)' ],
 ;
diff --git a/httemplate/search/cust_credit_source_bill_pkg.html b/httemplate/search/cust_credit_source_bill_pkg.html
new file mode 100644
index 0000000..3ef88bd
--- /dev/null
+++ b/httemplate/search/cust_credit_source_bill_pkg.html
@@ -0,0 +1,210 @@
+<& elements/search.html,
+              'title'         => 'Credit package source detail', #from line item
+              'name_singular' => 'credit source',
+              'query'         => $query,
+              'count_query'   => $count_query,
+               'count_addl'   => [ $money_char. '%.2f total', ],
+               'header'       => [
+                   #'#',
+
+                   'Amount',
+
+                   #credit
+                   'Date',
+                   'By',
+                   'Reason',
+
+                   # line item
+                   'Line item',
+
+                   #invoice
+                   'Invoice',
+                   'Date',
+                   FS::UI::Web::cust_header(),
+               ],
+               'fields'       => [
+                   #'creditsourcebillpkgnum',
+                   sub { sprintf($money_char.'%.2f', shift->amount ) },
+
+                   sub { time2str('%b %d %Y', shift->get('cust_credit_date') ) },
+                   sub { shift->cust_credit->otaker },
+                   sub { shift->cust_credit->reason },
+
+                   sub { $_[0]->pkgnum > 0
+                           ? $_[0]->get('pkg')      # possibly use override.pkg
+                           : $_[0]->get('itemdesc') # but i think this correct
+                       },
+                   'invnum',
+                   sub { time2str('%b %d %Y', shift->_date ) },
+                   \&FS::UI::Web::cust_fields,
+               ],
+               'sort_fields'  => [
+                   'amount',
+                   'cust_credit_date',
+                   '', #'otaker',
+                   '', #reason
+                   '', #line item description
+                   'invnum',
+                   '_date',
+                   FS::UI::Web::cust_sort_fields(),
+               ],
+               'links' => [
+                   '',
+                   '',
+                   '',
+                   '',
+                   '',
+                   $ilink,
+                   $ilink,
+                   ( map { $_ ne 'Cust. Status' ? $clink : '' }
+                         FS::UI::Web::cust_header()
+                   ),
+               ],
+               'align' => 'rrlll'.
+                          'rr'.
+                          FS::UI::Web::cust_aligns(),
+               'color' => [ 
+                              '',
+                              '',
+                              '',
+                              '',
+                              '',
+                              '',
+                              '',
+                              FS::UI::Web::cust_colors(),
+                            ],
+               'style' => [ 
+                              '',
+                              '',
+                              '',
+                              '',
+                              '',
+                              '',
+                              '',
+                              FS::UI::Web::cust_styles(),
+                          ],
+           
+&>
+<%init>
+
+#copied from cust_credit_source_bill.html, which itself was cribbed from
+# cust_bill_pkg.cgi and cust_credit.html, but then i took out a bunch of the
+# tax reports stuff... maybe look for parts of all three that can be made into
+# common subs?
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my $conf = new FS::Conf;
+
+#here is the agent virtualization
+my $agentnums_sql =
+  $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' );
+
+my @where = ( $agentnums_sql );
+
+if ( $cgi->param('usernum') =~ /^(\d+)$/ ) {
+  push @where, "cust_credit.usernum = $1";
+}
+
+#source invoice date (not yet in UI)
+my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+push @where, "cust_bill._date >= $beginning",
+             "cust_bill._date <= $ending";
+
+#credit date
+my($cr_begin, $cr_end) = FS::UI::Web::parse_beginning_ending($cgi, 'credit');
+push @where, "cust_credit._date >= $cr_begin",
+             "cust_credit._date <= $cr_end";
+
+#credit amount?  seems more what is expected than the applied amount (not in UI)
+my @lt_gt = FS::UI::Web::parse_lt_gt($cgi, 'amount' );
+s/amount/cust_credit.amount/g foreach (@lt_gt);
+push @where, @lt_gt;
+
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+  push @where, "cust_main.agentnum = $1";
+}
+
+#(not in UI)
+if ( $cgi->param('billpkgnum') =~ /^(\d+)$/ ) {
+  push @where, "billpkgnum = $1";
+}
+
+#(not in UI)
+#classnum
+# not specified: all classes
+# 0: empty class
+# N: classnum
+my $use_override = $cgi->param('use_override');
+if ( $cgi->param('classnum') =~ /^(\d+)$/ ) {
+  my $comparison = '';
+  if ( $1 == 0 ) {
+    $comparison = "IS NULL";
+  } else {
+    $comparison = "= $1";
+  }
+
+  if ( $use_override ) {
+    push @where, "(
+      part_pkg.classnum $comparison AND pkgpart_override IS NULL OR
+      override.classnum $comparison AND pkgpart_override IS NOT NULL
+    )";
+  } else {
+    push @where, "part_pkg.classnum $comparison";
+  }
+}
+
+my $count_query = "SELECT COUNT(DISTINCT creditsourcebillpkgnum),
+                          SUM(cust_credit_source_bill_pkg.amount)";
+
+my $join_cust =
+  '      JOIN cust_bill ON ( cust_bill_pkg.invnum = cust_bill.invnum )'.
+  FS::UI::Web::join_cust_main('cust_bill', 'cust_pkg');
+
+
+my $join_cust_bill_pkg = 'LEFT JOIN cust_bill_pkg USING ( billpkgnum )';
+
+my $join_pkg =  ' LEFT JOIN cust_pkg USING ( pkgnum )
+                  LEFT JOIN part_pkg USING ( pkgpart ) ';
+
+my $where = ' WHERE '. join(' AND ', @where);
+
+my $join_credit = ' LEFT JOIN cust_credit      USING ( crednum ) ';
+
+$count_query .= " FROM cust_credit_source_bill_pkg
+                         $join_cust_bill_pkg
+                         $join_pkg
+                         $join_credit
+                         $join_cust
+                       $where";
+
+my @select = ( 'cust_credit_source_bill_pkg.*',
+               'cust_bill_pkg.*',
+               'cust_credit.otaker',
+               'cust_credit._date AS cust_credit_date',
+               'cust_bill._date',
+             );
+push @select, 'part_pkg.pkg' unless $cgi->param('istax');
+push @select, 'cust_main.custnum',
+              FS::UI::Web::cust_sql_fields();
+
+my $query = {
+  'table'     => 'cust_credit_source_bill_pkg',
+  'addl_from' => "$join_cust_bill_pkg
+                  $join_pkg
+                  $join_credit
+                  $join_cust",
+  'hashref'   => {},
+  'select'    => join(', ', @select ),
+  'extra_sql' => $where,
+  'order_by'  => 'ORDER BY creditsourcebillpkgnum', #cust_bill. or cust_credit._date?
+};
+
+my $ilink = [ "${p}view/cust_bill.cgi?", 'invnum' ];
+my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
+
+my $conf = new FS::Conf;
+my $money_char = $conf->config('money_char') || '$'; #well, no guarantee we're totaling these up in the multi-currency world
+
+</%init>
diff --git a/httemplate/search/report_cust_credit_source_bill_pkg.html b/httemplate/search/report_cust_credit_source_bill_pkg.html
new file mode 100644
index 0000000..05f21c0
--- /dev/null
+++ b/httemplate/search/report_cust_credit_source_bill_pkg.html
@@ -0,0 +1,82 @@
+<& /elements/header.html, mt('Credit package source report') &>
+
+<FORM ACTION="cust_credit_source_bill_pkg.html" METHOD="GET">
+<!--<INPUT TYPE="hidden" NAME="magic" VALUE="_date">-->
+
+<TABLE BGCOLOR="#cccccc" CELLSPACING=0>
+
+<& /elements/tr-select-user.html,
+              'label'       => emt('Employee: '),
+              'access_user' => \%access_user,
+&>
+
+<& /elements/tr-select-agent.html,
+     curr_value    => scalar( $cgi->param('agentnum') ),
+     #label         => emt('Line items for agent: '),
+     disable_empty => 0,
+&>
+
+<!--
+<& /elements/tr-select-cust_main-status.html,
+     label => emt('Customer status'),
+&>
+-->
+
+<!-- customer
+<& /elements/tr-select-cust_class.html,
+     'label'        => emt('Class'),
+     'field'        => 'cust_classnum',
+     'multiple'     => 1,
+     'pre_options'  => [ '' => emt('(none)') ],
+     'all_selected' => 1,
+&>
+-->
+
+<!-- some sort of label saying this is the credit date... -->
+<& /elements/tr-input-beginning_ending.html,
+     'prefix' => 'credit',
+&>
+
+<!--
+<& /elements/tr-input-lessthan_greaterthan.html,
+     label   => emt('Amount'),
+     field   => 'amount',
+&>
+-->
+
+<!-- customer payment method in a 4.x world? huh.  how's that work?
+  <& /elements/tr-select-payby.html,
+                label   => emt('Payment method:'),
+                payby_type   => 'cust',
+                multiple     => 1,
+                all_selected => 1,
+  &>
+-->
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="<% mt('Get Report') |h %>">
+
+</FORM>
+
+<& /elements/footer.html &>
+<%init>
+
+#Financial reports?
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+#false laziness w/report_cust_credit.html
+my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_credit")
+  or die dbh->errstr;
+$sth->execute or die $sth->errstr;
+my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
+my %access_user =
+  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
+      @usernum;
+
+my $conf = new FS::Conf;
+
+</%init>
+

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

Summary of changes:
 FS/FS.pm                                           |    2 +
 FS/FS/Schema.pm                                    |   21 ++
 FS/FS/cust_credit.pm                               |   29 ++-
 ...dit_limit.pm => cust_credit_source_bill_pkg.pm} |   53 ++---
 FS/FS/cust_pkg.pm                                  |    7 +-
 FS/FS/part_pkg.pm                                  |  106 +++++++++-
 FS/FS/part_pkg/flat.pm                             |   25 ++-
 FS/MANIFEST                                        |    2 +
 ...AccessRight.t => cust_credit_source_bill_pkg.t} |    2 +-
 httemplate/elements/menu.html                      |    1 +
 httemplate/search/cust_credit_source_bill_pkg.html |  210 ++++++++++++++++++++
 ...tml => report_cust_credit_source_bill_pkg.html} |   34 +---
 12 files changed, 428 insertions(+), 64 deletions(-)
 copy FS/FS/{cust_main_credit_limit.pm => cust_credit_source_bill_pkg.pm} (50%)
 copy FS/t/{AccessRight.t => cust_credit_source_bill_pkg.t} (73%)
 create mode 100644 httemplate/search/cust_credit_source_bill_pkg.html
 copy httemplate/search/{report_cust_credit_bill_pkg.html => report_cust_credit_source_bill_pkg.html} (67%)




More information about the freeside-commits mailing list