From: ivan Date: Thu, 8 Jan 2009 01:45:22 +0000 (+0000) Subject: start adding package locations, RT#4499 X-Git-Tag: root_of_webpay_support~147 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=2b8ffc98529637ffddfe7cbf6b4f9b8deb90f0fa start adding package locations, RT#4499 --- diff --git a/FS/FS.pm b/FS/FS.pm index 7e9b04eb2..c4be977f1 100644 --- a/FS/FS.pm +++ b/FS/FS.pm @@ -222,6 +222,8 @@ L - Package reason class L - Customer class +L - Customer location class + L - Mixin class for records that contain fields from cust_main L - Invoice destination class diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 5d5616938..9c9c6aaaf 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2001,6 +2001,13 @@ worry that config_items is freeside-specific and icky. 'section' => 'billing', 'description' => 'By default, tax calculations are done based on the billing address. Enable this switch to calculate tax based on the shipping address instead. Note: Tax reports can take a long time when enabled.', 'type' => 'checkbox', + } +, + { + 'key' => 'tax-pkg_address', + 'section' => 'billing', + 'description' => 'By default, tax calculations are done based on the billing address. Enable this switch to calculate tax based on the package address instead (when present). Note: Tax reports can take a long time when enabled.', + 'type' => 'checkbox', }, { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 17665b132..ecf017e3b 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -671,6 +671,28 @@ sub tables_hashref { ], }, + #eventually use for billing & ship from cust_main too + #for now, just cust_pkg locations + 'cust_location' => { + 'columns' => [ + 'locationnum', 'serial', '', '', '', '', + 'custnum', 'int', '', '', '', '', + 'address1', 'varchar', '', $char_d, '', '', + 'address2', 'varchar', 'NULL', $char_d, '', '', + 'city', 'varchar', '', $char_d, '', '', + 'county', 'varchar', 'NULL', $char_d, '', '', + 'state', 'varchar', 'NULL', $char_d, '', '', + 'zip', 'varchar', 'NULL', 10, '', '', + 'country', 'char', '', 2, '', '', + 'geocode', 'varchar', 'NULL', 20, '', '', + ], + 'primary_key' => 'locationnum', + 'unique' => [], + 'index' => [ [ 'custnum' ], + [ 'county' ], [ 'state' ], [ 'country' ], [ 'zip' ], + ], + }, + 'cust_main_invoice' => { 'columns' => [ 'destnum', 'serial', '', '', '', '', @@ -938,26 +960,27 @@ sub tables_hashref { 'cust_pkg' => { 'columns' => [ - 'pkgnum', 'serial', '', '', '', '', - 'custnum', 'int', '', '', '', '', - 'pkgpart', 'int', '', '', '', '', - 'otaker', 'varchar', '', 32, '', '', - 'setup', @date_type, '', '', - 'bill', @date_type, '', '', - 'last_bill', @date_type, '', '', - 'susp', @date_type, '', '', - 'adjourn', @date_type, '', '', - 'cancel', @date_type, '', '', - 'expire', @date_type, '', '', - 'change_date', @date_type, '', '', - 'change_pkgnum', 'int', 'NULL', '', '', '', - 'change_pkgpart', 'int', 'NULL', '', '', '', - 'manual_flag', 'char', 'NULL', 1, '', '', - 'quantity', 'int', 'NULL', '', '', '', + 'pkgnum', 'serial', '', '', '', '', + 'custnum', 'int', '', '', '', '', + 'pkgpart', 'int', '', '', '', '', + 'locationnum', 'int', 'NULL', '', '', '', + 'otaker', 'varchar', '', 32, '', '', + 'setup', @date_type, '', '', + 'bill', @date_type, '', '', + 'last_bill', @date_type, '', '', + 'susp', @date_type, '', '', + 'adjourn', @date_type, '', '', + 'cancel', @date_type, '', '', + 'expire', @date_type, '', '', + 'change_date', @date_type, '', '', + 'change_pkgnum', 'int', 'NULL', '', '', '', + 'change_pkgpart', 'int', 'NULL', '', '', '', + 'manual_flag', 'char', 'NULL', 1, '', '', + 'quantity', 'int', 'NULL', '', '', '', ], 'primary_key' => 'pkgnum', 'unique' => [], - 'index' => [ ['custnum'], ['pkgpart'], + 'index' => [ ['custnum'], ['pkgpart'], [ 'locationnum' ], ['setup'], ['last_bill'], ['bill'], ['susp'], ['adjourn'], ['expire'], ['cancel'], ['change_date'], diff --git a/FS/FS/cust_location.pm b/FS/FS/cust_location.pm new file mode 100644 index 000000000..0544dcfba --- /dev/null +++ b/FS/FS/cust_location.pm @@ -0,0 +1,175 @@ +package FS::cust_location; + +use strict; +use base qw( FS::Record ); +use Locale::Country; +use FS::Record qw( qsearch ); #qsearchs ); +use FS::cust_main; +use FS::cust_main_county; + +=head1 NAME + +FS::cust_location - Object methods for cust_location records + +=head1 SYNOPSIS + + use FS::cust_location; + + $record = new FS::cust_location \%hash; + $record = new FS::cust_location { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_location object represents a customer location. FS::cust_location +inherits from FS::Record. The following fields are currently supported: + +=over 4 + +=item locationnum + +primary key + +=item custnum + +custnum + +=item address1 + +Address line one (required) + +=item address2 + +Address line two (optional) + +=item city + +City + +=item county + +County (optional, see L) + +=item state + +State (see L) + +=item zip + +Zip + +=item country + +Country (see L) + +=item geocode + +Geocode + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new location. To add the location 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 method. + +=cut + +sub table { 'cust_location'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=item check + +Checks all fields to make sure this is a valid location. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +#some false laziness w/cust_main, but since it should eventually lose these +#fields anyway... +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('locationnum') + || $self->ut_foreign_key('custnum', 'cust_main', 'custnum') + || $self->ut_text('address1') + || $self->ut_textn('address2') + || $self->ut_text('city') + || $self->ut_textn('county') + || $self->ut_textn('state') + || $self->ut_country('country') + || $self->ut_zip('zip', $self->country) + || $self->ut_alphan('geocode') + ; + return $error if $error; + + unless ( qsearch('cust_main_county', { + 'country' => $self->country, + 'state' => '', + } ) ) { + return "Unknown state/county/country: ". + $self->state. "/". $self->county. "/". $self->country + unless qsearch('cust_main_county',{ + 'state' => $self->state, + 'county' => $self->county, + 'country' => $self->country, + } ); + } + + $self->SUPER::check; +} + +=item country_full + +Returns this locations's full country name + +=cut + +sub country_full { + my $self = shift; + code2country($self->country); +} + +=back + +=head1 BUGS + +Not yet used for cust_main billing and shipping addresses. + +=head1 SEE ALSO + +L, L, L, +schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index da1d3e195..2b94dca33 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -135,101 +135,181 @@ FS::Record. The following fields are currently supported: =over 4 -=item custnum - primary key (assigned automatically for new customers) +=item custnum -=item agentnum - agent (see L) +Primary key (assigned automatically for new customers) -=item refnum - Advertising source (see L) +=item agentnum + +Agent (see L) + +=item refnum + +Advertising source (see L) + +=item first + +First name -=item first - name +=item last -=item last - name +Last name -=item ss - social security number (optional) +=item ss -=item company - (optional) +Cocial security number (optional) + +=item company + +(optional) =item address1 -=item address2 - (optional) +=item address2 + +(optional) =item city -=item county - (optional, see L) +=item county -=item state - (see L) +(optional, see L) + +=item state + +(see L) =item zip -=item country - (see L) +=item country + +(see L) -=item daytime - phone (optional) +=item daytime -=item night - phone (optional) +phone (optional) -=item fax - phone (optional) +=item night -=item ship_first - name +phone (optional) -=item ship_last - name +=item fax -=item ship_company - (optional) +phone (optional) + +=item ship_first + +Shipping first name + +=item ship_last + +Shipping last name + +=item ship_company + +(optional) =item ship_address1 -=item ship_address2 - (optional) +=item ship_address2 + +(optional) =item ship_city -=item ship_county - (optional, see L) +=item ship_county + +(optional, see L) + +=item ship_state -=item ship_state - (see L) +(see L) =item ship_zip -=item ship_country - (see L) +=item ship_country -=item ship_daytime - phone (optional) +(see L) -=item ship_night - phone (optional) +=item ship_daytime -=item ship_fax - phone (optional) +phone (optional) -=item payby - Payment Type (See L for valid payby values) +=item ship_night -=item payinfo - Payment Information (See L for data format) +phone (optional) -=item paymask - Masked payinfo (See L for how this works) +=item ship_fax + +phone (optional) + +=item payby + +Payment Type (See L for valid payby values) + +=item payinfo + +Payment Information (See L for data format) + +=item paymask + +Masked payinfo (See L for how this works) =item paycvv Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card -=item paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy +=item paydate + +Expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy + +=item paystart_month + +Start date month (maestro/solo cards only) + +=item paystart_year + +Start date year (maestro/solo cards only) -=item paystart_month - start date month (maestro/solo cards only) +=item payissue -=item paystart_year - start date year (maestro/solo cards only) +Issue number (maestro/solo cards only) -=item payissue - issue number (maestro/solo cards only) +=item payname -=item payname - name on card or billing name +Name on card or billing name -=item payip - IP address from which payment information was received +=item payip -=item tax - tax exempt, empty or `Y' +IP address from which payment information was received -=item otaker - order taker (assigned automatically, see L) +=item tax -=item comments - comments (optional) +Tax exempt, empty or `Y' -=item referral_custnum - referring customer number +=item otaker -=item spool_cdr - Enable individual CDR spooling, empty or `Y' +Order taker (assigned automatically, see L) -=item dundate - a suggestion to events (see L) to delay until this unix timestamp +=item comments -=item squelch_cdr - Discourage individual CDR printing, empty or `Y' +Comments (optional) + +=item referral_custnum + +Referring customer number + +=item spool_cdr + +Enable individual CDR spooling, empty or `Y' + +=item dundate + +A suggestion to events (see L) to delay until this unix timestamp + +=item squelch_cdr + +Discourage individual CDR printing, empty or `Y' =back @@ -2905,6 +2985,11 @@ Only return events for the specified eventtable (by default, events of all event Explicitly pass the objects to be tested (typically used with eventtable). +=item testonly + +Set to true to return the objects, but not actually insert them into the +database. + =back =cut @@ -2935,7 +3020,8 @@ sub due_cust_event { local $FS::UID::AutoCommit = 0; my $dbh = dbh; - $self->select_for_update; #mutex + $self->select_for_update #mutex + unless $opt{testonly}; ### # 1: find possible events (initial search) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 70f23df9b..03cec75b8 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -13,6 +13,7 @@ use FS::cust_main_Mixin; use FS::cust_svc; use FS::part_pkg; use FS::cust_main; +use FS::cust_location; use FS::type_pkgs; use FS::pkg_svc; use FS::cust_bill_pkg; @@ -106,7 +107,7 @@ inherits from FS::Record. The following fields are currently supported: =item pkgnum -primary key (assigned automatically for new billing items) +Primary key (assigned automatically for new billing items) =item custnum @@ -116,6 +117,10 @@ Customer (see L) Billing item definition (see L) +=item locationnum + +Optional link to package location (see L) + =item setup date @@ -435,6 +440,7 @@ sub check { $self->ut_numbern('pkgnum') || $self->ut_foreign_key('custnum', 'cust_main', 'custnum') || $self->ut_numbern('pkgpart') + || $self->ut_foreign_keyn('locationnum', 'location', 'locationnum') || $self->ut_numbern('setup') || $self->ut_numbern('bill') || $self->ut_numbern('susp') @@ -1569,6 +1575,30 @@ sub cust_main { qsearchs( 'cust_main', { 'custnum' => $self->custnum } ); } +=item cust_location + +Returns the location object, if any (see L). + +=cut + +sub cust_location { + my $self = shift; + return '' unless $self->locationnum; + qsearchs( 'cust_main', { 'locationnum' => $self->locationnum } ); +} + +=item cust_location_or_main + +If this package is associated with a location, returns the locaiton (see +L), otherwise returns the customer (see L). + +=cut + +sub cust_location_or_main { + my $self = shift; + $self->cust_location || $self->cust_main; +} + =item seconds_since TIMESTAMP Returns the number of seconds all accounts (see L) in this diff --git a/FS/MANIFEST b/FS/MANIFEST index c3252425b..21d721dcb 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -427,3 +427,5 @@ FS/cust_bill_pkg_display.pm t/cust_bill_pkg_display.t FS/cust_pkg_detail.pm t/cust_pkg_detail.t +FS/cust_location.pm +t/cust_location.t diff --git a/FS/t/cust_location.t b/FS/t/cust_location.t new file mode 100644 index 000000000..e98372d72 --- /dev/null +++ b/FS/t/cust_location.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::cust_location; +$loaded=1; +print "ok 1\n"; diff --git a/eg/table_template-svc.pm b/eg/table_template-svc.pm index 47dcbe6e4..7e10275cd 100644 --- a/eg/table_template-svc.pm +++ b/eg/table_template-svc.pm @@ -1,13 +1,10 @@ package FS::svc_table; use strict; -use vars qw(@ISA); +use base qw( FS::svc_Common ); #use FS::Record qw( qsearch qsearchs ); -use FS::svc_Common; use FS::cust_svc; -@ISA = qw(FS::svc_Common); - =head1 NAME FS::table_name - Object methods for table_name records diff --git a/eg/table_template.pm b/eg/table_template.pm index 5da6f3b28..9c71b3adc 100644 --- a/eg/table_template.pm +++ b/eg/table_template.pm @@ -1,11 +1,9 @@ package FS::table_name; use strict; -use vars qw( @ISA ); +use base qw( FS::Record ); use FS::Record qw( qsearch qsearchs ); -@ISA = qw(FS::Record); - =head1 NAME FS::table_name - Object methods for table_name records diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 5f1db4ab6..5fde2f392 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -123,7 +123,6 @@ Current packages % } % if ( @$packages ) { - <% include('/elements/table-grid.html') %> % my $bgcolor1 = '#eeeeee'; % my $bgcolor2 = '#ffffff'; @@ -132,444 +131,40 @@ Current packages Package Status + Location Services -%foreach my $cust_pkg (@$packages) { -% -% my $part_pkg = $cust_pkg->part_pkg; +% foreach my $cust_pkg (@$packages) { % -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } - - - - - - - - - - - -% if ( $cust_pkg->quantity > 1 ) { - - - +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; % } - - - - - -% my $editi = $curuser->access_right('Edit customer package invoice details'); -% my $editc = $curuser->access_right('Edit customer package comments'); % -% if ( $cust_pkg->cust_pkg_detail('I') || $cust_pkg->cust_pkg_detail('C') -% || $editi || $editc ) { -% -% my $editlink = $p. 'edit/cust_pkg_detail?pkgnum='. $cust_pkg->pkgnum. -% ';detailtype='; - - - -% if ( $cust_pkg->cust_pkg_detail('I') ) { - - - -% foreach my $cust_pkg_detail ( $cust_pkg->cust_pkg_detail('I') ) { - - - -% } -
- <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><% $part_pkg->pkg %> - - - <% $part_pkg->comment %> -
-       Quantity: - <% $cust_pkg->quantity %> -
- - - -% unless ( $cust_pkg->get('cancel') ) { -% my $br = 0; -% if ( $curuser->access_right('Change customer package') ) { $br=1; - - ( <%pkg_change_link($cust_pkg)%> ) -% } -% if ( $curuser->access_right('Edit customer package dates') ) { $br=1; - - ( <%pkg_dates_link($cust_pkg)%> ) -% } -% if ( $curuser->access_right('Customize customer package') ) { $br=1; - - ( <%pkg_customize_link($cust_pkg,$cust_main->custnum)%> ) -% } - <% $br ? '
' : '' %> -% } - -% if ( $cust_pkg->num_cust_event -% && ( $curuser->access_right('Billing event reports') -% || $curuser->access_right('View customer billing events') -% ) -% ) { - ( <%pkg_event_link($cust_pkg)%> ) -% } - -
- -
- <% include('/elements/table-grid.html') %> -
- - Invoice details -% if ( $editi && ! $cust_pkg->get('cancel') ) { - (<% include('/elements/popup_link.html', { - 'action' => $editlink. 'I', - 'label' => 'edit', - 'actionlabel' => 'Edit invoice details', - 'color' => '#333399', - 'width' => 763, - }) - %>) -% } - -
 - <% $cust_pkg_detail->detail |h %>
- -% } else { - -% if ( $editi && ! $cust_pkg->get('cancel') ) { - - ( <% include('/elements/popup_link.html', { - 'action' => $editlink. 'I', - 'label' => 'Add invoice details', - 'actionlabel' => 'Add invoice details', - 'color' => '#333399', - 'width' => 763, - }) - %> ) - -% } - -% } - -% if ( $cust_pkg->cust_pkg_detail('C') ) { - - <% include('/elements/table-grid.html') %> - - - - Comments -% if ( $editc ) { - (<% include('/elements/popup_link.html', { - 'action' => $editlink. 'C', - 'label' => 'edit', - 'actionlabel' => 'Edit comments', - 'color' => '#333399', - 'width' => 763, - }) - %>) -% } - - - -% foreach my $cust_pkg_detail ( $cust_pkg->cust_pkg_detail('C') ) { - -  - <% $cust_pkg_detail->detail |h %> - -% } - - -% } else { - -% if ( $editc ) { - - ( <% include('/elements/popup_link.html', { - 'action' => $editlink. 'C', - 'label' => 'Add comments', - 'actionlabel' => 'Add comments', - 'color' => '#333399', - 'width' => 763, - }) - %> ) - -% } - -% } - - -% } - - - - - - - -% -% sub myfreq { -% my $part_pkg = shift; -% my $freq = $part_pkg->freq_pretty; -% $freq =~ s/ / /g; -% $freq; -% } -% -% #this should use cust_pkg->status and cust_pkg->statuscolor eventually -% #my $colspan = $conf->exists('cust_pkg-display_times') ? 8 : 4; -% #my $width = $conf->exists('cust_pkg-display_times') ? '38%' : '56%'; -% -% #false laziness w/edit/REAL_cust_pkg.cgi -% my( $billed_or_prepaid, $last_bill_or_renewed, $next_bill_or_prepaid_until ); -% unless ( $part_pkg->is_prepaid ) { -% $billed_or_prepaid = 'billed'; -% $last_bill_or_renewed = 'Last bill'; -% $next_bill_or_prepaid_until = 'Next bill'; -% } else { -% $billed_or_prepaid = 'prepaid'; -% $last_bill_or_renewed = 'Renewed'; -% $next_bill_or_prepaid_until = 'Prepaid until'; -% } -% -% -% if ( $cust_pkg->get('cancel') ) { #status: cancelled -% my $cpr = $cust_pkg->last_cust_pkg_reason('cancel'); - - <% pkg_status_row($cust_pkg, 'Cancelled', 'cancel', 'color'=>'FF0000', conf=>$conf ) %> - - <% pkg_status_row_colspan( - ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '', - 'align' => 'right', 'color' => 'ff0000', 'size' => '-2', - ) - %> - -% unless ( $cust_pkg->get('setup') ) { - - <% pkg_status_row_colspan('Never billed') %> - -% } else { - - <% pkg_status_row( $cust_pkg, 'Setup', 'setup', conf=>$conf ) %> - <% pkg_status_row_changed( $cust_pkg, conf=>$conf ) %> - <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', conf=>$conf, curuser=>$curuser ) %> - <% pkg_status_row_if( $cust_pkg, 'Suspended', 'susp', conf=>$conf, curuser=>$curuser ) %> - -% } -% -% } else { -% -% if ( $cust_pkg->get('susp') ) { #status: suspended -% my $cpr = $cust_pkg->last_cust_pkg_reason('susp'); - - <% pkg_status_row( $cust_pkg, 'Suspended', 'susp', 'color'=>'FF9900', conf=>$conf ) %> - - <% pkg_status_row_colspan( - ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '', - 'align' => 'right', 'color' => 'FF9900', 'size' => '-2', - ) - %> - -% unless ( $cust_pkg->get('setup') ) { - <% pkg_status_row_colspan('Never billed') %> -% } else { - <% pkg_status_row($cust_pkg, 'Setup', 'setup', conf=>$conf ) %> -% } - - <% pkg_status_row_changed( $cust_pkg, conf=>$conf ) %> - <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', conf=>$conf, curuser=>$curuser ) %> -% # pkg_status_row($cust_pkg, 'Next bill', 'bill', conf=>$conf) - <% pkg_status_row_if( $cust_pkg, 'Expires', 'expire', conf=>$conf, curuser=>$curuser ) %> +% my %iopt = ( +% 'bgcolor' => $bgcolor, +% 'cust_pkg' => $cust_pkg, +% 'part_pkg' => $cust_pkg->part_pkg, +% ); + - + <% include('packages/package.html', %iopt) %> + <% include('packages/status.html', %iopt) %> + <% include('packages/location.html', %iopt) %> + <% include('packages/services.html', %iopt) %> -% } else { #status: active -% -% unless ( $cust_pkg->get('setup') ) { #not setup -% -% unless ( $part_pkg->freq ) { - - <% pkg_status_row_colspan('Not yet billed (one-time charge)') %> - - - - - -% } else { - - <% pkg_status_row_colspan("Not yet billed ($billed_or_prepaid ". myfreq($part_pkg). ')' ) %> - -% } -% -% } else { #setup -% -% unless ( $part_pkg->freq ) { - - <% pkg_status_row_colspan('One-time charge') %> - - <% pkg_status_row($cust_pkg, 'Billed', 'setup', conf=>$conf) %> - -% } else { -% -% if (scalar($cust_pkg->overlimit)) { - - <% pkg_status_row_colspan( - 'Overlimit', - $billed_or_prepaid. ' '. myfreq($part_pkg), - 'color' => 'FFD000', - ) - %> - -% } else { - <% pkg_status_row_colspan( - 'Active', - $billed_or_prepaid. ' '. myfreq($part_pkg), - 'color' => '00CC00', - ) - %> -% } - - <% pkg_status_row($cust_pkg, 'Setup', 'setup', conf=>$conf) %> - -% } -% -% } -% my $autosuspend = pkg_autosuspend_time( $cust_pkg ); -% $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend; - - <% pkg_status_row_changed( $cust_pkg, conf=>$conf ) %> - <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', conf=>$conf, curuser=>$curuser ) %> - <% pkg_status_row_if( $cust_pkg, $next_bill_or_prepaid_until, 'bill', conf=>$conf, curuser=>$curuser ) %> - <% pkg_status_row_if($cust_pkg, 'Will automatically suspend by', 'autosuspend', conf=>$conf) %> - <% pkg_status_row_if( $cust_pkg, 'Will suspend on', 'adjourn', conf=>$conf, curuser=>$curuser ) %> - <% pkg_status_row_if( $cust_pkg, 'Expires', 'expire', conf=>$conf, curuser=>$curuser ) %> - -% if ( $part_pkg->freq ) { - - - - -% } -% -% } -% } - -
> - -% if ( $curuser->access_right('Unsuspend customer package') ) { - ( <% pkg_unsuspend_link($cust_pkg) %> ) -% } -% if ( $curuser->access_right('Cancel customer package immediately') ) { - ( <% pkg_cancel_link($cust_pkg) %> ) -% } - -
> - -% if ( $curuser->access_right('Cancel customer package immediately') ) { - ( <% pkg_cancel_link($cust_pkg) %> ) -% } - -
> - -% if ( $curuser->access_right('Suspend customer package') ) { - ( <% pkg_suspend_link($cust_pkg) %> ) -% } -% if ( $curuser->access_right('Suspend customer package later') ) { - ( <% pkg_adjourn_link($cust_pkg) %> ) -% } -% if ( $curuser->access_right('Delay suspension events') ) { - ( <% pkg_delay_link($cust_pkg) %> ) -% } -% if ( $curuser->access_right('Cancel customer package immediately') ) { - ( <% pkg_cancel_link($cust_pkg) %> ) -% } -% if ( $curuser->access_right('Cancel customer package later') ) { - ( <% pkg_expire_link($cust_pkg) %> ) -% } - - -
- - - - - -% #foreach my $svcpart (sort {$a->{svcpart} <=> $b->{svcpart}} @{$pkg->{svcparts}}) { -% foreach my $part_svc ( $cust_pkg->part_svc ) { - -% #foreach my $service (@{$svcpart->{services}}) { -% foreach my $cust_svc ( @{ $part_svc->cust_pkg_svc } ) { - - - - - - - - - - - - - - - - -% } - -% if ( ! $cust_pkg->get('cancel') -% && $curuser->access_right('Provision customer service') -% && $part_svc->num_avail -% ) { - - - - - -% } - -% } - -
<% FS::UI::Web::svc_link($m, $part_svc, $cust_svc) %><% FS::UI::Web::svc_label_link($m, $part_svc, $cust_svc) %><% FS::UI::Web::svc_export_links($m, $part_svc, $cust_svc) %>
- - <% $cust_svc->overlimit ? "Overlimit: ". time2str('%b %o %Y' . ($conf->exists('cust_pkg-display_times') ? ' %l:%M %P' : ''), $cust_svc->overlimit) : '' %> -
- -% if ( $curuser->access_right('Recharge customer service') -% && $part_svc->svcdb eq 'svc_acct' -% && ( $cust_svc->svc_x->seconds ne '' -% || $cust_svc->svc_x->upbytes ne '' -% || $cust_svc->svc_x->downbytes ne '' -% || $cust_svc->svc_x->totalbytes ne '' -% ) -% ) { - ( <%svc_recharge_link($cust_svc)%> ) -% } - - -% if ( $curuser->access_right('Unprovision customer service') ) { - ( <%svc_unprovision_link($cust_svc)%> ) -% } -
- <% svc_provision_link($cust_pkg, $part_svc, $conf, $curuser) %> -
- -% } #end display packages -% - +% } -% } else { +% } else {
% } + % if ( $cgi->param('fragment') =~ /^cust_pkg(\d+)$/ ) {