[freeside-commits] freeside/FS/FS Conf.pm, 1.378, 1.378.2.1 Mason.pm, 1.47, 1.47.2.1 Schema.pm, 1.226, 1.226.2.1 cust_bill.pm, 1.288, 1.288.2.1 cust_bill_pkg.pm, 1.51, 1.51.2.1 cust_bill_pkg_detail.pm, 1.13, 1.13.2.1 cust_main.pm, 1.527, 1.527.2.1 elec_general.pm, NONE, 1.1.2.1 part_pkg.pm, 1.105, 1.105.2.1 svc_elec.pm, NONE, 1.1.2.1 transaction810.pm, NONE, 1.1.2.1 transaction867.pm, NONE, 1.1.2.1 usage_elec.pm, NONE, 1.1.2.1 usage_elec_transaction867.pm, NONE, 1.1.2.1
Jeff Finucane,420,,
jeff at wavetail.420.am
Mon Aug 2 12:49:21 PDT 2010
- Previous message: [freeside-commits] freeside/FS MANIFEST,1.165,1.165.2.1
- Next message: [freeside-commits] freeside/FS/FS/part_pkg business_elec_generic.pm, NONE, 1.1.2.1 energy_base_discount_500kwh.pm, NONE, 1.1.2.1 energy_base_discount_tiers.pm, NONE, 1.1.2.1 residential_elec_generic.pm, NONE, 1.1.2.1 residential_elec_generic_var.pm, NONE, 1.1.2.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /home/cvs/cvsroot/freeside/FS/FS
In directory wavetail.420.am:/tmp/cvs-serv14262/FS/FS
Modified Files:
Tag: svc_elec_features
Conf.pm Mason.pm Schema.pm cust_bill.pm cust_bill_pkg.pm
cust_bill_pkg_detail.pm cust_main.pm part_pkg.pm
Added Files:
Tag: svc_elec_features
elec_general.pm svc_elec.pm transaction810.pm
transaction867.pm usage_elec.pm usage_elec_transaction867.pm
Log Message:
add svc_elec_features merged from reference code RT#7643
Index: cust_bill_pkg_detail.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_bill_pkg_detail.pm,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -u -w -d -r1.13 -r1.13.2.1
--- cust_bill_pkg_detail.pm 27 Mar 2010 06:21:53 -0000 1.13
+++ cust_bill_pkg_detail.pm 2 Aug 2010 19:49:18 -0000 1.13.2.1
@@ -57,6 +57,45 @@
=item detail - detail description
+=item prev_date
+
+=item curr_date -
+
+=item prev_read -
+
+=item curr_read -
+
+=item tdsp -
+
+=item taxes -
+
+=item rate -
+
+=item gr_fee -
+
+=item energy_base -
+
+=item energy_charge -
+
+=item setup_fee -
+
+=item one_time_charge -
+
+=item one_time_description -
+
+=item balance -
+
+=item last_pay -
+
+=item last_pay_date -
+
+=item return_addr -
+
+=item bill_return_address -
+
+=item pkg_info -
+
+
=back
=head1 METHODS
@@ -141,6 +180,32 @@
|| $self->ut_foreign_keyn('classnum', 'usage_class', 'classnum')
|| $self->$phonenum_check_method('phonenum')
|| $self->SUPER::check
+ || $self->ut_numbern('prev_date')
+ || $self->ut_numbern('curr_date')
+ || $self->ut_floatn('prev_read')
+ || $self->ut_floatn('curr_read')
+ || $self->ut_money('tdsp')
+ || $self->ut_money('taxes')
+ || $self->ut_money('gr_fee')
+ || $self->ut_money('energy_base')
+ || $self->ut_money('energy_charge')
+ || $self->ut_money('setup_fee')
+ || $self->ut_money('one_time_charge')
+ || $self->ut_floatn('rate')
+ || $self->ut_floatn('discount1_rate')
+ || $self->ut_floatn('discount1_total')
+ || $self->ut_numbern('number_of_days')
+ || $self->ut_floatn('average_price')
+ || $self->ut_floatn('energy_usage')
+ || $self->ut_anything('one_time_description')
+ || $self->ut_money('balance')
+ || $self->ut_money('last_pay')
+ || $self->ut_numbern('last_pay_date')
+ || $self->ut_anything('return_addr')
+ || $self->ut_textn('bill_return_address')
+ || $self->ut_floatn('meter_multiplier')
+ || $self->ut_floatn('demanded_bill')
+ || $self->ut_floatn('measured_bill')
;
}
@@ -325,6 +390,7 @@
'hashref' => {},
'extra_sql' => 'WHERE invnum IS NOT NULL AND '.
'pkgnum IS NOT NULL',
+ 'order_by' => 'ORDER BY detailnum',
});
if (scalar(@cbpd)) {
Index: Conf.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Conf.pm,v
retrieving revision 1.378
retrieving revision 1.378.2.1
diff -u -w -d -r1.378 -r1.378.2.1
--- Conf.pm 30 Jul 2010 22:08:54 -0000 1.378
+++ Conf.pm 2 Aug 2010 19:49:16 -0000 1.378.2.1
@@ -1156,6 +1156,13 @@
},
{
+ 'key' => 'rec_latex',
+ 'section' => 'invoicing',
+ 'description' => 'Optional LaTeX template for typeset PostScript statements when svc_elec_features are enabled. See the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration#Typeset_.28LaTeX.29_invoice_templates">billing documentation</a> for details.',
+ 'type' => 'textarea',
+ },
+
+ {
'key' => 'invoice_email_pdf',
'section' => 'invoicing',
'description' => 'Send PDF invoice as an attachment to emailed invoices. By default, includes the plain text invoice as the email body, unless invoice_email_pdf_note is set.',
@@ -1181,7 +1188,7 @@
'section' => 'invoicing',
'description' => 'Optional default invoice term, used to calculate a due date printed on invoices.',
'type' => 'select',
- 'select_enum' => [ '', 'Payable upon receipt', 'Net 0', 'Net 10', 'Net 15', 'Net 20', 'Net 30', 'Net 45', 'Net 60' ],
+ 'select_enum' => [ '', 'Payable upon receipt', 'Net 0', 'Net 10', 'Net 15', 'Net 16', 'Net 20', 'Net 30', 'Net 45', 'Net 60' ],
},
{
@@ -3885,6 +3892,14 @@
},
{
+ 'key' => 'svc_elec_features',
+ 'section' => '',
+ 'description' => 'Enable electrical billing features',
+ 'type' => 'select',
+ 'type' => 'checkbox',
+ },
+
+ {
'key' => 'maestro-status_test',
'section' => 'UI',
'description' => 'Display a link to the maestro status test page on the customer view page',
Index: cust_bill_pkg.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_bill_pkg.pm,v
retrieving revision 1.51
retrieving revision 1.51.2.1
diff -u -w -d -r1.51 -r1.51.2.1
--- cust_bill_pkg.pm 27 Jun 2010 09:25:26 -0000 1.51
+++ cust_bill_pkg.pm 2 Aug 2010 19:49:18 -0000 1.51.2.1
@@ -145,7 +145,12 @@
if ( $self->get('details') ) {
foreach my $detail ( @{$self->get('details')} ) {
- my $cust_bill_pkg_detail = new FS::cust_bill_pkg_detail {
+ my $cust_bill_pkg_detail;
+ if (ref($detail) eq 'FS::cust_bill_pkg_detail') {
+ $cust_bill_pkg_detail = $detail;
+ $cust_bill_pkg_detail->billpkgnum($self->billpkgnum);
+ } else {
+ $cust_bill_pkg_detail = new FS::cust_bill_pkg_detail {
'billpkgnum' => $self->billpkgnum,
'format' => (ref($detail) ? $detail->[0] : '' ),
'detail' => (ref($detail) ? $detail->[1] : $detail ),
@@ -155,6 +160,7 @@
'duration' => (ref($detail) ? $detail->[5] : '' ),
'regionname' => (ref($detail) ? $detail->[6] : '' ),
};
+ }
$error = $cust_bill_pkg_detail->insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
@@ -870,7 +876,11 @@
my %hash = ( 'billpkgnum' => $self->billpkgnum );
$hash{classnum} = $classnum if $classnum;
- qsearch ( 'cust_bill_pkg_detail', { %hash } ),
+ qsearch ({
+ 'table' => 'cust_bill_pkg_detail',
+ 'hashref' => { %hash },
+ 'order_by' => 'ORDER BY detailnum',
+ });
}
Index: cust_bill.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_bill.pm,v
retrieving revision 1.288
retrieving revision 1.288.2.1
diff -u -w -d -r1.288 -r1.288.2.1
--- cust_bill.pm 28 Jun 2010 04:11:47 -0000 1.288
+++ cust_bill.pm 2 Aug 2010 19:49:17 -0000 1.288.2.1
@@ -36,6 +36,8 @@
use FS::payby;
use FS::bill_batch;
use FS::cust_bill_batch;
+use FS::usage_elec qw(most_current_date);
+use FS::cust_bill_pkg_detail; #ugh
@ISA = qw( FS::cust_main_Mixin FS::Record );
@@ -50,6 +52,13 @@
$rdate_format = $conf->config('date_format') || '%m/%d/%Y';
} );
+# i think this is cruft
+sub usage_elec{
+ warn "$me: usage_elec has been called\n";
+ my $self = shift;
+ qsearch('usage_elec',{ 'cust_nr' => $self->custnum});
+}
+
=head1 NAME
FS::cust_bill - Object methods for cust_bill records
@@ -2051,7 +2060,7 @@
$params{'time'} = $today if $today;
$params{'template'} = $template if $template;
$params{$_} = $opt{$_}
- foreach grep $opt{$_}, qw( unsquealch_cdr notice_name );
+ foreach grep $opt{$_}, qw(unsquealch_cdr notice_name base ignore_due_date);
$template ||= $self->_agent_template;
@@ -2100,6 +2109,7 @@
Optional options include
+base - a value used for the name of the template. defaults to 'invoice'
template - a value used as a suffix for a configuration template
time - a value used to control the printing of overdue messages. The
@@ -2129,6 +2139,15 @@
die "Unknown format: $format"
unless $format =~ /^(latex|html|template)$/;
+ # this weirdness switches to the most recent invoice under some circumstances
+ if ( $conf->exists('svc_elec_features') && ($params{base} =~ /^rec/i) ) {
+ $self = qsearchs({
+ 'table' => 'cust_bill',
+ 'hashref' => { 'custnum' => $self->custnum },
+ 'order_by' => 'ORDER BY invnum DESC LIMIT 1',
+ });
+ }
+
my $cust_main = $self->cust_main;
$cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
unless $cust_main->payname
@@ -2141,7 +2160,8 @@
#create the template
my $template = $params{template} ? $params{template} : $self->_agent_template;
- my $templatefile = "invoice_$format";
+ my $templatefile = $params{base} || 'invoice'; #base only used for 'rec'
+ $templatefile .= "_$format";
$templatefile .= "_$template"
if length($template);
my @invoice_template = map "$_\n", $conf->config($templatefile)
@@ -2343,9 +2363,12 @@
'notice_name' => ($params{'notice_name'} || 'Invoice'),#escape_function?
'current_charges' => sprintf("%.2f", $self->charged),
'duedate' => $self->due_date2str($rdate_format), #date_format?
+ 'due_date' => $self->due_date2str($rdate_format), #date_format?
+ 'ignore_due_date' => ($params{'ignore_due_date'} || ''),
#customer info
'custnum' => $cust_main->display_custnum,
+ 'phone' => $cust_main->daytime,
'agent_custid' => &$escape_function($cust_main->agent_custid),
( map { $_ => &$escape_function($cust_main->$_()) } qw(
payname company address1 address2 city state zip fax
@@ -2380,6 +2403,121 @@
);
+ my @last_cust_bill_pkg_details = ();
+ if ($conf->exists('svc_elec_features')) {
+
+ $invoice_data{date} = time2str('%D', $self->_date); # date_format?
+
+ # get the detail records sorted by detailnum
+ # too inefficient?
+ @last_cust_bill_pkg_details =
+ sort { $a->detailnum <=> $b->detailnum }
+ map { $_->cust_bill_pkg_detail }
+ $self->cust_bill_pkg;
+
+ # save a copy of the last if there is one
+ my $last_cust_bill_pkg_detail;
+ if (scalar(@last_cust_bill_pkg_details)) {
+ $last_cust_bill_pkg_detail = pop @last_cust_bill_pkg_details;
+ push @last_cust_bill_pkg_details, $last_cust_bill_pkg_detail;
+ }
+
+ foreach my $method ( qw( last_pay setup_fee prev_read one_time_charge
+ curr_read energy_charge energy_base tdsp gr_fee
+ taxes esiid late_fee average_price
+ meter_multplier meter_number ) )
+ {
+ $invoice_data{$method} = $last_cust_bill_pkg_detail
+ ? $last_cust_bill_pkg_detail->$method
+ : '';
+ }
+
+ foreach my $method ( qw( prev_date curr_date last_pay_date ) )
+ {
+ $invoice_data{$method} =
+ $last_cust_bill_pkg_detail
+ ? time2str('%D', $last_cust_bill_pkg_detail->$method)
+ : '';
+ }
+
+ foreach my $method ( qw( one_time_description pkg_info note ) )
+ {
+ $invoice_data{$method} =
+ $last_cust_bill_pkg_detail
+ ? &$escape_function($last_cust_bill_pkg_detail->$method)
+ : '';
+ }
+
+ $invoice_data{$_} = ''
+ foreach qw( discount2_total discount2_description discount2_pkgnum
+ bill_return_address usage numberOfDays balance rate
+ previousbill_numberOfDays previousbill_totalUsage
+ lastyear_numberOfDays lastyear_totalUsage
+ billed_demand measured_demand );
+
+ if ($last_cust_bill_pkg_detail) {
+ $invoice_data{bill_return_address} =
+ $last_cust_bill_pkg_detail->bill_return_addr;
+ $invoice_data{usage} = $last_cust_bill_pkg_detail->energy_usage;
+ $invoice_data{numberOfDays} = $last_cust_bill_pkg_detail->number_of_days;
+ $invoice_data{balance} =
+ sprintf("%.2f", $last_cust_bill_pkg_detail->balance);
+ $invoice_data{actual_balance} = sprintf("%.2f", $cust_main->balance);
+ $invoice_data{rate} = sprintf("%.6f", $last_cust_bill_pkg_detail->rate);
+ $invoice_data{amount_due} =
+ sprintf("%.2f", $self->charged + $last_cust_bill_pkg_detail->balance);
+ $invoice_data{bill_charged} = $invoice_data{current_charges};
+ $invoice_data{billed_demand} = $last_cust_bill_pkg_detail->demanded_bill;
+ $invoice_data{measured_demand} =
+ $last_cust_bill_pkg_detail->measured_bill;
+ $invoice_data{total_discount1} =
+ sprintf('%.2f', $last_cust_bill_pkg_detail->discount1_total)
+ if $last_cust_bill_pkg_detail->discount1_total
+ }
+
+ if (scalar(@last_cust_bill_pkg_details) > 1) {
+ $invoice_data{previousbill_numberOfDays} =
+ &$escape_function($last_cust_bill_pkg_details[1]->number_of_days);
+ $invoice_data{previousbill_totalUsage} =
+ &$escape_function($last_cust_bill_pkg_details[1]->energy_usage);
+ }
+
+ if (scalar(@last_cust_bill_pkg_details) > 11) {
+ $invoice_data{lastyear_numberOfDays} =
+ &$escape_function($last_cust_bill_pkg_details[11]->number_of_days);
+ $invoice_data{lastyear_totalUsage} =
+ &$escape_function($last_cust_bill_pkg_details[11]->energy_usage);
+ }
+
+ #-ctran 4/11/07 : Manipulatinng the Service address to be input
+ #into latex pdf invoice. The database table cust_main call the
+ #service address as ship address. Here I will combine the ship_address1,
+ #ship_address2, and ship_zip to form service address.
+ #-ctran 4/15/07 : If service address is empty, use address1 form cust_main,
+ #this is the mailing address.
+
+ my ($ship_addr1, $ship_addr2) = ($cust_main->ship_address1,
+ $cust_main->ship_address2);
+ $ship_addr1 .= ", $ship_addr2" if $ship_addr2;
+
+ # we have a total of 30 character for the service address location,
+ # so address will consist 19 chars, zip 9 chars, ', ' 2 chars = 30
+
+ my $service_addrs;
+ if ($ship_addr1) {
+ if ( (length($ship_addr1)) > 30 ) {
+ $service_addrs = substr($ship_addr1,0,28) . "...";
+ } else {
+ $service_addrs = $ship_addr1;
+ }
+ $service_addrs .= ", ".$cust_main->ship_zip if ($cust_main->ship_zip);
+ } else {
+ $service_addrs = substr($cust_main->address1,0,30);
+ }
+ $invoice_data{srvc_addr} = &$escape_function($service_addrs);
+
+ }
+
$invoice_data{finance_section} = '';
if ( $conf->config('finance_pkgclass') ) {
my $pkg_class =
@@ -2506,6 +2644,8 @@
my $other_money_char = $other_money_chars{$format};
$invoice_data{'dollar'} = $other_money_char;
+ my $dash = $conf->exists('svc_elec_features') ? '*'x20 : '-----------';
+
my @detail_items = ();
my @total_items = ();
my @buf = ();
@@ -2516,6 +2656,31 @@
$invoice_data{'buf'} = \@buf;
$invoice_data{'sections'} = \@sections;
+ # for some kind of statement
+ my @bills = qsearch({
+ 'table' => 'cust_bill',
+ 'hashref' => { 'custnum' => $self->custnum },
+ 'order_by' => 'ORDER BY _date DESC LIMIT 19',
+ });
+ @bills = reverse(@bills);
+
+ #what about multiple details? original code seems not to care
+ my @bill_details = ();
+ push @bill_details,
+ map { $_->cust_bill_pkg_detail }
+ map { $_->cust_bill_pkg }
+ @bills;
+
+ my @pays = reverse( qsearch({ 'table' => 'cust_pay',
+ 'hashref' => { 'custnum' => $self->custnum },
+ 'order_by' => 'ORDER BY _date DESC LIMIT 19',
+ })
+ );
+
+ $invoice_data{'total_bills'} = \@bills;
+ $invoice_data{'total_payments'} = \@pays;
+ $invoice_data{'total_details'} = \@bill_details;
+
my $previous_section = { 'description' => 'Previous Charges',
'subtotal' => $other_money_char.
sprintf('%.2f', $pr_total),
@@ -2613,7 +2778,7 @@
}
if ( @pr_cust_bill && !$conf->exists('disable_previous_balance') ) {
- push @buf, ['','-----------'];
+ push @buf, ['', $dash];
push @buf, [ 'Total Previous Balance',
$money_char. sprintf("%10.2f", $pr_total) ];
push @buf, ['',''];
@@ -2668,6 +2833,18 @@
$detail->{'description'} = &$escape_function($line_item->{'description'});
if ( exists $line_item->{'ext_description'} ) {
@{$detail->{'ext_description'}} = @{$line_item->{'ext_description'}};
+
+ if ($conf->exists('svc_elec_features')) {
+ if ( grep { /DISCOUNT2/i } @{$line_item->{'ext_description'}} ) {
+ $invoice_data{'discount2_total'} = $line_item->{'amount'};
+ $invoice_data{'discount2_pkgnum'} = $detail->{'ref'};
+
+ #want the bare description
+ $invoice_data{'discount2_description'} = &$escape_function($_->desc)
+ foreach $self->cust_bill_pkg_pkgnum($detail->{'ref'});
+ }
+ }
+
}
$detail->{'amount'} = ( $old_latex ? '' : $money_char ).
$line_item->{'amount'};
@@ -2683,8 +2860,9 @@
);
}
+
if ( $section->{'description'} ) {
- push @buf, ( ['','-----------'],
+ push @buf, ( ['', $dash],
[ $section->{'description'}. ' sub-total',
$money_char. sprintf("%10.2f", $section->{'subtotal'})
],
@@ -2757,7 +2935,7 @@
}
$invoice_data{'taxtotal'} = sprintf('%.2f', $taxtotal);
- push @buf,['','-----------'];
+ push @buf,['', $dash];
push @buf,[( $conf->exists('disable_previous_balance')
? 'Total Charges'
: 'Total New Charges'
@@ -2791,7 +2969,7 @@
}else{
push @total_items, $total;
}
- push @buf,['','-----------'];
+ push @buf,['', $dash];
push @buf,[$item,
$money_char.
sprintf( '%10.2f', $amount )
@@ -2886,7 +3064,7 @@
}else{
push @total_items, $total;
}
- push @buf,['','-----------'];
+ push @buf,['', $dash];
push @buf,[$self->balance_due_msg, $money_char.
sprintf("%10.2f", $balance_due ) ];
}
--- NEW FILE: svc_elec.pm ---
package FS::svc_elec;
use strict;
use vars qw( @ISA );
#use FS::Record qw( qsearch qsearchs );
use FS::svc_Common;
#@ISA = qw(FS::Record);
@ISA = qw( FS::svc_Common );
=head1 NAME
FS::svc_elec - Object methods for svc_elec records
=head1 SYNOPSIS
use FS::svc_elec;
$record = new FS::svc_elec \%hash;
$record = new FS::svc_elec { 'column' => 'value' };
$error = $record->insert;
$error = $new_record->replace($old_record);
$error = $record->delete;
$error = $record->check;
$error = $record->suspend;
$error = $record->unsuspend;
$error = $record->cancel;
=head1 DESCRIPTION
An FS::svc_elec object represents an example. FS::svc_elec inherits from
FS::Record. The following fields are currently supported:
=over 4
=item id -
=item esiid -
=item svcnum - primary key
=item countrycode -
=item phonenum -
=item pin -
=back
=head1 METHODS
=over 4
=item new HASHREF
Creates a new example. To add the example 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
# the new method can be inherited from FS::Record, if a table method is defined
sub table { 'svc_elec'; }
=item insert
Adds this record to the database. If there is an error, returns the error,
otherwise returns false.
=cut
# the insert method can be inherited from FS::Record
=item delete
Delete this record from the database.
=cut
# the delete method can be inherited from FS::Record
=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.
=cut
# the replace method can be inherited from FS::Record
=item check
Checks all fields to make sure this is a valid example. If there is
an error, returns the error, otherwise returns false. Called by the insert
and replace methods.
=cut
# the check method should currently be supplied - FS::Record contains some
# data checking routines
sub check {
my $self = shift;
my $error =
$self->ut_numbern('svcnum')
|| $self->ut_number('id')
|| $self->ut_number('esiid')
|| $self->ut_text('countrycode')
|| $self->ut_text('phonenum')
|| $self->ut_textn('pin')
;
return $error if $error;
$self->SUPER::check;
}
=back
=head1 BUGS
The author forgot to customize this manpage.
=head1 SEE ALSO
L<FS::Record>, schema.html from the base documentation.
=cut
1;
--- NEW FILE: usage_elec_transaction867.pm ---
package FS::usage_elec_transaction867;
use strict;
use vars qw( @ISA );
use FS::Record qw( qsearch qsearchs );
@ISA = qw(FS::Record);
=head1 NAME
FS::usage_elec_transaction867 - Object methods for usage_elec_transaction867 records
=head1 SYNOPSIS
use FS::usage_elec_transaction867;
$record = new FS::usage_elec_transaction867 \%hash;
$record = new FS::usage_elec_transaction867 { 'column' => 'value' };
$error = $record->insert;
$error = $new_record->replace($old_record);
$error = $record->delete;
$error = $record->check;
=head1 DESCRIPTION
An FS::usage_elec_transaction867 object represents an example. FS::usage_elec_transaction867 inherits from
FS::Record. The following fields are currently supported:
=over 4
=item id - primary key
=item usage_elec_id -
=item note -
=back
=head1 METHODS
=over 4
=item new HASHREF
Creates a new example. To add the example 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
# the new method can be inherited from FS::Record, if a table method is defined
sub table { 'usage_elec_transaction867'; }
=item insert
Adds this record to the database. If there is an error, returns the error,
otherwise returns false.
=cut
# the insert method can be inherited from FS::Record
=item delete
Delete this record from the database.
=cut
# the delete method can be inherited from FS::Record
=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.
=cut
# the replace method can be inherited from FS::Record
=item check
Checks all fields to make sure this is a valid example. If there is
an error, returns the error, otherwise returns false. Called by the insert
and replace methods.
=cut
# the check method should currently be supplied - FS::Record contains some
# data checking routines
sub check {
my $self = shift;
my $error =
$self->ut_numbern('id')
|| $self->ut_number('usage_elec_id')
|| $self->ut_textn('note')
;
return $error if $error;
$self->SUPER::check;
}
=back
=head1 BUGS
The author forgot to customize this manpage.
=head1 SEE ALSO
L<FS::Record>, schema.html from the base documentation.
=cut
1;
--- NEW FILE: transaction810.pm ---
package FS::transaction810;
use strict;
use vars qw( @ISA @EXPORT_OK );
use vars qw( @ISA );
use FS::Record qw( qsearch qsearchs );
use FS::UID qw( getotaker dbh );
use Exporter;
use Data::Dumper;
@ISA = qw(FS::Record);
@EXPORT_OK=qw(batch_810data_import);
=head1 NAME
FS::transaction810 - Object methods for transaction810 records
=head1 SYNOPSIS
use FS::transaction810;
$record = new FS::transaction810 \%hash;
$record = new FS::transaction810 { 'column' => 'value' };
$error = $record->insert;
$error = $new_record->replace($old_record);
$error = $record->delete;
$error = $record->check;
=head1 DESCRIPTION
An FS::transaction810 object represents an example. FS::transaction810 inherits from
FS::Record. The following fields are currently supported:
=over 4
=item id - primary key
=item duns -
=item inv_num -
=item usage_867 -
=item esiid -
=item tdsp -
=item due_date -
=item inv_date -
=item usage_kwatts -
=item srvc_from_date -
=item srvc_to_date -
=item puct_fund -
=item billed_demand -
=item measured_demand -
=item bill_status -
=item type_of_bill -
=item ack_997 -
=back
=head1 METHODS
=over 4
=item new HASHREF
Creates a new example. To add the example 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
# the new method can be inherited from FS::Record, if a table method is defined
sub table { 'transaction810'; }
=item insert
Adds this record to the database. If there is an error, returns the error,
otherwise returns false.
=cut
# the insert method can be inherited from FS::Record
=item delete
Delete this record from the database.
=cut
# the delete method can be inherited from FS::Record
=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.
=cut
# the replace method can be inherited from FS::Record
=item check
Checks all fields to make sure this is a valid example. If there is
an error, returns the error, otherwise returns false. Called by the insert
and replace methods.
=cut
# the check method should currently be supplied - FS::Record contains some
# data checking routines
sub check {
my $self = shift;
my $error =
$self->ut_numbern('id')
|| $self->ut_number('tdsp_duns')
|| $self->ut_number('inv_num')
|| $self->ut_textn('ref_identification')
|| $self->ut_number('esiid')
|| $self->ut_number('tdsp')
|| $self->ut_number('due_date')
|| $self->ut_number('inv_date')
|| $self->ut_float('usage_kwatts')
|| $self->ut_number('srvc_from_date')
|| $self->ut_number('srvc_to_date')
|| $self->ut_number('puct_fund')
|| $self->ut_float('billed_demand')
|| $self->ut_floatn('measured_demand')
|| $self->ut_text('bill_status')
|| $self->ut_numbern('type_of_bill')
|| $self->ut_numbern('ack_997')
|| $self->ut_numbern('processed')
;
return $error if $error;
$self->SUPER::check;
}
sub testing {
my $param = shift;
my @usages = qsearch ( 'usage_elec' );
foreach my $usage (@usages) {
print "meter number: " . $usage->meter_number . "\n";
}
return "Successful sub read\n";
}
=item batch_810data_import
Importing a CVS file with the following column:
duns inv_num 867_usage esiid tdsp due_date inv_date usage_kwatts
srvc_from_date srvc_to_date puct_fund billed_demand
measured_demand bill_status type_of_bill 997_ack
=cut
#@EXPORT_OK=qw(batch_810data_import);
sub batch_810data_import {
#my $param = shift;
my ($fh,$format) = @_;
# print "\n\n****************** the cvs file\n\n";
# print (<$fh>);
# print ("\n$format\n");
# return "done\n";
#my $fh = $param->{filehandle};
#my $format = $param->{'format'};
my $error;
my $debug = 0;
my @fields;
if ( $format eq 'extended' ) {
@fields = qw(
tdsp_duns inv_num ref_identification esiid tdsp due_date
inv_date usage_kwatts srvc_from_date srvc_to_date
puct_fund billed_demand measured_demand bill_status
type_of_bill
);
} else {
die "unknown format $format";
}
eval "use Text::CSV_XS;";
die $@ if $@;
my $csv = new Text::CSV_XS;
#warn $csv;
#warn $fh;
my $imported = 0;
#my $columns;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
local $SIG{PIPE} = 'IGNORE';
my $oldAutoCommit = $FS::UID::AutoCommit;
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
#while ( $columns = $csv->getline($fh) ) {
my $line;
while ( defined($line=<$fh>) ) {
$csv->parse($line) or do {
$dbh->rollback if $oldAutoCommit;
return "can't parse: ". $csv->error_input();
};
my @columns = $csv->fields();
#warn join('-', at columns);
# this hash will hold each CVS line
my %transaction810_data;
my $billtime = time;
# my %cust_pkg = ( pkgpart => $pkgpart );
my %svc_acct = ();
foreach my $field ( @fields ) {
# -cal this section is ignored by the 810 import
$transaction810_data{$field} = shift @columns;
}
# initialize the column 'ack_997' to 0 (not yet sent ack)
$transaction810_data{'ack_997'} = 0;
# initialize the column 'processed' to 0 (not process yet)
$transaction810_data{'processed'} = 0;
print Dumper(\%transaction810_data) if $debug;
#return ("done\n");
### check to see if the invoice is already in transaction810 table
# if so then print a warning
my $inv_num = $transaction810_data{'inv_num'};
my $search_res = qsearchs ( 'transaction810',
{'inv_num' => $inv_num}
);
if ( $search_res ) {
###
#place some code to fix this problem here
#
print "$line\n";
print "OOps! a transaction with invoice number "
."$transaction810_data{'inv_num'}\n"
."\t is in the table already!!\n";
}
else {
my $transaction810_obj = new FS::transaction810( \%transaction810_data );
$error = $transaction810_obj->insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "can't bill customer for $line: $error";
}
$imported++;
}
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
return "Empty file!" unless $imported;
''; #no error
}
=back
=head1 BUGS
The author forgot to customize this manpage.
=head1 SEE ALSO
L<FS::Record>, schema.html from the base documentation.
=cut
1;
Index: part_pkg.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/part_pkg.pm,v
retrieving revision 1.105
retrieving revision 1.105.2.1
diff -u -w -d -r1.105 -r1.105.2.1
--- part_pkg.pm 29 Jul 2010 23:11:31 -0000 1.105
+++ part_pkg.pm 2 Aug 2010 19:49:19 -0000 1.105.2.1
@@ -1418,6 +1418,7 @@
warn "no %info hash found in FS::part_pkg::$mod, skipping\n";
next;
}
+
warn "got plan info from FS::part_pkg::$mod: $info\n" if $DEBUG;
if ( exists($info->{'disabled'}) && $info->{'disabled'} ) {
warn "skipping disabled plan FS::part_pkg::$mod" if $DEBUG;
@@ -1433,7 +1434,15 @@
keys %info;
sub plan_info {
- \%plans;
+ my $conf = new FS::Conf;
+ return \%plans unless $conf->exists('svc_elec_features');
+
+ tie my %result, 'Tie::IxHash',
+ map { $_ => $plans{$_} }
+ grep { $plans{$_}{svc_elec_compatible} }
+ keys %plans;
+
+ \%result;
}
--- NEW FILE: transaction867.pm ---
package FS::transaction867;
use strict;
use vars qw( @ISA @EXPORT_OK );
use FS::Record qw( qsearch qsearchs );
use FS::UID qw( getotaker dbh );
use Exporter;
use Data::Dumper;
@ISA = qw(FS::Record);
@EXPORT_OK = qw(batch_867data_import);
=head1 NAME
FS::transaction867 - Object methods for transaction867 records
=head1 SYNOPSIS
use FS::transaction867;
$record = new FS::transaction867 \%hash;
$record = new FS::transaction867 { 'column' => 'value' };
$error = $record->insert;
$error = $new_record->replace($old_record);
$error = $record->delete;
$error = $record->check;
=head1 DESCRIPTION
An FS::transaction867 object represents an example. FS::transaction867 inherits from
FS::Record. The following fields are currently supported:
=over 4
=item id - primary key
=item tdsp_duns -
=item ref_identification -
=item esiid -
=item trans_creation_date -
=item meter_no -
=item srvc_period_start_date -
=item srvc_period_end_date -
=item prev_read_kwatts -
=item curr_read_kwatts -
=item meter_multiplier -
=item usage_kwatts -
=item measured_demand -
=item ack_997 -
=item processed -
=back
=head1 METHODS
=over 4
=item new HASHREF
Creates a new example. To add the example 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
# the new method can be inherited from FS::Record, if a table method is defined
sub table { 'transaction867'; }
=item insert
Adds this record to the database. If there is an error, returns the error,
otherwise returns false.
=cut
# the insert method can be inherited from FS::Record
=item delete
Delete this record from the database.
=cut
# the delete method can be inherited from FS::Record
=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.
=cut
# the replace method can be inherited from FS::Record
=item check
Checks all fields to make sure this is a valid example. If there is
an error, returns the error, otherwise returns false. Called by the insert
and replace methods.
=cut
# the check method should currently be supplied - FS::Record contains some
# data checking routines
sub check {
my $self = shift;
my $error =
$self->ut_numbern('id')
|| $self->ut_number('tdsp_duns')
|| $self->ut_text('ref_identification')
|| $self->ut_text('esiid')
|| $self->ut_number('trans_creation_date')
|| $self->ut_text('meter_no')
|| $self->ut_number('srvc_period_start_date')
|| $self->ut_number('srvc_period_end_date')
|| $self->ut_float('prev_read_kwatts')
|| $self->ut_float('curr_read_kwatts')
|| $self->ut_float('meter_multiplier')
|| $self->ut_float('usage_kwatts')
|| $self->ut_floatn('measured_demand')
|| $self->ut_number('ack_997')
|| $self->ut_number('processed')
;
return $error if $error;
$self->SUPER::check;
}
=item batch_867data_import
Importing a CVS file with the following column:
867_usage esiid date meter srvc_from_date srvc_to_date previous_read_kwatts
current_read_kwatts mult usage_kwatts measure_demand 997_ack
=cut
#@EXPORT_OK=qw(batch_867data_import);
sub batch_867data_import {
#my $param = shift;
my ($fh,$format) = @_;
# print "\n\n****************** the cvs file\n\n";
# print (<$fh>);
# print ("\n$format\n");
# return "done\n";
#my $fh = $param->{filehandle};
#my $format = $param->{'format'};
my $error;
my $debug = 0;
my @fields;
if ( $format eq 'extended' ) {
@fields = qw(
tdsp_duns ref_identification esiid trans_creation_date
meter_no srvc_period_start_date srvc_period_end_date
prev_read_kwatts curr_read_kwatts meter_multiplier
usage_kwatts measured_demand ack_997 processed
);
} else {
die "unknown format $format";
}
eval "use Text::CSV_XS;";
die $@ if $@;
my $csv = new Text::CSV_XS;
#warn $csv;
#warn $fh;
my $imported = 0;
#my $columns;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
local $SIG{PIPE} = 'IGNORE';
my $oldAutoCommit = $FS::UID::AutoCommit;
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
#while ( $columns = $csv->getline($fh) ) {
my $line;
while ( defined($line=<$fh>) ) {
$csv->parse($line) or do {
$dbh->rollback if $oldAutoCommit;
return "can't parse: ". $csv->error_input();
};
my @columns = $csv->fields();
#warn join('-', at columns);
# this hash will hold each CVS line
my %transaction867_data;
my $billtime = time;
# my %cust_pkg = ( pkgpart => $pkgpart );
my %svc_acct = ();
foreach my $field ( @fields ) {
# -cal this section is ignored by the 867 import
$transaction867_data{$field} = shift @columns;
}
# make sure to set the 'ack_997' column
$transaction867_data{'ack_997'} = 0;
# make sure to set the 'processed' column
$transaction867_data{'processed'} = 0;
print Dumper(\%transaction867_data) if $debug;
### Check to see if the invoice is already in transaction810 table
# if so then print a warning
my $ref_identification = $transaction867_data{'ref_identification'};
my $search_res = qsearchs ( 'transaction867',
{'ref_identification' => $ref_identification}
);
if ($search_res) {
###
# place some code here to fix the problme of trying to insert
# data that have the same references identification number
print "$line\n";
print "OOps! a transaction with the same references identification"
." number $ref_identification\n"
."\tis in the transaction867 table already!!\n";
}
else {
my $transaction867_obj = new FS::transaction867( \%transaction867_data );
$error = $transaction867_obj->insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "can't bill customer for $line: $error";
}
$imported++;
}
} #end while
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
return "Empty file!" unless $imported;
''; #no error
}
=back
=head1 BUGS
The author forgot to customize this manpage.
=head1 SEE ALSO
L<FS::Record>, schema.html from the base documentation.
=cut
1;
Index: cust_main.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_main.pm,v
retrieving revision 1.527
retrieving revision 1.527.2.1
diff -u -w -d -r1.527 -r1.527.2.1
--- cust_main.pm 28 Jul 2010 23:16:29 -0000 1.527
+++ cust_main.pm 2 Aug 2010 19:49:18 -0000 1.527.2.1
@@ -22,6 +22,7 @@
use Tie::IxHash;
use Digest::MD5 qw(md5_base64);
use Date::Format;
+use Date::Parse;
#use Date::Manip;
use File::Temp qw( tempfile );
use String::Approx qw(amatch);
@@ -71,6 +72,10 @@
use FS::payment_gateway;
use FS::agent_payment_gateway;
use FS::banned_pay;
+use FS::transaction810;
+use FS::transaction867;
+use FS::usage_elec;
+use FS::usage_elec_transaction867;
use FS::TicketSystem;
@EXPORT_OK = qw( smart_search );
@@ -2204,6 +2209,9 @@
# This should be generalized to use config options to determine order.
sub sort_packages {
+ return $a->pkgnum <=> $b->pkgnum
+ if $conf->exists('svc_elec_features');
+
my $locationsort = ( $a->locationnum || 0 ) <=> ( $b->locationnum || 0 );
return $locationsort if $locationsort;
@@ -2873,6 +2881,9 @@
my %cust_bill_pkg = map { $_ => [] } @passes;
+ # some values we may need for elec billing
+ my $elec_hash = { 'pkgnum' => 0, 'rate' => 0, 'detail' => ' ' };
+
###
# find the packages which are due for billing, find out how much they are
# & generate invoice database.
@@ -2881,14 +2892,22 @@
my %total_setup = map { my $z = 0; $_ => \$z; } @passes;
my %total_recur = map { my $z = 0; $_ => \$z; } @passes;
+ ###
+ # XXX this looks to be redundant in that we have cust_pkg_discount
+ # and cust_bill_pkg_discount which should be able to factor this out
+ ###
+ my %total_discount = map { my $z = 0; $_ => \$z; } @passes;
+
my %taxlisthash = map { $_ => {} } @passes;
my @precommit_hooks = ();
$options{'pkg_list'} ||= [ $self->ncancelled_pkgs ]; #param checks?
+ $options{'elec_hash'} = $elec_hash;
foreach my $cust_pkg ( @{ $options{'pkg_list'} } ) {
next if $options{'not_pkgpart'}->{$cust_pkg->pkgpart};
+ next if $conf->exists('svc_elec_features') && $cust_pkg->susp; # eh?
warn " bill package ". $cust_pkg->pkgnum. "\n" if $DEBUG > 1;
@@ -2914,6 +2933,7 @@
'line_items' => $cust_bill_pkg{$pass},
'setup' => $total_setup{$pass},
'recur' => $total_recur{$pass},
+ 'discount' => $total_discount{$pass},
'tax_matrix' => $taxlisthash{$pass},
'time' => $time,
'real_pkgpart' => $real_pkgpart,
@@ -2928,6 +2948,63 @@
} #foreach my $cust_pkg
+
+ my $average_price = 0;
+ my $total_recur = 0; $total_recur += ${ $total_recur{$_} } foreach @passes;
+ $average_price = $total_recur/$elec_hash->{energy_usage}
+ if $elec_hash->{energy_usage};
+
+ my $round4 = sub { int( shift() * 10000 + .5 ) / 10000 }; #very weird
+ $elec_hash->{average_price} = &$round4($average_price);
+ $elec_hash->{balance} = $self->balance;
+ $elec_hash->{last_pay} = 0;
+ $elec_hash->{last_pay_date} = 0;
+
+ # XXX this is a roundabout way to get this info on the invoice
+ my $last_payment = qsearchs({
+ 'table' => 'cust_pay',
+ 'hashref' => { 'op' => '=',
+ 'custnum' => $self->custnum,
+ },
+ 'extra_sql' => 'ORDER BY _date DESC',
+ });
+
+ if (defined($last_payment)) {
+ $elec_hash->{last_pay} = $last_payment->paid;
+ $elec_hash->{last_pay_date} = $last_payment->date;
+ }
+
+ # XXX whoa
+ my $returnaddress;
+ if ( length($conf->config_orbase('invoice_latexreturnaddress')) ) {
+ $returnaddress = join("\n", $conf->config_orbase('invoice_latexreturnaddress'));
+ } else {
+ $returnaddress = '~';
+ }
+ $elec_hash->{returnaddress} = $returnaddress;
+
+ # XXX again? need to get rid of this loop
+ if ($conf->exists('svc_elec_features')) {
+ foreach my $cust_pkg ($self->ncancelled_pkgs) {
+ next if $cust_pkg->susp;
+ next unless $cust_pkg->bill;
+
+ my @svc_external = grep { $_->title =~ /esiid/i }
+ grep { ref($_) eq 'FS::svc_external' }
+ map { $_->svc_x }
+ $cust_pkg->cust_svc;
+ next unless @svc_external;
+ my $rate = $svc_external[0]->cust_svc->cust_pkg->part_pkg->option('rate');
+ $elec_hash->{rate} = $rate unless $elec_hash->{rate};
+ $elec_hash->{pkg_info} =
+ $svc_external[0]->cust_svc->cust_pkg->part_pkg->pkg;
+ $elec_hash->{esiid} = $svc_external[0]->id;
+ my $transaction867 =
+ qsearchs('transaction867', {'esiid' => $elec_hash->{esiid} });
+ $elec_hash->{meter_number} = $transaction867->meter_no if $transaction867;
+ }
+ }
+
#if the customer isn't on an automatic payby, everything can go on a single
#invoice anyway?
#if ( $cust_main->payby !~ /^(CARD|CHEK)$/ ) {
@@ -2965,6 +3042,7 @@
'line_items' => \@cust_bill_pkg,
'setup' => $total_setup{$pass},
'recur' => $total_recur{$pass},
+ 'discount' => $total_discount{$pass},
'tax_matrix' => $taxlisthash{$pass},
'time' => $time,
'real_pkgpart' => $real_pkgpart,
@@ -2988,11 +3066,15 @@
return $listref_or_error;
}
+ my $total_tax = 0; # per pass?
foreach my $taxline ( @$listref_or_error ) {
${ $total_setup{$pass} } =
sprintf('%.2f', ${ $total_setup{$pass} } + $taxline->setup );
+ $total_tax = sprintf('%.2f', $total_tax + $taxline->setup );
push @cust_bill_pkg, $taxline;
}
+ $elec_hash->{taxes} = $total_tax;
+
#add tax adjustments
warn "adding tax adjustments...\n" if $DEBUG > 2;
@@ -3022,7 +3104,7 @@
}
- my $charged = sprintf('%.2f', ${ $total_setup{$pass} } + ${ $total_recur{$pass} } );
+ my $charged = sprintf('%.2f', ${ $total_setup{$pass} } + ${ $total_recur{$pass} } - ${ $total_discount{$pass} });
my @cust_bill = $self->cust_bill;
my $balance = $self->balance;
@@ -3050,6 +3132,16 @@
return "can't create invoice for customer #". $self->custnum. ": $error";
}
+ if ( $conf->exists('svc_elec_features') ) {
+ my $pkgnum = delete($elec_hash->{pkgnum});
+ my $cust_bill_pkg_detail = new FS::cust_bill_pkg_detail $elec_hash;
+ foreach my $cust_bill_pkg( @cust_bill_pkg ) {
+ next unless $cust_bill_pkg->pkgnum == $pkgnum;
+ push @{$cust_bill_pkg->get('details')}, $cust_bill_pkg_detail;
+ last;
+ }
+ }
+
foreach my $cust_bill_pkg ( @cust_bill_pkg ) {
$cust_bill_pkg->invnum($cust_bill->invnum);
my $error = $cust_bill_pkg->insert;
@@ -3262,6 +3354,7 @@
my $cust_bill_pkgs = $params{line_items} or die "no line buffer specified";
my $total_setup = $params{setup} or die "no setup accumulator specified";
my $total_recur = $params{recur} or die "no recur accumulator specified";
+ my $total_discount = $params{discount} or die "no discount accumulator specified";
my $taxlisthash = $params{tax_matrix} or die "no tax accumulator specified";
my $time = $params{'time'} or die "no time specified";
my (%options) = %{$params{options}};
@@ -3270,6 +3363,7 @@
my $real_pkgpart = $params{real_pkgpart};
my %hash = $cust_pkg->hash;
my $old_cust_pkg = new FS::cust_pkg \%hash;
+ my $elec_hash = $options{elec_hash};
my @details = ();
my @discounts = ();
@@ -3314,6 +3408,25 @@
$cust_pkg->setfield('start_date', '')
if $cust_pkg->start_date;
+ if ( $setup != 0 ) {
+ my $value = $elec_hash->{one_time_charge} || 0;
+ my $string = $elec_hash->{one_time_description} || '';
+ $string = '/'. $string if $string;
+ $elec_hash->{one_time_charge} = sprintf('%.2f', $setup+$value);
+ ### or should we be using $part_pkg below?
+ $elec_hash->{one_time_description} = $cust_pkg->part_pkg->pkg. $string;
+ } else {
+ $elec_hash->{setup_fee} = $setup;
+ }
+ }
+
+ my $is_energypkg;
+ if ( $conf->exists('svc_elec_features') ) {
+ $is_energypkg = 1
+ if grep { $_->title =~ /esiid/i }
+ grep { ref($_) eq 'FS::svc_external' }
+ map { $_->svc_x }
+ $cust_pkg->cust_svc;
}
###
@@ -3324,10 +3437,13 @@
my $recur = 0;
my $unitrecur = 0;
my $sdate;
+ my $testdate = $conf->exists('svc_elec_features')
+ ? ( $cust_pkg->getfield('last_bill') || 0 )
+ : ( $cust_pkg->getfield('bill') || 0 );
if ( ! $cust_pkg->get('susp')
and ! $cust_pkg->get('start_date')
and ( $part_pkg->getfield('freq') ne '0'
- && ( $cust_pkg->getfield('bill') || 0 ) <= $time
+ && $testdate <= $time
)
|| ( $part_pkg->plan eq 'voip_cdr'
&& $part_pkg->option('bill_every_call')
@@ -3365,9 +3481,53 @@
return "$@ running $method for $cust_pkg\n"
if ( $@ );
+ if ($recur != 0) {
+ my $lastbilldate = $cust_pkg->last_bill || 0;
+
+ if ($is_energypkg) {
+ my $vrate = $cust_pkg->part_pkg->option('vrate', 'quiet');
+ my $rate = $cust_pkg->part_pkg->option('rate');
+ my %var_rate;
+ if ($vrate) {
+ foreach my $rate_frame ( split(';',$vrate) ) {
+ my ($period, $period_rate) = split(':', $rate_frame);
+ my ($yr,$mo) = split('-',$period);
+ $var_rate{$yr}{$mo} = $period_rate;
+ }
+ my @cust_svc = grep { $_->title =~ /esiid/ }
+ map { $_->svc_x }
+ $cust_pkg->cust_svc('svc_external');
+ my $cust_svc = $cust_svc[0] if @cust_svc;
+ # XXX ok: these lines are clearly bunk as they return the empty list
+ my @usage_elecs =
+ qsearch( 'usage_elec',
+ { 'svcnum' => $cust_svc->svcnum,
+ '_date' => { op => '>', 'value' => $lastbilldate },
+ 'extra_sql' => 'ORDER BY _date_',
+ }
+ );
+ if(defined($usage_elecs[0])) {
+ my $usage_enddate_year =
+ time2str('%Y', $usage_elecs[0]->curr_date);
+ my $usage_enddate_month =
+ time2str('%m', $usage_elecs[0]->curr_date);
+ $rate = $var_rate{$usage_enddate_year}{$usage_enddate_month}
+ if exists($var_rate{$usage_enddate_year}{$usage_enddate_month});
+ }
+ }
+
+ $elec_hash->{rate} = $rate;
+
+ $elec_hash->{discount1_rate} =$part_pkg->option('rate1_discount');
+ }
+ }
+
if ( $increment_next_bill ) {
- my $next_bill = $part_pkg->add_freq($sdate);
+ # this is probably better handled differently than svc_elect_feature
+ # is this a recur_temporality issue?
+ my $next_bill =
+ $part_pkg->add_freq($conf->exists('svc_elec_feature') ? $time : $sdate);
return "unparsable frequency: ". $part_pkg->freq
if $next_bill == -1;
@@ -3408,6 +3568,9 @@
if $error; #just in case
}
+ $cust_pkg->last_bill($time)
+ if $conf->exists('svc_elec_features') && $part_pkg->option('rate');
+
$setup = sprintf( "%.2f", $setup );
$recur = sprintf( "%.2f", $recur );
if ( $setup < 0 && ! $conf->exists('allow_negative_charges') ) {
@@ -3451,6 +3614,29 @@
#$cust_bill_pkg->edate( $time ) if $options{cancel};
}
+ if ($conf->exists('svc_elec_features')) {
+ if( $recur != 0 ){
+ my $cust_svc=qsearchs('cust_svc',{'pkgnum' => $cust_pkg->pkgnum});
+
+ if ($is_energypkg) {
+ my $lastbilldate = $cust_pkg->last_bill || 0;
+ my $usage_elec = qsearchs ({
+ 'table' => 'usage_elec',
+ 'hashref' => { 'svcnum' => $cust_svc->svcnum,
+ '_date' => { 'op' => '>',
+ 'value' => $lastbilldate,
+ },
+ },
+ 'extra_sql' => 'ORDER BY _date'
+ });
+ if ($usage_elec) {
+ $cust_bill_pkg->sdate($usage_elec->prev_date);
+ $cust_bill_pkg->edate($usage_elec->curr_date);
+ }
+ }
+ }
+ }
+
$cust_bill_pkg->pkgpart_override($part_pkg->pkgpart)
unless $part_pkg->pkgpart == $real_pkgpart;
@@ -3471,6 +3657,99 @@
} #if $line_items
+ # logically here? might need to be before taxes?
+ if ($is_energypkg) {
+ if($recur != 0 and $cust_pkg->pkgnum) {
+ my $vrate = $cust_pkg->part_pkg->option('vrate', 'quiet');
+ my $pkg_rate = $cust_pkg->part_pkg->option('rate');
+ my %var_rate;
+
+ # a bit of extra bunk
+ my $cust_svc=qsearchs('cust_svc',{'pkgnum' => $cust_pkg->pkgnum});
+ my $lastbilldate = $cust_pkg->last_bill || 0;
+
+ if ($vrate) {
+ foreach my $rate_frame ( split(';',$vrate) ) {
+ my ($period, $period_rate) = split(':', $rate_frame);
+ my ($yr,$mo) = split('-',$period);
+ $var_rate{$yr}{$mo} = $period_rate;
+ }
+ # XXX ok: these lines are clearly bunk as they return the empty list
+ my @usage_elecs =
+ qsearch( 'usage_elec',
+ { 'svcnum' => $cust_svc->svcnum,
+ '_date' => { op => '>', 'value' => $lastbilldate },
+ 'extra_sql' => 'ORDER BY _date_',
+ }
+ );
+ if(defined($usage_elecs[0])) {
+ my $usage_enddate_year =
+ time2str('%Y', $usage_elecs[0]->curr_date);
+ my $usage_enddate_month =
+ time2str('%m', $usage_elecs[0]->curr_date);
+ $pkg_rate = $var_rate{$usage_enddate_year}{$usage_enddate_month}
+ if exists($var_rate{$usage_enddate_year}{$usage_enddate_month});
+ }
+ }
+ $elec_hash->{rate} = $pkg_rate unless $elec_hash->{rate};
+ my $late_fee = $part_pkg->option('penalty') || 0;
+ my $pkg_gr_fee = $part_pkg->option('gr_fee') || 0;
+ my $pkg_basic_fee = $part_pkg->option('base_fee') || 0;
+ $elec_hash->{'pkgnum'} = $cust_pkg->pkgnum;
+ my $usage_elec = qsearchs({
+ 'table' => 'usage_elec',
+ 'hashref' => { 'svcnum' => $cust_svc->svcnum,
+ '_date' => { 'op' => '>', 'value' => $lastbilldate },
+ },
+ 'extra_sql' => 'ORDER BY _date',
+ });
+ if ($usage_elec) {
+ my $usage_elec_transaction867 =
+ qsearchs( 'usage_elec_transaction867',
+ {'usage_elec_id' => $usage_elec->id}
+ );
+ $elec_hash->{note} = $usage_elec_transaction867->note
+ if $usage_elec_transaction867;
+
+ my $usagefromelec = $usage_elec->getUsage;
+
+ my $round = sub { sprintf('%.2f', int( shift() * 100 + .5 ) / 100) };
+ if ( $elec_hash->{discount1_rate} ) {
+ $elec_hash->{discount1_total} =
+ &$round($elec_hash->{discount1_rate} * $usagefromelec);
+ $$total_discount += $elec_hash->{discount1_total};
+ }
+
+ my $charge = &$round($usagefromelec * $pkg_rate);
+ $elec_hash->{meter_number} = $usage_elec->meter_number;
+ $elec_hash->{energy_base} = sprintf('%.2f', $pkg_basic_fee);
+ $elec_hash->{energy_charge} =
+ sprintf('%.2f', $usagefromelec * $elec_hash->{rate});
+ $elec_hash->{tdsp} = $usage_elec->tdsp;
+ $elec_hash->{number_of_days} = $usage_elec->getNumberOfDays;
+ $elec_hash->{energy_usage} = $usagefromelec;
+ $elec_hash->{demanded_bill} = $usage_elec->billed_demand;
+ $elec_hash->{measured_bill} = $usage_elec->measured_demand;
+ $elec_hash->{meter_multiplier} = $usage_elec->meter_multiplier;
+
+ $elec_hash->{balance} = 0;
+ my $thistdsp = $usage_elec->tdsp;
+ $elec_hash->{gr_fee} =
+ sprintf('%.2f', ($charge+$thistdsp+$pkg_basic_fee) * $pkg_gr_fee);
+ $elec_hash->{last_pay} = 0;
+ $elec_hash->{last_pay_date} = 0;
+ $elec_hash->{taxes} = 0;
+ $elec_hash->{prev_date} = $usage_elec->prev_date;
+ $elec_hash->{curr_date} = $usage_elec->curr_date;
+ $elec_hash->{prev_read} = $usage_elec->prev_read;
+ $elec_hash->{curr_read} = $usage_elec->curr_read;
+ $late_fee = $late_fee * # a rate i guess
+ sprintf('%.2f', ($charge+$thistdsp+$pkg_basic_fee+$elec_hash->{gr_fee}));
+ $elec_hash->{late_fee} = $late_fee;
+ }
+ }
+ }
+
'';
}
@@ -8740,7 +9019,12 @@
}
if ( $row{'amount'} > 0 ) {
- my $error = $cust_main->charge($row{'amount'}, $row{'pkg'});
+ my @args = ();
+ if (exists($row{taxclass})){
+ push @args, sprintf("\$%.2f", $row{amount});
+ push @args, $row{taxclass};
+ }
+ my $error = $cust_main->charge($row{'amount'}, $row{'pkg'}, @args);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
@@ -9098,6 +9382,490 @@
$cust_main->bill_and_collect( %$param );
}
+# This import script was written to import old OnPAC customer from the
+# previous billing database into freeside
+# coder: Cal Tran
+# dob: 3/20/06
+
+=item batch_import_onp
+
+=cut
+
+sub batch_import_onp {
+ my $param = shift;
+ #warn join('-',keys %$param);
+ my $fh = $param->{filehandle};
+ my $agentnum = $param->{agentnum};
+
+ my $refnum = $param->{refnum};
+ my $pkgpart = $param->{pkgpart};
+
+ my $debug = 1;
+ #my @fields = @{$param->{fields}};
+ my $format = $param->{'format'};
+ my (@fields, @incoming_fields);
+ my $payby;
+ if ( $format eq 'simple' ) {
+ @fields = qw( cust_pkg.setup dayphone first last
+ address1 address2 city state zip comments );
+ $payby = 'BILL';
+ } elsif ( $format eq 'extended' ) {
+ @fields = qw( agent_custid refnum
+ last first address1 address2 city state zip country
+ daytime night
+ ship_last ship_first ship_address1 ship_address2
+ ship_city ship_state ship_zip ship_country
+ payinfo paycvv paydate
+ invoicing_list
+ cust_pkg.pkgpart
+ svc_acct.username svc_acct._password
+ );
+ @incoming_fields = qw( custnum
+ name address1 address2 citystate zip
+ ss
+ daytime night
+ ship_name ship_address1 ship_address2
+ ship_citystate ship_zip
+ newcustdate
+ );
+ # mapping notes of incoming_field
+ # legend: incoming_field = field
+ # *custnum - this is not map to any of the original field
+ # name = last, first
+ # address1 = address1
+ # address2 = address2
+ # citystate = city state
+ # zip = zip
+ # ss - this is not map to any of the original field
+ # daytime = daytime
+ # night = night
+ # ship_name = ship_last, ship_first
+ # ship_address1 = ship_address1
+ # ship_address2 = ship_address2
+ # ship_citystate = ship_city ship_state
+ # ship_zip = ship_zip
+ # * newcustdate - this is not map to any of the original field
+
+ $payby = 'BILL';
+
+ } else {
+ die "unknown format $format";
+ }
+
+ eval "use Text::CSV_XS;";
+ die $@ if $@;
+
+ my $csv = new Text::CSV_XS;
+ #warn $csv;
+ #warn $fh;
+
+ my $imported = 0;
+ #my $columns;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ #while ( $columns = $csv->getline($fh) ) {
+ my $line;
+ while ( defined($line=<$fh>) ) {
+
+ $csv->parse($line) or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't parse: ". $csv->error_input();
+ };
+
+ my @columns = $csv->fields();
+ my $inpstr = $debug ? join ('|', at columns) : '';
+ #warn join('-', at columns);
+
+ my %cust_main = (
+ agentnum => $agentnum,
+ refnum => 1,
+ country => $conf->config('countrydefault') || 'US',
+ daytime =>'',
+ night =>'',
+ ship_country => $conf->config('countrydefault') || 'US',
+ payby => $payby, #default
+ paydate => '12/2037', #default
+ );
+ my $billtime = time;
+ my %cust_pkg = ( pkgpart => $pkgpart );
+ my %svc_acct = ();
+
+ # getting rid of all leading and trailing spaces
+ foreach my $value (@columns) {
+ $value =~ s/^\s*(.*?)\s*$/$1/;
+ }
+
+ foreach my $field ( @incoming_fields ) {
+
+ if ($field eq 'custnum') {
+ ### verify custnum correctness
+ my $cn = $columns[0];
+ # note: If the custnum is null, then we are assuming that
+ # the custnum is fill in from the system
+ next if !$cn;
+
+ return "error: custnum '$cn' need to be a 9 digit number.<br>$inpstr"
+ if ($cn !~ /^\d{9}$/);
+
+ return "error: custnum '$cn' must start with a 9 or 1.<br>$inpstr"
+ if ($cn !~ /^(1|9)/);
+
+ $cust_main{$field} = shift @columns;
+ }
+ elsif ( $field =~ /^(name|ship_name)$/ ) {
+ my ($last,$first) = split (/,/,$columns[0]);
+ $last =~ s/\s*$//; # remove trailing spaces
+ $first =~ s/^\s*//; # remove leading spaces
+
+ if ($field eq 'name') {
+ $cust_main{'last'} = $last;
+ $cust_main{'first'} = $first;
+ }
+ else {
+ $cust_main{'ship_last'} = $last;
+ $cust_main{'ship_first'} = $first;
+ }
+
+ shift @columns;
+
+ }
+ elsif ($field =~ /^(citystate|ship_citystate)$/) {
+
+ #if ( $columns[0] =~ /(.*?)\s([a-zA-Z]{2})$/ ) { #use for any state
+ if ( $columns[0] =~ /(.*)\s(TX)$/i ) { # TX only
+ my ($city,$state) = (uc $1,uc $2);
+ $city =~ s/\s*$//; # remove trailing spaces
+
+ if ($field eq 'citystate') {
+ $cust_main{'city'} = $city;
+ $cust_main{'state'} = $state;
+ }
+ else {
+ $cust_main{'ship_city'} = $city;
+ $cust_main{'ship_state'} = $state;
+ }
+ }
+ else {
+ return "error: Field city_state '".$columns[0]."',don't match"
+ ." format 'city state'. I.E. SUGAR LAND TX"
+ ."<br>$inpstr";
+ }
+
+ shift @columns;
+
+ }
+ elsif ( $field =~ /^(zip|ship_zip)$/ ) {
+ if ( $columns[0] =~ /^(\d{5}|\d{9})$/ ) {
+ my $zipcode = $1;
+ # cludge. Because the system is not accepting a straight
+ # 9 digit zipcode. Need to have in format ddddd-dddd
+ $zipcode =~ s/^(\d{5})(\d{4})$/$1\-$2/;
+ $cust_main{$field} = $zipcode;
+ }
+ else {
+ return "error: Zip code '".$columns[0]."' need to be in the format "
+ ."of 5 digit or 9 digit. I.E. 75227 or 752271212"
+ ."<br>$inpstr";
+ }
+ shift @columns;
+ }
+ elsif ( $field eq 'ss' ) {
+ if ($columns[0]) { #ignore if blak
+ if ( $columns[0] =~ /^\d{9}$/ ) {
+ # verify social security number format
+ $cust_main{$field} = $columns[0];
+ }
+ else {
+ return "error: Social Security number ".$columns[0]."' need to be in"
+ ." the format of 9 digit. No dash or non digit character are"
+ ." allowed. I.E. 512342898"
+ ."<br>$inpstr";
+ }
+ }
+ shift @columns;
+ }
+ elsif ( $field =~ /^(daytime|night)$/ ) {
+ if ( $columns[0] ) { #ignore if blank
+ if ( $columns[0] =~ /^(\d{3})(\d{3})(\d{4})$/ ) {
+ # duplicate the ph # to service address too
+ $cust_main{$field} = $cust_main{"ship_$field"}= "$1\-$2\-$3";
+ }
+ else {
+ return "error: Phone number ".$columns[0]."' need to be in the format "
+ ."of 10 digit. No dash or non digit character are allowed."
+ ." I.E. 8179072171"
+ ."<br>$inpstr";
+ }
+ }
+ shift @columns;
+
+ }
+ elsif ( $field eq 'newcustdate' ) {
+
+ # string format coming in is in the form of m/d/yyyy
+ if ($columns[0] =~ /^\d{1,2}\/\d{1,2}\/\d{4}$/) {
+ my($month, $day, $year) = split(/\//,$columns[0]);
+
+ # pad month and day with a '0' if they are single digit
+ $month =~ s/^(\d)$/0$1/;
+ $day =~ s/^(\d)$/0$1/;
+
+ my $date = str2time("${year}${month}${day}");
+
+ $cust_main{'signupdate'} = $date;
+ }
+ else {
+ return "error: Time '".$columns[0]."' format is not correct."
+ ." Accepted format is m/d/yyyy i.e. 3/5/2002."
+ ."<br>$inpstr";
+ }
+ shift @columns;
+
+ }
+ else {
+ $cust_main{$field} = shift @columns;
+ }
+
+ } #foreach
+
+ my $cust_main = new FS::cust_main ( \%cust_main );
+
+ use Tie::RefHash;
+ tie my %hash, 'Tie::RefHash'; #this part is important
+
+ my $invoicing_list = [];
+ my $error = $cust_main->insert( \%hash, $invoicing_list );
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't insert customer for $line: $error";
+ }
+
+ if ( $format eq 'simple' ) {
+
+ #false laziness w/bill.cgi
+ $error = $cust_main->bill( 'time' => $billtime );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't bill customer for $line: $error";
+ }
+
+ $cust_main->apply_payments;
+ $cust_main->apply_credits;
+
+ $error = $cust_main->collect();
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't collect customer for $line: $error";
+ }
+
+ }
+
+ $imported++;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ return "Empty file!" unless $imported;
+
+ ''; #no error
+
+} # sub batch_import_onp
+
+
+# This import script was written to import and process 810 & 867 edi
+# data for customer
+# coder: Cal Tran
+# dob: 3/11/08
+
+=item batch_edidata_onp
+
+=cut
+
+sub batch_edidata_onp {
+ my $param = shift;
+ #warn join('-',keys %$param);
+ my $fh = $param->{filehandle};
+ my $agentnum = $param->{agentnum};
+
+ my $refnum = $param->{refnum};
+ my $pkgpart = $param->{pkgpart};
+
+ my $debug = 1;
+ #my @fields = @{$param->{fields}};
+ my $format = $param->{'format'};
+ my (@fields, @incoming_fields);
+ my $payby;
+ if ( $format eq 'simple' ) {
+ @fields = qw( cust_pkg.setup dayphone first last
+ address1 address2 city state zip comments );
+ $payby = 'BILL';
+ }
+ elsif ( $format eq 'extended' ) {
+
+ }
+ else {
+ die "unknown format $format";
+ }
+
+ eval "use Text::CSV_XS;";
+ die $@ if $@;
+
+ my $csv = new Text::CSV_XS;
+ #warn $csv;
+ #warn $fh;
+
+ my $imported = 0;
+ #my $columns;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $dbh = dbh;
+ my $return_msg;
+
+ #while ( $columns = $csv->getline($fh) ) {
+ my $line;
+ while ( defined($line=<$fh>) ) {
+
+ $csv->parse($line) or do {
+ return "ERROR can't parse: ". $csv->error_input();
+ };
+
+ my @columns = $csv->fields();
+ my $inpstr = $debug ? join ('|', at columns) : '';
+ #warn join('-', at columns);
+
+ # getting rid of all leading and trailing spaces
+ foreach my $value (@columns) {
+ $value =~ s/^\s*(.*?)\s*$/$1/;
+ }
+
+ my $esiid = $columns[3];
+
+ ### check for matching of 810 usage and 867 usage
+ my $usage_match_810_867;
+ if ($columns[11] == $columns[31]) {
+ $usage_match_810_867 = 0;
+ }
+ else {
+ $usage_match_810_867 = 'FALSE';
+ };
+
+
+ my @svc_external = qsearch ( 'svc_external', { 'id' => $esiid } );
+
+ return "ERROR fail: No one own ESIID $esiid!" unless @svc_external;
+
+ my $cust_main;
+ my $cust_pkg;
+
+ foreach my $svcexternal (@svc_external) {
+ my $cust_svc = qsearchs ( 'cust_svc', { 'svcnum' => $svcexternal->svcnum} );
+ unless ($cust_svc) {
+ return "ERROR fail1";
+ }
+
+ $cust_pkg = qsearchs ( 'cust_pkg', { 'pkgnum' => $cust_svc->pkgnum} );
+ unless ($cust_pkg) {
+ return "ERROR fail2";
+ }
+
+ # don't process any package unless it is active
+ next if ($cust_pkg->status() ne "active");
+
+ $cust_main = qsearchs ( 'cust_main', { 'custnum' => $cust_pkg->custnum} );
+ unless ($cust_main) {
+ return "ERROR fail3";
+ #return "can't insert customer for $line: $error";
+ }
+
+ # don't process any customer that is not active
+ next if ($cust_main->status() ne "active");
+
+ my $svc_num = $svcexternal->svcnum;
+ my $firstname = $cust_main->first;
+ my $lastname = $cust_main->last;
+ my $custnum = $cust_main->custnum;
+ my $balance = $cust_main->balance;
+ my $lastbilled = time2str('%D',$cust_pkg->get('last_bill'));
+
+ # note - the empty column that is after $lastbilled is later used tostore
+ # the last reading from usage_elec
+ my $easy_view = join(',',$usage_match_810_867, $firstname, $lastname, $custnum,
+ $svc_num,$balance, $lastbilled,'--',
+ '**',
+ # 13-start date 14-end date 28-prev read 29-curr read
+ $columns[13], $columns[14], $columns[28],
+ # 29-curr read 6-tdsp
+ $columns[29], $columns[6],
+ # 30 - meter multiplier 31-867 usage 21-measured demand
+ $columns[30], $columns[31], $columns[21],
+ # 20 - billed demand
+ $columns[20], '','','',
+ '**',
+ @columns
+ );
+
+ if ($return_msg) {
+ $return_msg .= "\n$easy_view";
+ }
+ else {
+ $return_msg = "$easy_view";
+ }
+
+ } #foreach svc_external
+
+ }
+
+ return($return_msg);
+
+ ''; #no error
+
+} # sub batch_edidata_onp
+
+sub insert_test_value{
+ my $time = time;
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+ my $transaction810 = new FS::usage_elec({
+ 'prev_date'=>'1',
+ 'curr_date'=>'1',
+ 'prev_read'=>'1',
+ 'curr_read'=>'1',
+ 'tdsp'=>'1',
+ 'svcnum'=>'10',
+ 'meter_multiplier'=>'1',
+ 'measured_demand'=>'1',
+ 'billed_demand'=>'1',
+
+
+ });
+
+ my $error=$transaction810->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error applying prepaid card (transaction rolled back): $error";
+
+ }
+}
+
sub _upgrade_data { #class method
my ($class, %opts) = @_;
Index: Schema.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Schema.pm,v
retrieving revision 1.226
retrieving revision 1.226.2.1
diff -u -w -d -r1.226 -r1.226.2.1
--- Schema.pm 28 Jul 2010 23:16:29 -0000 1.226
+++ Schema.pm 2 Aug 2010 19:49:16 -0000 1.226.2.1
@@ -593,6 +593,38 @@
'phonenum', 'varchar', 'NULL', 15, '', '',
'regionname', 'varchar', 'NULL', $char_d, '', '',
'detail', 'varchar', '', 255, '', '',
+ # seems suboptimal to store below values here
+ 'prev_date','int','NULL','','0','',
+ 'curr_date','int','NULL','','0','',
+ 'prev_read','decimal','NULL','14,4','0','',
+ 'curr_read','decimal','NULL','14,4','0','',
+ 'number_of_days','int','NULL','','','',
+ 'energy_usage','decimal','NULL','14,4','','',
+ 'tdsp','decimal','NULL','10,2','0','',
+ 'taxes','decimal','NULL','10,2','','',
+ 'gr_fee','decimal','NULL','10,2','0','',
+ 'rate','decimal','NULL','10,6','','',
+ 'discount1_rate','decimal','NULL','10,6','','',
+ 'discount1_total','decimal','NULL','10,2','','',
+ 'energy_base','decimal','NULL','10,2','','',
+ 'energy_charge','decimal','NULL','10,2','','',
+ 'setup_fee','decimal','NULL','10,2','0','',
+ 'one_time_charge','decimal','NULL','10,2','0','',
+ 'one_time_description','varchar','NULL','150','','',
+ 'demanded_bill','decimal','NULL','14,4','0','',
+ 'measured_bill','decimal','NULL','14,4','0','',
+ 'meter_multiplier','real','NULL','','0','',
+ 'balance', at money_type,'0','',
+ 'average_price','decimal','NULL','10,4','0','',
+ 'pkg_info','varchar','NULL','255','','',
+ 'note','varchar','NULL','255','','',
+ 'meter_number','varchar','NULL','255','','',
+ 'esiid','varchar','NULL','255','','',
+ 'late_fee','decimal','NULL','14,4','0','',
+ 'last_pay', at money_type,'0','',
+ 'last_pay_date','int','NULL','','','',
+ 'return_addr','varchar','NULL',150,'','',
+ 'bill_return_address','varchar','NULL',150,'','',
],
'primary_key' => 'detailnum',
'unique' => [],
@@ -2188,7 +2220,7 @@
'svc_external' => {
'columns' => [
'svcnum', 'int', '', '', '', '',
- 'id', 'int', 'NULL', '', '', '',
+ 'id', 'varchar', 'NULL', $char_d, '', '',
'title', 'varchar', 'NULL', $char_d, '', '',
],
'primary_key' => 'svcnum',
@@ -2196,6 +2228,116 @@
'index' => [],
},
+ 'usage_elec_transaction867' => {
+ 'columns'=> [
+ 'id','serial','','','','',
+ 'usage_elec_id','serial','','','','',
+ 'note','varchar','NULL','255','','',
+ ],
+ 'primary_key'=> 'id',
+ 'unique' => [],
+ 'index'=>[['usage_elec_id']],
+ },
+
+ 'usage_elec' => {
+ 'columns' => [
+ 'id', 'serial', '', '', '', '',
+ 'prev_date', @date_type, '', '',
+ 'curr_date', @date_type,'','',
+ 'prev_read', 'decimal', '14,4', '', '', '',
+ 'curr_read', 'decimal', '14,4', '', '', '',
+ 'tdsp', @money_type, '', '',
+ 'meter_multiplier','real','','','','',
+ 'total_usage','decimal','14,4','','','',
+ 'measured_demand','decimal','14,4','','','',
+ 'billed_demand','decimal','14,4','','','',
+ 'svcnum', 'int', '', '', '', '',
+ '_date', at date_type,'','',
+ 'meter_number','varchar','255','','','',
+ ],
+ 'primary_key' => 'id',
+ 'unique' => [],
+ 'index' => [['svcnum']],
+ },
+
+# -nguyen
+ 'elec_general' => {
+ 'columns' => [
+ 'id', 'serial', '', '', '', '',
+ 'esiid','int','','','','',
+ ],
+ 'primary_key' => 'id',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'trading_rep_profile' => {
+ 'columns' => [
+ 'id', 'serial', '', '', '', '',
+ 'company_name', 'varchar', 'NULL', $char_d, '', '',
+ 'duns_num', 'int', '', '', '', '',
+ 'company_type', 'varchar', 'NULL', $char_d, '', '',
+ 'puct_license_num', 'int', '', '', '', '',
+ 'active', 'int', '', '', '', '',
+ 'start_date', @date_type, '', '',
+ 'end_date', @date_type, '', '',
+ ],
+ 'primary_key' => 'id',
+ 'unique' => [ ['duns_num'] ],
+ 'index' => [],
+ },
+
+
+ 'transaction810' => {
+ 'columns' => [
+ 'id', 'serial', '', '', '', '',
+ 'tdsp_duns', 'varchar', 'NULL', $char_d, '', '',
+ 'inv_num', 'varchar', 'NULL', $char_d, '', '',
+ 'ref_identification', 'varchar', 'NULL', $char_d, '', '',
+ 'esiid', 'varchar', 'NULL', $char_d, '', '',
+ 'tdsp', 'int', '', '', '', '',
+ 'due_date', 'int', '', '', '', '',
+ 'inv_date', 'int', '', '', '', '',
+ 'usage_kwatts', 'real', '', '', '', '',
+ 'srvc_from_date', 'int', '', '', '', '',
+ 'srvc_to_date', 'int', '', '', '', '',
+ 'puct_fund', 'int', '', '', '', '',
+ 'billed_demand', 'real', '', '', '', '',
+ 'measured_demand', 'real', 'NULL', '', '', '',
+ 'bill_status', 'char', '', 2, '', '',
+ 'type_of_bill', 'int', '', '', '', '', # bool 0/1
+ 'ack_997', 'int', '', '', '', '', # bool 0/1
+ 'processed', 'int', '', '', '', '', # bool 0/1
+ ],
+ 'primary_key' => 'id',
+ 'unique' => [ ['inv_num'] ],
+ 'index' => [ ['id'], ['tdsp_duns'], ['inv_num'], ['esiid'] ],
+ },
+
+ 'transaction867' => {
+ 'columns' => [
+ 'id', 'serial', '', '', '', '',
+ 'tdsp_duns', 'int', '', '', '', '',
+ 'ref_identification', 'varchar', '', $char_d, '', '',
+ 'esiid', 'varchar', '', $char_d, '', '',
+ 'trans_creation_date', 'int', '', '', '', '',
+ 'meter_no', 'varchar', '', $char_d, '', '',
+ 'srvc_period_start_date', 'int', '', '', '', '',
+ 'srvc_period_end_date', 'int', '', '', '', '',
+ 'prev_read_kwatts', 'real', '', '', '', '',
+ 'curr_read_kwatts', 'real', '', '', '', '',
+ 'meter_multiplier', 'real', '', '', '', '',
+ 'usage_kwatts', 'real', '', '', '', '',
+ 'measured_demand', 'real', 'NULL', '', '', '',
+ 'ack_997', 'int', '', '', '', '', # bool 0/1
+ 'processed', 'int', '', '', '', '', # bool 0/1
+ ],
+ 'primary_key' => 'id',
+ 'unique' => [ ['ref_identification'] ],
+ 'index' => [],
+ },
+
+
'cust_pay_refund' => {
'columns' => [
'payrefundnum', 'serial', '', '', '', '',
@@ -2844,6 +2986,21 @@
'index' => [ [ 'pkgnum' ], [ 'refnum' ] ],
},
+#-- nguyen
+ 'svc_elec' => {
+ 'columns' => [
+ 'id', 'serial', '', '', '', '',
+ 'esiid','int','','','','',
+ 'svcnum', 'int', '', '', '', '',
+ 'countrycode', 'varchar', '', 3, '', '',
+ 'phonenum', 'varchar', '', 15, '', '', #12 ?
+ 'pin', 'varchar', 'NULL', $char_d, '', '',
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [],
+ 'index' => [ [ 'countrycode', 'phonenum' ] ],
+ },
+
'svc_pbx' => {
'columns' => [
'svcnum', 'int', '', '', '', '',
--- NEW FILE: elec_general.pm ---
package FS::elec_general;
use strict;
use vars qw( @ISA );
use FS::Record qw( qsearch qsearchs );
@ISA = qw(FS::Record);
=head1 NAME
FS::elec_general - Object methods for elec_general records
=head1 SYNOPSIS
use FS::elec_general;
$record = new FS::elec_general \%hash;
$record = new FS::elec_general { 'column' => 'value' };
$error = $record->insert;
$error = $new_record->replace($old_record);
$error = $record->delete;
$error = $record->check;
=head1 DESCRIPTION
An FS::elec_general object represents an example. FS::elec_general inherits from
FS::Record. The following fields are currently supported:
=over 4
=item id - primary key
=item esiid -
=back
=head1 METHODS
=over 4
=item new HASHREF
Creates a new example. To add the example 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
# the new method can be inherited from FS::Record, if a table method is defined
sub table { 'elec_general'; }
=item insert
Adds this record to the database. If there is an error, returns the error,
otherwise returns false.
=cut
# the insert method can be inherited from FS::Record
=item delete
Delete this record from the database.
=cut
# the delete method can be inherited from FS::Record
=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.
=cut
# the replace method can be inherited from FS::Record
=item check
Checks all fields to make sure this is a valid example. If there is
an error, returns the error, otherwise returns false. Called by the insert
and replace methods.
=cut
# the check method should currently be supplied - FS::Record contains some
# data checking routines
sub check {
my $self = shift;
my $error =
$self->ut_numbern('id')
|| $self->ut_number('esiid')
;
return $error if $error;
$self->SUPER::check;
}
=back
=head1 BUGS
The author forgot to customize this manpage.
=head1 SEE ALSO
L<FS::Record>, schema.html from the base documentation.
=cut
1;
--- NEW FILE: usage_elec.pm ---
package FS::usage_elec;
use strict;
use vars qw( @ISA @EXPORT_OK $me);
use FS::Record qw( qsearch qsearchs );
use FS::UID qw( getotaker dbh );
use FS::usage_elec_transaction867;
#use FS::cust_main;
use Exporter;
use List::Util qw[min max];
use Date::Format;
use HTTP::Date qw( str2time );
use Data::Dumper;
use Date::Calc qw(Delta_Days);
@ISA = qw(FS::Record Exporter);
@EXPORT_OK = qw( most_current_date curr_read edi_to_usage );
=head1 NAME
FS::usage_elec - Object methods for usage_elec records
=head1 SYNOPSIS
use FS::usage_elec;
$record = new FS::usage_elec \%hash;
$record = new FS::usage_elec { 'column' => 'value' };
$error = $record->insert;
$error = $new_record->replace($old_record);
$error = $record->delete;
$error = $record->check;
=head1 DESCRIPTION
An FS::usage_elec object represents an example. FS::usage_elec inherits from
FS::Record. The following fields are currently supported:
=over 4
=item id - primary key
=item prev_date -
=item curr_date -
=item prev_read -
=item curr_read -
=item tdsp -
=item svcnum -
=item _date -
=back
=head1 METHODS
=over 4
=item new HASHREF
Creates a new example. To add the example 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
# the new method can be inherited from FS::Record, if a table method is defined
sub table { 'usage_elec'; }
=item insert
Adds this record to the database. If there is an error, returns the error,
otherwise returns false.
=cut
# the insert method can be inherited from FS::Record
=item delete
Delete this record from the database.
=cut
# the delete method can be inherited from FS::Record
=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.
=cut
# the replace method can be inherited from FS::Record
=item check
Checks all fields to make sure this is a valid example. If there is
an error, returns the error, otherwise returns false. Called by the insert
and replace methods.
=cut
# the check method should currently be supplied - FS::Record contains some
# data checking routines
sub check {
my $self = shift;
my $error =
$self->ut_numbern('id')
|| $self->ut_numbern('prev_date')
|| $self->ut_numbern('curr_date')
|| $self->ut_number('prev_read')
|| $self->ut_number('curr_read')
|| $self->ut_money('tdsp')
|| $self->ut_number('svcnum')
|| $self->ut_numbern('_date')
|| $self->ut_float('meter_multiplier')
|| $self->ut_numbern('demand_measure')
|| $self->ut_numbern('demand_bill')
;
return $error if $error;
$self->SUPER::check;
}
=back
=head1 BUGS
The author forgot to customize this manpage.
=head1 SEE ALSO
L<FS::Record>, schema.html from the base documentation.
=cut
sub most_current_date {
# my $self = shift;
my $cust_nr=shift;
my @custs = qsearch('usage_elec',{ 'cust_nr' => $cust_nr});
my $most_current_date = 0;
if (@custs) {
foreach my $cust (@custs) {
if ($cust->curr_date > $most_current_date){
$most_current_date = $cust;
}
}
}
return $most_current_date;
}
sub getUsage{
my $self = shift;
return $self->total_usage;
}
#sub getUsage{
# my $self = shift;
# my $prev_read=$self->prev_read;
# my $curr_read=$self->curr_read;
# my $usage;
# if ($prev_read<=$curr_read) {
# $usage= ($curr_read-$prev_read);
# }
# else{
# $usage=(($curr_read+10**max(length($prev_read),length($curr_read)))-$prev_read);
# }
# return $usage*$self->meter_multiplier;
#}
sub getNumberOfDays {
my $self = shift;
return Date::Calc::Delta_Days( time2str('%Y', $self->prev_date),
time2str('%L', $self->prev_date),
time2str('%e', $self->prev_date),
time2str('%Y', $self->curr_date),
time2str('%L', $self->curr_date),
time2str('%e', $self->curr_date)
);
}
### insert into table
#
sub insert_usage {
my $self = shift;
my $debug = 0;
my $error;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
local $SIG{PIPE} = 'IGNORE';
my $oldAutoCommit = $FS::UID::AutoCommit;
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
$error = $self->check;
return $error if $error;
$error = $self->SUPER::insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
my $msg = "error: Can't insert data into usage_elec : $error\n"
.Dumper($self);
return $msg;
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
return;
}
### Take in a time and convert it to time string to be entered into usage_elec
### the function use is str2time from module "HTTP::Date qw( str2time )"
sub to_usage_elec_time {
my ($time) = shift;
### becareful using time2str, year allows are 1970-jan2038
return str2time($time);
}
# Get the past 10 usage for a particular svcnum and return the object
# return:
# array of usages object
# undef otherwise
#
#
sub query_usage {
my ($svcnum, $how_many) = @_;
#$how_many = 10 unless $how_many; # default to 10 usages
# my @usages = qsearch (
# 'usage_elec',
# {
#
# 'svcnum' => $svcnum,
# # sort in DESCending order so it easier to splice
# # the array in the next step
# 'extra_sql' => 'ORDER BY _date DESC'
# }
# );
my @usages = qsearch ( {
'table' => 'usage_elec',
'hashref' => { 'svcnum' => $svcnum },
'extra_sql' => 'ORDER BY _date DESC'
} );
# shrink the array to $how_many index if it over the requested number
$#usages = $how_many - 1 if ( @usages && $how_many && (@usages > $how_many) );
if (@usages) {
# since we query the usage by DESCending order, it a good idea to put it
# in ascending order before a return.
@usages = reverse @usages;
return @usages;
}
return;
}
# sub routine that go through the transaction810 and transaction867 table
# to put data into usage_elec table
#
#
# some note
# to input data into usage_elect, all condition below must be meet
# 1. there is unprocess data from transaction810 table
# 2. there is unprocess data from transaction867 table
# 3. the unprocess data from transaction867 match transaction810
# data.
sub edi_to_usage {
my $self = shift;
my $debug = 1;
#my @invoices_to_generate; # store usage_elec svcnum
# Only send data to usage_elec if a transactin from 810 & 867 match up
#
# first thing first. Let get all edi from transaction_810 table that haven't
# been process
my @edi_810_processeds = qsearch (
'transaction810',
{'processed' => '0'}
);
unless (@edi_810_processeds) {
return "There were no un-process 810 to input into usage_elec.\n"
."Run again when there is 810 data to process\n";
}
# second, let get all edi from transaction_867 table that haven't been
# process
my @edi_867_processeds = qsearch (
'transaction867',
{'processed' => '0'}
);
unless (@edi_867_processeds) {
return "There were no un-process 867 to match up with 810 data.\n"
."Run again when there is 867 data to process\n";
}
# third, match up the 810 and 867 data. Those data that match up, goes
# into usage_elec table.
### for efficientcy we will use the smaller list to traverse
if (@edi_810_processeds < @edi_867_processeds) {
print "debug: using 810\n" if $debug;
foreach my $edi_810 (@edi_810_processeds) {
# find matching 867
my $ref_identification_810 = $edi_810->ref_identification;
my $srv_from_810 = $edi_810->srvc_from_date;
my $srv_to_810 = $edi_810->srvc_to_date;
### search for the edi that match exactly with the 810
my $edi_867 = qsearchs ( 'transaction867',
{ 'ref_identification' => $ref_identification_810,
'srvc_from_date' => $srv_from_810,
'srvc_to_date' => $srv_to_810,
}
);
if ($edi_867) {
### we have a match, extract the data and put into usage
my $usage_elec_obj = extract_data_to_usage_elec ($edi_810, $edi_867);
if ($usage_elec_obj) {
### mark the 810 and 867 as already process
$edi_810->setfield('processed',1);
$edi_867->setfield('processed',1);
### go ahead and billed
my $rtnval = billing_call($usage_elec_obj);
if ($rtnval) {
print "Oh! Oh!.. unable to bill svcnum: $usage_elec_obj->svcnum\n";
print $rtnval;
$edi_810->setfield('processed',0);
$edi_867->setfield('processed',0);
$usage_elec_obj->delete;
return;
}
}
else {
print "RED ALERT.. something went wrong when inserting data\n"
."into usage_elec (810)\n";
print "ref_identification of 810 : " . $edi_867->ref_identification
."\n";
return;
}
}
}
}
else {
print "debug: using 867\n" if $debug;
foreach my $edi_867 (@edi_867_processeds) {
# find matching 810
my $ref_identification_867 = $edi_867->ref_identification;
my $srv_from_867 = $edi_867->srvc_period_start_date;
my $srv_to_867 = $edi_867->srvc_period_end_date;
print "(debug) ref_identification: $ref_identification_867\n" if $debug;
### search for the edi that match exactly with the 867
my $edi_810 = qsearchs ( 'transaction810',
{ 'ref_identification' => $ref_identification_867,
'srvc_from_date' => $srv_from_867,
'srvc_to_date' => $srv_to_867,
}
);
if ($edi_810) {
print "(debug) found an 810 that match the 867: esiid "
.$edi_810->esiid."\n" if $debug;
### we have a match, extract the data and put into usage
my $usage_elec_obj = extract_data_to_usage_elec($edi_810, $edi_867);
if ($usage_elec_obj) {
### mark the 810 and 867 as already process
my $edi_810_new = new FS::transaction810( { $edi_810->hash } );
$edi_810_new->setfield('processed',1);
my $error = $edi_810_new->replace($edi_810);
if ($error) {
print "there is an error changing column 'processed' of transaction810 table\n";
print "error: $error\n";
}
my $edi_867_new = new FS::transaction867( { $edi_867->hash } );
$edi_867->setfield('processed',1);
$error = $edi_867_new->replace($edi_867);
if ($error) {
print "there is an error changing column 'processed' of transaction867 table\n";
print "error: $error\n";
}
### go ahead and billed
my $rtnval = billing_call($usage_elec_obj);
if ($rtnval) {
print "Oh! Oh!.. unable to bill svcnum: $usage_elec_obj->svcnum\n";
print "$rtnval";
$edi_810->setfield('processed',0);
$edi_867->setfield('processed',0);
$usage_elec_obj->delete;
return;
}
}
else {
print "RED ALERT.. something went wrong when inserting data\n"
."into usage_elec (810)\n";
print "ref_identification of 810 : " . $edi_810->ref_identification
."\n";
#return;
}
}
}
}
}
# This subroutine does the physical adding of data into usage_elec
# using the transaction810 and transaction867 table
sub extract_data_to_usage_elec {
my ($edi_810, $edi_867) = @_;
### variables declaration
### following decl are column of usage_elec
my ($prev_date, $curr_date, $prev_read, $curr_read, $tdsp, $svcnum, $_date,
$meter_multiplier, $total_usage, $measured_demand, $billed_demand,
$meter_number);
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
local $SIG{PIPE} = 'IGNORE';
my $oldAutoCommit = $FS::UID::AutoCommit;
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
### this message will print in the year 2038 because their is a limitation
# with str2time ( cpan.org package Icwa-1.0.0.tar.gz )
if ( int(time2str('%Y',time)) > 2037 ) {
print "Bug: Try to use function 'time2str' has generate an error because"
."\n\tit can't handle year greter than 2037.\n";
return;
}
# data from 867
$prev_date = str2time($edi_867->srvc_period_start_date);
$curr_date = str2time($edi_867->srvc_period_end_date);
$prev_read = $edi_867->prev_read_kwatts;
$curr_read = $edi_867->curr_read_kwatts;
$meter_multiplier = $edi_867->meter_multiplier;
$total_usage = $edi_867->usage_kwatts;
$measured_demand = $edi_867->measured_demand;
$meter_number = $edi_867->meter_no;
# data from 810
$tdsp = sprintf('%.2f',$edi_810->tdsp/100);
$billed_demand = $edi_810->billed_demand;
### obtain the svcnum
my $esiid = $edi_810->esiid;
my $svc_obj = qsearchs ( 'svc_external',
{ 'id' => $esiid
}
);
return unless ($svc_obj); #debug
$svcnum = $svc_obj->svcnum;
### obtain _date
$_date = time;
### got everything we needed
# now let insert it into usage_elec
my %usage = (
'prev_date' => $prev_date,
'curr_date' => $curr_date,
'prev_read' => $prev_read,
'curr_read' => $curr_read,
'tdsp' => $tdsp,
'svcnum' => $svcnum,
'_date' => $_date,
#'meter_multiplier' => $meter_multiplier,
'meter_multiplier' => $meter_multiplier,
'total_usage' => $total_usage,
'measured_demand' => $measured_demand,
'billed_demand' => $billed_demand,
'meter_number' => $meter_number,
);
print "usage_elect Dumping". Dumper(\%usage);
if ( $edi_810->esiid != '10443720004466311' &&
$edi_810->esiid != '10443720004264904') {
return; #for testing
}
my $usage_elec_obj = new FS::usage_elec( \%usage );
my $error = $usage_elec_obj->insert;
print "I'm inserting something into usage_elec\n";
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
my $msg = "Can't insert data into usage_elec : $error\n"
.Dumper(\%usage);
print "$msg";
return;
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
### for testing purpose.. put a message into usage_elec_transaction_867
#
my $usage_elec_transaction867_obj = new FS::usage_elec_transaction867(
{'usage_elec_id' => $usage_elec_obj->id,
'note' => "Attention: a meter change out has occured at"
." your location\n"
}
);
$error = $usage_elec_transaction867_obj->insert;
print "Adding note into usage_elec_transaction867\n";
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
my $msg = "Can't insert data into usage_elec_transaction867 : $error\n";
print "$msg";
return;
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
#exit;
return $usage_elec_obj;
} # end extract_data_to_usage_elec
### do the billing call
### return: if there is an error, returns the error, otherwise
### returns false.
sub billing_call {
my $usage_elec_obj = shift;
my $debug = 0;
my $svcnum = $usage_elec_obj->svcnum;
print "svcnum = $svcnum\n" if $debug;
my $package = qsearchs ( 'cust_svc',
{ 'svcnum' => $svcnum
}
);
unless ($package) {
return "error: sub billing_call: unable to acquire the package\n";
}
my $pkgnum = $package->pkgnum;
print "pkgnum = $pkgnum\n" if $debug;
my $custpkg = qsearchs ( 'cust_pkg',
{ 'pkgnum' => $pkgnum
}
);
unless ($custpkg) {
return "error: sub billing_call: unable to acquire the custpkg\n";
}
my $custnum = $custpkg->custnum;
print "custnum = $custnum\n" if $debug;
my $cust_main_obj = qsearchs ( 'cust_main',
{ 'custnum' => $custnum
}
);
unless ($cust_main_obj) {
return "error: sub billing_call: unable to acquire the cust_main_obj\n";
}
my $rtnval = $cust_main_obj->bill();
if ($rtnval) {
return "error: calling billing command\n\t$rtnval";
}
### now let generate the invoice for the customer
if ($debug) { #debug
my $heading = "\tid\tprev_date\tcurr_date\tprev_read\tcurr_read"
. "\ttdsp\tsvcnum\t_date\n";
print "$heading";
print "\t" . $usage_elec_obj->id;
print "\t" . $usage_elec_obj->prev_date;
print "\t" . $usage_elec_obj->curr_date;
print "\t" . $usage_elec_obj->prev_read;
print "\t" . $usage_elec_obj->curr_read;
print "\t" . $usage_elec_obj->tdsp;
print "\t" . $usage_elec_obj->svcnum;
print "\t" . $usage_elec_obj->_date;
print "\t" . $usage_elec_obj->meter_multiplier;
print "\t" . $usage_elec_obj->measured_demand;
print "\t" . $usage_elec_obj->billed_demand;
print "\n";
}
return;
} #end billing_call
1;
Index: Mason.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Mason.pm,v
retrieving revision 1.47
retrieving revision 1.47.2.1
diff -u -w -d -r1.47 -r1.47.2.1
--- Mason.pm 21 Jul 2010 02:06:44 -0000 1.47
+++ Mason.pm 2 Aug 2010 19:49:16 -0000 1.47.2.1
@@ -248,6 +248,12 @@
use FS::rate_time_interval;
use FS::msg_template;
use FS::part_tag;
+ use FS::elec_general;
+ use FS::svc_elec;
+ use FS::usage_elec;
+ use FS::transaction810;
+ use FS::transaction867;
+ use FS::usage_elec_transaction867;
# Sammath Naur
if ( $FS::Mason::addl_handler_use ) {
- Previous message: [freeside-commits] freeside/FS MANIFEST,1.165,1.165.2.1
- Next message: [freeside-commits] freeside/FS/FS/part_pkg business_elec_generic.pm, NONE, 1.1.2.1 energy_base_discount_500kwh.pm, NONE, 1.1.2.1 energy_base_discount_tiers.pm, NONE, 1.1.2.1 residential_elec_generic.pm, NONE, 1.1.2.1 residential_elec_generic_var.pm, NONE, 1.1.2.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the freeside-commits
mailing list