diff options
Diffstat (limited to 'FS/t/suite')
| -rwxr-xr-x | FS/t/suite/00-new_customer.t | 67 | ||||
| -rwxr-xr-x | FS/t/suite/01-order_pkg.t | 49 | ||||
| -rwxr-xr-x | FS/t/suite/02-bill_customer.t | 38 | ||||
| -rwxr-xr-x | FS/t/suite/03-realtime_pay.t | 40 | ||||
| -rwxr-xr-x | FS/t/suite/04-pkg_change_status.t | 103 | ||||
| -rwxr-xr-x | FS/t/suite/05-prorate_sync_same_day.t | 97 | ||||
| -rwxr-xr-x | FS/t/suite/06-prorate_defer_bill.t | 92 | ||||
| -rwxr-xr-x | FS/t/suite/07-pkg_change_location.t | 82 | ||||
| -rwxr-xr-x | FS/t/suite/08-sales_tax.t | 76 | ||||
| -rw-r--r-- | FS/t/suite/WRITING | 93 |
10 files changed, 737 insertions, 0 deletions
diff --git a/FS/t/suite/00-new_customer.t b/FS/t/suite/00-new_customer.t new file mode 100755 index 000000000..8e86459d1 --- /dev/null +++ b/FS/t/suite/00-new_customer.t @@ -0,0 +1,67 @@ +#!/usr/bin/perl + +use FS::Test; +use Test::More tests => 4; + +my $FS = FS::Test->new; +# get the form +$FS->post('/edit/cust_main.cgi'); +my $form = $FS->form('CustomerForm'); + +my %params = ( + residential_commercial => 'Residential', + agentnum => 1, + refnum => 1, + last => 'Customer', + first => 'New', + invoice_email => 'newcustomer@fake.freeside.biz', + bill_address1 => '123 Example Street', + bill_address2 => 'Apt. Z', + bill_city => 'Sacramento', + bill_state => 'CA', + bill_zip => '94901', + bill_country => 'US', + bill_coord_auto => 'Y', + daytime => '916-555-0100', + night => '916-555-0200', + ship_address1 => '125 Example Street', + ship_address2 => '3rd Floor', + ship_city => 'Sacramento', + ship_state => 'CA', + ship_zip => '94901', + ship_country => 'US', + ship_coord_auto => 'Y', + invoice_ship_address => 'Y', + postal_invoice => 'Y', + billday => '1', + no_credit_limit => 1, + # payment method + custpaybynum0_payby => 'CARD', + custpaybynum0_payinfo => '4012888888881881', + custpaybynum0_paydate_month => '12', + custpaybynum0_paydate_year => '2020', + custpaybynum0_paycvv => '123', + custpaybynum0_payname => '', + custpaybynum0_weight => 1, +); +foreach (keys %params) { + $form->value($_, $params{$_}); +} +$FS->post($form); +ok( $FS->error eq '' , 'form posted' ); +if ( + ok($FS->redirect =~ m[^/view/cust_main.cgi\?(\d+)], 'new customer accepted') +) { + my $custnum = $1; + my $cust = $FS->qsearchs('cust_main', { custnum => $1 }); + isa_ok ( $cust, 'FS::cust_main' ); + $FS->post($FS->redirect); + ok ( $FS->error eq '' , 'can view customer' ); +} else { + # try to display the error message, or if not, show everything + $FS->post($FS->redirect); + diag ($FS->error); + done_testing(2); +} + +1; diff --git a/FS/t/suite/01-order_pkg.t b/FS/t/suite/01-order_pkg.t new file mode 100755 index 000000000..ab5a2ddc6 --- /dev/null +++ b/FS/t/suite/01-order_pkg.t @@ -0,0 +1,49 @@ +#!/usr/bin/perl + +use Test::More tests => 4; +use FS::Test; +use Date::Parse 'str2time'; +my $FS = FS::Test->new; + +# get the form +$FS->post('/misc/order_pkg.html', custnum => 2); +my $form = $FS->form('OrderPkgForm'); + +# Customer #2 has three packages: +# a $30 monthly prorate, a $90 monthly prorate, and a $25 annual prorate. +# Next bill date on the monthly prorates is 2016-04-01. +# Add a new package that will start billing on 2016-03-20 (to make prorate +# behavior visible). + +my %params = ( + pkgpart => 2, + quantity => 1, + start => 'on_date', + start_date => '03/20/2016', + package_comment0 => $0, # record the test we're executing +); + +$form->find_input('start')->disabled(0); # JS +foreach (keys %params) { + $form->value($_, $params{$_}); +} +$FS->post($form); +ok( $FS->error eq '' , 'form posted' ); +if ( + ok( $FS->page =~ m[location = '.*/view/cust_main.cgi.*\#cust_pkg(\d+)'], + 'new package accepted' ) +) { + # on success, sends us back to cust_main view with #cust_pkg$pkgnum + # but with an in-page javascript redirect + my $pkg = $FS->qsearchs('cust_pkg', { pkgnum => $1 }); + isa_ok( $pkg, 'FS::cust_pkg' ); + ok($pkg->start_date == str2time('2016-03-20'), 'start date set'); +} else { + # try to display the error message, or if not, show everything + $FS->post($FS->redirect); + diag ($FS->error); + done_testing(2); +} + +1; + diff --git a/FS/t/suite/02-bill_customer.t b/FS/t/suite/02-bill_customer.t new file mode 100755 index 000000000..3fa908e96 --- /dev/null +++ b/FS/t/suite/02-bill_customer.t @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +use FS::Test; +use Test::More tests => 6; +use Test::MockTime 'set_fixed_time'; +use Date::Parse 'str2time'; +use FS::cust_main; + +my $FS = FS::Test->new; + +# After test 01: cust#2 has a package set to bill on 2016-03-20. +# Set local time. +my $date = '2016-03-20'; +set_fixed_time(str2time($date)); +my $cust_main = FS::cust_main->by_key(2); +my @return; + +# Bill the customer. +my $error = $cust_main->bill( return_bill => \@return ); +ok($error eq '', "billed on $date") or diag($error); + +# should be an invoice now +my $cust_bill = $return[0]; +isa_ok($cust_bill, 'FS::cust_bill'); + +# Apr 1 - Mar 20 = 12 days = 288 hours +# Apr 1 - Mar 1 = 31 days - 1 hour (DST) = 743 hours +# 288/743 * $30 = $11.63 recur + $20.00 setup +ok( $cust_bill->charged == 31.63, 'prorated first month correctly' ); + +# the package bill date should now be 2016-04-01 +my @lineitems = $cust_bill->cust_bill_pkg; +ok( scalar(@lineitems) == 1, 'one package was billed' ); +my $pkg = $lineitems[0]->cust_pkg; +ok( $pkg->status eq 'active', 'package is now active' ); +ok( $pkg->bill == str2time('2016-04-01'), 'package bill date set correctly' ); + +1; diff --git a/FS/t/suite/03-realtime_pay.t b/FS/t/suite/03-realtime_pay.t new file mode 100755 index 000000000..17456bb15 --- /dev/null +++ b/FS/t/suite/03-realtime_pay.t @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +use FS::Test; +use Test::More tests => 2; +use FS::cust_main; + +my $FS = FS::Test->new; + +# In the stock database, cust#5 has open invoices +my $cust_main = FS::cust_main->by_key(5); +my $balance = $cust_main->balance; +ok( $balance > 10.00, 'customer has an outstanding balance of more than $10.00' ); + +# Get the payment form +$FS->post('/misc/payment.cgi?payby=CARD;custnum=5'); +my $form = $FS->form('OneTrueForm'); +$form->value('amount' => '10.00'); +$form->value('custpaybynum' => ''); +$form->value('payinfo' => '4012888888881881'); +$form->value('month' => '01'); +$form->value('year' => '2020'); +# payname and location fields should already be set +$form->value('save' => 1); +$form->value('auto' => 1); +$FS->post($form); + +# on success, gives a redirect to the payment receipt +my $paynum; +if ($FS->redirect =~ m[^/view/cust_pay.html\?(\d+)]) { + pass('payment processed'); + $paynum = $1; +} elsif ( $FS->error ) { + fail('payment rejected'); + diag ( $FS->error ); +} else { + fail('unknown result'); + diag ( $FS->page ); +} + +1; diff --git a/FS/t/suite/04-pkg_change_status.t b/FS/t/suite/04-pkg_change_status.t new file mode 100755 index 000000000..cc969983a --- /dev/null +++ b/FS/t/suite/04-pkg_change_status.t @@ -0,0 +1,103 @@ +#!/usr/bin/perl + +=head2 DESCRIPTION + +Tests the effect of a scheduled change on the status of an active or +suspended package. Ref RT#38564. + +Correct: A scheduled package change should result in a package with the same +status as before. + +=cut + +use strict; +use Test::More tests => 20; +use FS::Test; +use Date::Parse 'str2time'; +use Test::MockTime qw(set_fixed_time); +use FS::cust_main; +use FS::cust_pkg; +my $FS = FS::Test->new; + +# Create two package defs with the suspend_bill flag, and one with +# the unused_credit_change flag. +my $part_pkg = $FS->qsearchs('part_pkg', { pkgpart => 2 }); +my $error; +my @part_pkgs; +foreach my $i (0, 1) { + $part_pkgs[$i] = $part_pkg->clone; + $part_pkgs[$i]->insert(options => { $part_pkg->options, + 'suspend_bill' => 1, + 'unused_credit_change' => $i } ); + BAIL_OUT("can't configure package: $error") if $error; +} + +# For customer #3, order four packages. 0-1 will be suspended, 2-3 will not. +# 1 and 3 will use $part_pkgs[1], the one with unused_credit_change. + +my $cust = $FS->qsearchs('cust_main', { custnum => 3 }); +my @pkgs; +foreach my $i (0..3) { + $pkgs[$i] = FS::cust_pkg->new({ pkgpart => $part_pkgs[$i % 2]->pkgpart }); + $error = $cust->order_pkg({ cust_pkg => $pkgs[$i] }); + BAIL_OUT("can't order package: $error") if $error; +} + +# On Mar 25, bill the customer. + +set_fixed_time(str2time('2016-03-25')); +$error = $cust->bill_and_collect; +ok( $error eq '', 'initially bill customer' ); +# update our @pkgs to match +@pkgs = map { $_->replace_old } @pkgs; + +# On Mar 26, suspend packages 0-1. + +set_fixed_time(str2time('2016-03-25')); +my $reason_type = $FS->qsearchs('reason_type', { type => 'Suspend Reason' }); +foreach my $i (0,1) { + $error = $pkgs[$i]->suspend(reason => { + typenum => $reason_type->typenum, + reason => 'Test suspension + future package change', + }); + ok( $error eq '', "suspended package $i" ) or diag($error); + $pkgs[$i] = $pkgs[$i]->replace_old; +} + +# For each of these packages, clone the package def, then schedule a future +# change (on Mar 26) to that package. +my $change_date = str2time('2016-03-26'); +my @new_pkgs; +foreach my $i (0..3) { + my $pkg = $pkgs[$i]; + my $new_part_pkg = $pkg->part_pkg->clone; + $error = $new_part_pkg->insert( options => { $pkg->part_pkg->options } ); + ok( $error eq '', 'created new package def' ) or diag($error); + $error = $pkg->change_later( + pkgpart => $new_part_pkg->pkgpart, + start_date => $change_date, + ); + ok( $error eq '', 'scheduled package change' ) or diag($error); + $new_pkgs[$i] = $FS->qsearchs('cust_pkg', { + pkgnum => $pkg->change_to_pkgnum + }); + ok( $new_pkgs[$i], 'future package was created' ); +} + +# Then bill the customer on that date. +set_fixed_time($change_date); +$error = $cust->bill_and_collect; +ok( $error eq '', 'billed customer on change date' ) or diag($error); + +foreach my $i (0,1) { + $new_pkgs[$i] = $new_pkgs[$i]->replace_old; + ok( $new_pkgs[$i]->status eq 'suspended', "new package $i is suspended" ) + or diag($new_pkgs[$i]->status); +} +foreach my $i (2,3) { + $new_pkgs[$i] = $new_pkgs[$i]->replace_old; + ok( $new_pkgs[$i]->status eq 'active', "new package $i is active" ) + or diag($new_pkgs[$i]->status); +} + +1; diff --git a/FS/t/suite/05-prorate_sync_same_day.t b/FS/t/suite/05-prorate_sync_same_day.t new file mode 100755 index 000000000..91a8efa74 --- /dev/null +++ b/FS/t/suite/05-prorate_sync_same_day.t @@ -0,0 +1,97 @@ +#!/usr/bin/perl + +=head2 DESCRIPTION + +Tests the effect of ordering and activating two sync_bill_date packages on +the same day. Ref RT#42108. + +Correct: If the packages have prorate_round_day = 1 (round nearest), or 3 +(round down) then the second package should be prorated one day short. If +they have prorate_round_day = 2 (round up), they should be billed +for the same amount. In both cases they should have the same next bill date. + +=cut + +use strict; +use Test::More tests => 9; +use FS::Test; +use Date::Parse 'str2time'; +use Date::Format 'time2str'; +use Test::MockTime qw(set_fixed_time); +use FS::cust_main; +use FS::cust_pkg; +use FS::Conf; +my $FS= FS::Test->new; + +foreach my $prorate_mode (1, 2, 3) { + diag("prorate_round_day = $prorate_mode"); + # Create a package def with the sync_bill_date option. + my $error; + my $old_part_pkg = $FS->qsearchs('part_pkg', { pkgpart => 5 }); + my $part_pkg = $old_part_pkg->clone; + BAIL_OUT("existing pkgpart 5 is not a flat monthly package") + unless $part_pkg->freq eq '1' and $part_pkg->plan eq 'flat'; + $error = $part_pkg->insert( + options => { $old_part_pkg->options, + 'sync_bill_date' => 1, + 'prorate_round_day' => $prorate_mode, } + ); + + BAIL_OUT("can't configure package: $error") if $error; + + my $pkgpart = $part_pkg->pkgpart; + # Create a clean customer with no other packages. + my $location = FS::cust_location->new({ + address1 => '123 Example Street', + city => 'Sacramento', + state => 'CA', + country => 'US', + zip => '94901', + }); + my $cust = FS::cust_main->new({ + agentnum => 1, + refnum => 1, + last => 'Customer', + first => 'Sync bill date', + invoice_email => 'newcustomer@fake.freeside.biz', + bill_location => $location, + ship_location => $location, + }); + $error = $cust->insert; + BAIL_OUT("can't create test customer: $error") if $error; + + my @pkgs; + # Create and bill the first package. + set_fixed_time(str2time('2016-03-10 08:00')); + $pkgs[0] = FS::cust_pkg->new({ pkgpart => $pkgpart }); + $error = $cust->order_pkg({ 'cust_pkg' => $pkgs[0] }); + BAIL_OUT("can't order package: $error") if $error; + $error = $cust->bill_and_collect; + # Check the amount billed. + my ($cust_bill_pkg) = $pkgs[0]->cust_bill_pkg; + my $recur = $part_pkg->base_recur; + ok( $cust_bill_pkg->recur == $recur, "first package recur is $recur" ) + or diag("first package recur is ".$cust_bill_pkg->recur); + + # Create and bill the second package. + set_fixed_time(str2time('2016-03-10 16:00')); + $pkgs[1] = FS::cust_pkg->new({ pkgpart => $pkgpart }); + $error = $cust->order_pkg({ 'cust_pkg' => $pkgs[1] }); + BAIL_OUT("can't order package: $error") if $error; + $error = $cust->bill_and_collect; + + # Check the amount billed. + if ( $prorate_mode == 1 or $prorate_mode == 3 ) { + # it should be one day short, in March + $recur = sprintf('%.2f', $recur * 30/31); + } + ($cust_bill_pkg) = $pkgs[1]->cust_bill_pkg; + ok( $cust_bill_pkg->recur == $recur, "second package recur is $recur" ) + or diag("second package recur is ".$cust_bill_pkg->recur); + + my @next_bill = map { time2str('%Y-%m-%d', $_->replace_old->get('bill')) } @pkgs; + + ok( $next_bill[0] eq $next_bill[1], + "both packages will bill again on $next_bill[0]" ) + or diag("first package bill date is $next_bill[0], second package is $next_bill[1]"); +} diff --git a/FS/t/suite/06-prorate_defer_bill.t b/FS/t/suite/06-prorate_defer_bill.t new file mode 100755 index 000000000..e14b8ec21 --- /dev/null +++ b/FS/t/suite/06-prorate_defer_bill.t @@ -0,0 +1,92 @@ +#!/usr/bin/perl + +=head2 DESCRIPTION + +Tests the prorate_defer_bill behavior when a package is started on the cutoff day, +and when it's started later in the month. + +Correct: The package started on the cutoff day should be charged a setup fee and a +full period. The package started later in the month should be charged a setup fee, +a full period, and the partial period. + +=cut + +use strict; +use Test::More tests => 11; +use FS::Test; +use Date::Parse 'str2time'; +use Date::Format 'time2str'; +use Test::MockTime qw(set_fixed_time); +use FS::cust_main; +use FS::cust_pkg; +use FS::Conf; +my $FS= FS::Test->new; + +my $error; + +my $old_part_pkg = $FS->qsearchs('part_pkg', { pkgpart => 2 }); +my $part_pkg = $old_part_pkg->clone; +BAIL_OUT("existing pkgpart 2 is not a prorated monthly package") + unless $part_pkg->freq eq '1' and $part_pkg->plan eq 'prorate'; +$error = $part_pkg->insert( + options => { $old_part_pkg->options, + 'prorate_defer_bill' => 1, + 'cutoff_day' => 1, + 'setup_fee' => 100, + 'recur_fee' => 30, + } +); +BAIL_OUT("can't configure package: $error") if $error; + +my $cust = $FS->new_customer('Prorate defer'); +$error = $cust->insert; +BAIL_OUT("can't create test customer: $error") if $error; + +my @pkgs; +foreach my $start_day (1, 11) { + diag("prorate package starting on day $start_day"); + # Create and bill the first package. + my $date = str2time("2016-04-$start_day"); + set_fixed_time($date); + my $pkg = FS::cust_pkg->new({ pkgpart => $part_pkg->pkgpart }); + $error = $cust->order_pkg({ 'cust_pkg' => $pkg }); + BAIL_OUT("can't order package: $error") if $error; + + # bill the customer on the order date + $error = $cust->bill_and_collect; + $pkg = $pkg->replace_old; + push @pkgs, $pkg; + my ($cust_bill_pkg) = $pkg->cust_bill_pkg; + if ( $start_day == 1 ) { + # then it should bill immediately + ok($cust_bill_pkg, "package was billed") or next; + ok($cust_bill_pkg->setup == 100, "setup fee was charged"); + ok($cust_bill_pkg->recur == 30, "one month was charged"); + } elsif ( $start_day == 11 ) { + # then not + ok(!$cust_bill_pkg, "package billing was deferred"); + ok($pkg->setup == $date, "package setup date was set"); + } +} +diag("first of month billing..."); +my $date = str2time('2016-05-01'); +set_fixed_time($date); +my @bill; +$error = $cust->bill_and_collect(return_bill => \@bill); +# examine the invoice... +my $cust_bill = $bill[0] or BAIL_OUT("neither package was billed"); +for my $pkg ($pkgs[0]) { + diag("package started day 1:"); + my ($cust_bill_pkg) = grep {$_->pkgnum == $pkg->pkgnum} $cust_bill->cust_bill_pkg; + ok($cust_bill_pkg, "was billed") or next; + ok($cust_bill_pkg->setup == 0, "no setup fee was charged"); + ok($cust_bill_pkg->recur == 30, "one month was charged"); +} +for my $pkg ($pkgs[1]) { + diag("package started day 11:"); + my ($cust_bill_pkg) = grep {$_->pkgnum == $pkg->pkgnum} $cust_bill->cust_bill_pkg; + ok($cust_bill_pkg, "was billed") or next; + ok($cust_bill_pkg->setup == 100, "setup fee was charged"); + ok($cust_bill_pkg->recur == 50, "twenty days + one month was charged"); +} + diff --git a/FS/t/suite/07-pkg_change_location.t b/FS/t/suite/07-pkg_change_location.t new file mode 100755 index 000000000..6744f78ef --- /dev/null +++ b/FS/t/suite/07-pkg_change_location.t @@ -0,0 +1,82 @@ +#!/usr/bin/perl + +=head2 DESCRIPTION + +Test scheduling a package location change through the UI, then billing +on the day of the scheduled change. + +=cut + +use Test::More tests => 6; +use FS::Test; +use Date::Parse 'str2time'; +use Date::Format 'time2str'; +use Test::MockTime qw(set_fixed_time); +use FS::cust_pkg; +my $FS = FS::Test->new; +my $error; + +# set up a customer with an active package +my $cust = $FS->new_customer('Future location change'); +$error = $cust->insert; +my $pkg = FS::cust_pkg->new({pkgpart => 2}); +$error ||= $cust->order_pkg({ cust_pkg => $pkg }); +my $date = str2time('2016-04-01'); +set_fixed_time($date); +$error ||= $cust->bill_and_collect; +BAIL_OUT($error) if $error; + +# get the form +my %args = ( pkgnum => $pkg->pkgnum, + pkgpart => $pkg->pkgpart, + locationnum => -1); +$FS->post('/misc/change_pkg.cgi', %args); +my $form = $FS->form('OrderPkgForm'); + +# Schedule the package change two days from now. +$date += 86400*2; +my $date_str = time2str('%x', $date); + +my %params = ( + start_date => $date_str, + delay => 1, + address1 => int(rand(1000)) . ' Changed Street', + city => 'New City', + state => 'CA', + zip => '90001', + country => 'US', +); + +diag "requesting location change to $params{address1}"; + +foreach (keys %params) { + $form->value($_, $params{$_}); +} +$FS->post($form); +ok( $FS->error eq '' , 'form posted' ); +if ( ok( $FS->page =~ m[location.reload], 'location change accepted' )) { + #nothing +} else { + $FS->post($FS->redirect); + BAIL_OUT( $FS->error); +} +# check that the package change is set +$pkg = $pkg->replace_old; +my $new_pkgnum = $pkg->change_to_pkgnum; +ok( $new_pkgnum, 'package change is scheduled' ); + +# run it and check that the package change happened +diag("billing customer on $date_str"); +set_fixed_time($date); +my $error = $cust->bill_and_collect; +BAIL_OUT($error) if $error; + +$pkg = $pkg->replace_old; +ok($pkg->get('cancel'), "old package is canceled"); +my $new_pkg = $FS->qsearchs('cust_pkg', { pkgnum => $new_pkgnum }); +ok($new_pkg->setup, "new package is active"); +ok($new_pkg->cust_location->address1 eq $params{'address1'}, "new location is correct") + or diag $new_pkg->cust_location->address1; + +1; + diff --git a/FS/t/suite/08-sales_tax.t b/FS/t/suite/08-sales_tax.t new file mode 100755 index 000000000..bf1ae48c8 --- /dev/null +++ b/FS/t/suite/08-sales_tax.t @@ -0,0 +1,76 @@ +#!/usr/bin/perl + +=head2 DESCRIPTION + +Tests basic sales tax calculations, including consolidation and rounding. +The invoice will have two charges that add up to $50 and two taxes: +- Tax 1, 8.25%, for $4.125 in tax, which will round up. +- Tax 2, 8.245%, for $4.1225 in tax, which will round down. + +Correct: The invoice will have one line item for each of those taxes, with +the correct amount. + +=cut + +use strict; +use Test::More tests => 2; +use FS::Test; +use Date::Parse 'str2time'; +use Date::Format 'time2str'; +use Test::MockTime qw(set_fixed_time); +use FS::cust_main; +use FS::cust_pkg; +use FS::Conf; +my $FS= FS::Test->new; + +# test configuration +my @taxes = ( + [ 'Tax 1', 8.250, 4.13 ], + [ 'Tax 2', 8.245, 4.12 ], +); + +# Create the customer and charge them +my $cust = $FS->new_customer('Basic taxes'); +$cust->bill_location->state('AZ'); # move it away from the default of CA +my $error; +$error = $cust->insert; +BAIL_OUT("can't create test customer: $error") if $error; +$error = $cust->charge( { + amount => 25.00, + pkg => 'Test charge 1', +} ) || +$cust->charge({ + amount => 25.00, + pkg => 'Test charge 2', +}); +BAIL_OUT("can't create test charges: $error") if $error; + +# Create tax defs +foreach my $tax (@taxes) { + my $cust_main_county = FS::cust_main_county->new({ + 'country' => 'US', + 'state' => 'AZ', + 'exempt_amount' => 0.00, + 'taxname' => $tax->[0], + 'tax' => $tax->[1], + }); + $error = $cust_main_county->insert; + BAIL_OUT("can't create tax definitions: $error") if $error; +} + +# Bill the customer +set_fixed_time(str2time('2016-03-10 08:00')); +my @return; +$error = $cust->bill( return_bill => \@return ); +BAIL_OUT("can't bill charges: $error") if $error; +my $cust_bill = $return[0] or BAIL_OUT("no invoice generated"); +# Check amounts +diag("Tax on 25.00 + 25.00"); +foreach my $cust_bill_pkg ($cust_bill->cust_bill_pkg) { + next if $cust_bill_pkg->pkgnum; + my ($tax) = grep { $_->[0] eq $cust_bill_pkg->itemdesc } @taxes; + if ( $tax ) { + ok ( $cust_bill_pkg->setup eq $tax->[2], "Tax at rate $tax->[1]% = $tax->[2]") + or diag("is ". $cust_bill_pkg->setup); + } +} diff --git a/FS/t/suite/WRITING b/FS/t/suite/WRITING new file mode 100644 index 000000000..d9421cc7b --- /dev/null +++ b/FS/t/suite/WRITING @@ -0,0 +1,93 @@ +WRITING TESTS + +Load the test database (kept in FS-Test/share/test.sql for now). This has +a large set of customers in a known initial state. You can login through +the web interface as "admin"/"admin" to examine the state of things and plan +your test. + +The test scripts now have access to BOTH sides of the web interface, so you +can create an object through the UI and then examine its internal +properties, etc. + + use Test::More tests => 1; + use FS::Test; + my $FS = FS::Test->new; + +$FS has qsearch and qsearchs methods for finding objects directly. You can +do anything with those objects that Freeside backend code could normally do. +For example, this will bill a customer: + + my $cust = $FS->qsearchs('cust_main', { custnum => 52 }); + my $error = $cust->bill; + +TESTING UI INTERACTION + +To fetch a page from the UI, use the post() method: + + $FS->post('/view/cust_main.cgi?52'); + ok( $FS->error eq '', 'fetched customer view' ) or diag($FS->error); + ok( $FS->page =~ /Customer, New/, 'customer is named "Customer, New"' ); + +To simulate a user filling in and submitting a form, first fetch the form, +and select it by name: + + $FS->post('/edit/svc_acct.cgi?98'); + my $form = $FS->form('OneTrueForm'); + +then fill it in and submit it: + + $form->value('clear_password', '1234abcd'); + $FS->post($form); + +and examine the result: + + my $svc_acct = $FS->qsearch('svc_acct', { svcnum => 98 }); + ok( $svc_acct->_password eq '1234abcd', 'password was changed' ); + +TESTING UI FLOW (EDIT/PROCESS/VIEW SEQUENCE) + +Forms for editing records will post to a processing page. $FS->post($form) +handles this. The processing page will usually redirect back to the view +page on success, and back to the edit form with an error on failure. +Determine which kind of redirect it is. If it's a redirect to the edit form, +you need to follow it to report the error. + + if ( $FS->redirect =~ m[^/view/svc_acct.cgi] ) { + + pass('redirected to view page'); + + } elsif ( $FS->redirect =~ m[^/edit/svc_acct.cgi] ) { + + fail('redirected back to edit form'); + $FS->post($FS->redirect); + diag($FS->error); + + } else { + + fail('unsure what happened'); + diag($FS->page); + + } + +RUNNING TESTS AT A SPECIFIC DATE + +Important for testing package billing. Test::MockTime provides the +set_fixed_time() function, which will freeze the time returned by the time() +function at a specific value. I recommend giving it a unix timestamp rather +than a date string to avoid any confusion about time zones. + +Note that FS::Cron::bill and some other parts of the system look at the $^T +variable (the time that the current program started running). You can +override that by just assigning to the variable. + +Customers in the test database are billed up through Mar 1 2016. This will +bill a customer for the next month after that: + + use Test::MockTime qw(set_fixed_time); + use Date::Parse qw(str2time); + + my $cust = $FS->qsearchs('cust_main', { custnum => 52 }); + set_fixed_time( str2time('2016-04-01') ); + $cust->bill; + + |
