From 705f7d564546e7211844773f3566a89f0ae87a2c Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 10 Jan 2009 23:56:59 +0000 Subject: [PATCH] implement package changes w/location change, RT#4499 --- FS/FS/Conf.pm | 8 + FS/FS/Schema.pm | 35 +++- FS/FS/cust_main.pm | 246 ++++++++++++++--------- FS/FS/cust_pkg.pm | 177 ++++++++++++++-- httemplate/edit/process/change-cust_pkg.html | 46 +++++ httemplate/edit/process/cust_pkg.cgi | 64 ++---- httemplate/elements/location.html | 6 +- httemplate/elements/tr-select-cust_location.html | 4 +- httemplate/misc/change_pkg.cgi | 66 +++--- httemplate/view/cust_main/packages/location.html | 23 +++ httemplate/view/cust_main/packages/package.html | 12 +- 11 files changed, 483 insertions(+), 204 deletions(-) create mode 100644 httemplate/edit/process/change-cust_pkg.html diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index a7a0b45c5..1e594e5b3 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -767,6 +767,14 @@ worry that config_items is freeside-specific and icky. }, { + 'key' => 'invoice_subject', + 'section' => 'billing', + 'description' => 'Subject: header on email invoices. Defaults to "Invoice". The following substitutions are available: $name, $name_short, $invoice_number, and $invoice_date.', + 'type' => 'text', + 'per_agent' => 1, + }, + + { 'key' => 'invoice_template', 'section' => 'billing', 'description' => 'Text template file for invoices. Used if no invoice_html template is defined, and also seen by users using non-HTML capable mail clients. See the billing documentation for details.', diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index ecf017e3b..2c3c9670d 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -661,13 +661,20 @@ sub tables_hashref { 'primary_key' => 'custnum', 'unique' => [ [ 'agentnum', 'agent_custid' ] ], #'index' => [ ['last'], ['company'] ], - 'index' => [ ['last'], [ 'company' ], [ 'referral_custnum' ], - [ 'daytime' ], [ 'night' ], [ 'fax' ], [ 'refnum' ], - [ 'county' ], [ 'state' ], [ 'country' ], [ 'zip' ], + 'index' => [ + [ 'agentnum' ], [ 'refnum' ], [ 'custbatch' ], + [ 'referral_custnum' ], + [ 'payby' ], [ 'paydate' ], + #billing + [ 'last' ], [ 'company' ], + [ 'county' ], [ 'state' ], [ 'country' ], + [ 'zip' ], + [ 'daytime' ], [ 'night' ], [ 'fax' ], + #shipping [ 'ship_last' ], [ 'ship_company' ], + [ 'ship_county' ], [ 'ship_state' ], [ 'ship_country' ], + [ 'ship_zip' ], [ 'ship_daytime' ], [ 'ship_night' ], [ 'ship_fax' ], - [ 'payby' ], [ 'paydate' ], - [ 'agentnum' ], [ 'custbatch' ], ], }, @@ -975,6 +982,7 @@ sub tables_hashref { 'change_date', @date_type, '', '', 'change_pkgnum', 'int', 'NULL', '', '', '', 'change_pkgpart', 'int', 'NULL', '', '', '', + 'change_locationnum', 'int', 'NULL', '', '', '', 'manual_flag', 'char', 'NULL', 1, '', '', 'quantity', 'int', 'NULL', '', '', '', ], @@ -1994,7 +2002,7 @@ sub tables_hashref { ], 'primary_key' => 'acctid', 'unique' => [], - 'index' => [ [ 'calldate' ], [ 'dst' ], [ 'accountcode' ], [ 'freesidestatus' ], [ 'cdrbatch' ], ], + 'index' => [ [ 'calldate' ], [ 'src' ], [ 'dst' ], [ 'charged_party' ], [ 'accountcode' ], [ 'freesidestatus' ], [ 'cdrbatch' ], ], }, 'cdr_calltype' => { @@ -2039,6 +2047,21 @@ sub tables_hashref { 'index' => [], }, + #'cdr_file' => { + # 'columns' => [ + # 'filenum', 'serial', '', '', '', '', + # 'filename', 'varchar', '', '', '', '', + # 'status', 'varchar', 'NULL', '', '', '', + # ], + # 'primary_key' => 'filenum', + # 'unique' => [ [ 'filename' ], ], #just change the index if we need to + # # agent-virtualize or have a customer + # # with dup-filename needs or something + # # (only used by cdr.http_and_import for + # # chrissakes) + # 'index' => [], + #}, + 'inventory_item' => { 'columns' => [ 'itemnum', 'serial', '', '', '', '', diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 94280a4db..7a350c1a1 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -659,85 +659,9 @@ sub _copy_skel { } -=item order_pkgs HASHREF, [ SECONDSREF, [ , OPTION => VALUE ... ] ] - -Like the insert method on an existing record, this method orders a package -and included services atomicaly. Pass a Tie::RefHash data structure to this -method containing FS::cust_pkg and FS::svc_I objects. There should -be a better explanation of this, but until then, here's an example: - - use Tie::RefHash; - tie %hash, 'Tie::RefHash'; #this part is important - %hash = ( - $cust_pkg => [ $svc_acct ], - ... - ); - $cust_main->order_pkgs( \%hash, \'0', 'noexport'=>1 ); - -Services can be new, in which case they are inserted, or existing unaudited -services, in which case they are linked to the newly-created package. - -Currently available options are: I and I. - -If I is set, all provisioning jobs will have a dependancy -on the supplied jobnum (they will not run until the specific job completes). -This can be used to defer provisioning until some action completes (such -as running the customer's credit card successfully). - -The I option is deprecated. If I is set true, no -provisioning jobs (exports) are scheduled. (You can schedule them later with -the B method for each cust_pkg object. Using the B method -on the cust_main object is not recommended, as existing services will also be -reexported.) - -=cut - -sub order_pkgs { - my $self = shift; - my $cust_pkgs = shift; - my $seconds = shift; - my %options = @_; - - warn "$me order_pkgs called with options ". - join(', ', map { "$_: $options{$_}" } keys %options ). "\n" - if $DEBUG; - - 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; - - local $FS::svc_Common::noexport_hack = 1 if $options{'noexport'}; - - foreach my $cust_pkg ( keys %$cust_pkgs ) { - - my $error = $self->order_pkg( 'cust_pkg' => $cust_pkg, - 'svcs' => $cust_pkgs->{$cust_pkg}, - 'seconds' => $seconds, - 'depend_jobnum' => $options{'depend_jobnum'}, - ); - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; - } - - } - - $dbh->commit or die $dbh->errstr if $oldAutoCommit; - ''; #no error -} - =item order_pkg HASHREF | OPTION => VALUE ... -Orders a single package. This is the preferred and most flexible method for -ordering a single package, including the ability to set a (new or existing) -location as well as insert services. +Orders a single package. Options may be passed as a list of key/value pairs or as a hash reference. Options are: @@ -837,6 +761,81 @@ sub order_pkg { } +=item order_pkgs HASHREF, [ SECONDSREF, [ , OPTION => VALUE ... ] ] + +Like the insert method on an existing record, this method orders multiple +packages and included services atomicaly. Pass a Tie::RefHash data structure +to this method containing FS::cust_pkg and FS::svc_I objects. +There should be a better explanation of this, but until then, here's an +example: + + use Tie::RefHash; + tie %hash, 'Tie::RefHash'; #this part is important + %hash = ( + $cust_pkg => [ $svc_acct ], + ... + ); + $cust_main->order_pkgs( \%hash, \'0', 'noexport'=>1 ); + +Services can be new, in which case they are inserted, or existing unaudited +services, in which case they are linked to the newly-created package. + +Currently available options are: I and I. + +If I is set, all provisioning jobs will have a dependancy +on the supplied jobnum (they will not run until the specific job completes). +This can be used to defer provisioning until some action completes (such +as running the customer's credit card successfully). + +The I option is deprecated. If I is set true, no +provisioning jobs (exports) are scheduled. (You can schedule them later with +the B method for each cust_pkg object. Using the B method +on the cust_main object is not recommended, as existing services will also be +reexported.) + +=cut + +sub order_pkgs { + my $self = shift; + my $cust_pkgs = shift; + my $seconds = shift; + my %options = @_; + + warn "$me order_pkgs called with options ". + join(', ', map { "$_: $options{$_}" } keys %options ). "\n" + if $DEBUG; + + 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; + + local $FS::svc_Common::noexport_hack = 1 if $options{'noexport'}; + + foreach my $cust_pkg ( keys %$cust_pkgs ) { + + my $error = $self->order_pkg( 'cust_pkg' => $cust_pkg, + 'svcs' => $cust_pkgs->{$cust_pkg}, + 'seconds' => $seconds, + 'depend_jobnum' => $options{'depend_jobnum'}, + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; #no error +} + =item recharge_prepay IDENTIFIER | PREPAY_CREDIT_OBJ [ , AMOUNTREF, SECONDSREF, UPBYTEREF, DOWNBYTEREF ] Recharges this (existing) customer with the specified prepaid card (see @@ -3896,7 +3895,7 @@ sub realtime_bop { my $templ_hash = { error => $transaction->error_message }; my $error = send_email( - 'from' => $conf->config('invoice_from'), + 'from' => $conf->config('invoice_from', $self->agentnum ), 'to' => [ grep { $_ ne 'POST' } $self->invoicing_list ], 'subject' => 'Your payment could not be processed', 'body' => [ $template->fill_in(HASH => $templ_hash) ], @@ -5391,6 +5390,35 @@ sub ship_name { } } +=item name_short + +Returns a name string for this customer, either "Company" or "First Last". + +=cut + +sub name_short { + my $self = shift; + $self->company !~ /^\s*$/ ? $self->company : $self->contact_firstlast; +} + +=item ship_name_short + +Returns a name string for this (service/shipping) contact, either "Company" +or "First Last". + +=cut + +sub ship_name_short { + my $self = shift; + if ( $self->get('ship_last') ) { + $self->ship_company !~ /^\s*$/ + ? $self->ship_company + : $self->ship_contact_firstlast; + } else { + $self->name_company_or_firstlast; + } +} + =item contact Returns this customer's full (billing) contact name only, "Last, First" @@ -5415,6 +5443,30 @@ sub ship_contact { : $self->contact; } +=item contact_firstlast + +Returns this customers full (billing) contact name only, "First Last". + +=cut + +sub contact_firstlast { + my $self = shift; + $self->first. ' '. $self->get('last'); +} + +=item ship_contact_firstlast + +Returns this customer's full (shipping) contact name only, "First Last". + +=cut + +sub ship_contact_firstlast { + my $self = shift; + $self->get('ship_last') + ? $self->first. ' '. $self->get('ship_last') + : $self->contact_firstlast; +} + =item country_full Returns this customer's full country name @@ -6717,18 +6769,19 @@ I<$expdate> - the expiration of the customer payment in seconds from epoch =cut sub notify { - my ($customer, $template, %options) = @_; + my ($self, $template, %options) = @_; return unless $conf->exists($template); - my $from = $conf->config('invoice_from') if $conf->exists('invoice_from'); + my $from = $conf->config('invoice_from', $self->agentnum) + if $conf->exists('invoice_from', $self->agentnum); $from = $options{from} if exists($options{from}); - my $to = join(',', $customer->invoicing_list_emailonly); + my $to = join(',', $self->invoicing_list_emailonly); $to = $options{to} if exists($options{to}); - my $subject = "Notice from " . $conf->config('company_name') - if $conf->exists('company_name'); + my $subject = "Notice from " . $conf->config('company_name', $self->agentnum) + if $conf->exists('company_name', $self->agentnum); $subject = $options{subject} if exists($options{subject}); my $notify_template = new Text::Template (TYPE => 'ARRAY', @@ -6739,16 +6792,17 @@ sub notify { $notify_template->compile() or die "can't compile template: Text::Template::ERROR"; - $FS::notify_template::_template::company_name = $conf->config('company_name'); + $FS::notify_template::_template::company_name = + $conf->config('company_name', $self->agentnum); $FS::notify_template::_template::company_address = - join("\n", $conf->config('company_address') ). "\n"; - - my $paydate = $customer->paydate || '2037-12-31'; - $FS::notify_template::_template::first = $customer->first; - $FS::notify_template::_template::last = $customer->last; - $FS::notify_template::_template::company = $customer->company; - $FS::notify_template::_template::payinfo = $customer->mask_payinfo; - my $payby = $customer->payby; + join("\n", $conf->config('company_address', $self->agentnum) ). "\n"; + + my $paydate = $self->paydate || '2037-12-31'; + $FS::notify_template::_template::first = $self->first; + $FS::notify_template::_template::last = $self->last; + $FS::notify_template::_template::company = $self->company; + $FS::notify_template::_template::payinfo = $self->mask_payinfo; + my $payby = $self->payby; my ($payyear,$paymonth,$payday) = split (/-/,$paydate); my $expire_time = timelocal(0,0,0,$payday,--$paymonth,$payyear); @@ -6848,10 +6902,10 @@ sub generate_letter { ); if ( length($retadd) ) { $letter_data{returnaddress} = $retadd; - } elsif ( grep /\S/, $conf->config('company_address') ) { + } elsif ( grep /\S/, $conf->config('company_address', $self->agentnum) ) { $letter_data{returnaddress} = join( '\\*'."\n", map s/( {2,})/'~' x length($1)/eg, - $conf->config('company_address') + $conf->config('company_address', $self->agentnum) ); } else { $letter_data{returnaddress} = '~'; @@ -6860,7 +6914,7 @@ sub generate_letter { $letter_data{conf_dir} = "$FS::UID::conf_dir/conf.$FS::UID::datasrc"; - $letter_data{company_name} = $conf->config('company_name'); + $letter_data{company_name} = $conf->config('company_name', $self->agentnum); my $dir = $FS::UID::conf_dir."/cache.". $FS::UID::datasrc; my $fh = new File::Temp( TEMPLATE => 'letter.'. $self->custnum. '.XXXXXXXX', @@ -6910,6 +6964,8 @@ sub print { do_print [ $self->print_ps($template) ]; } +#these three subs should just go away once agent stuff is all config overrides + sub agent_template { my $self = shift; $self->_agent_plandata('agent_templatename'); diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 25985ce1f..e2ca871d0 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -174,6 +174,10 @@ Previous pkgnum Previous pkgpart +=item change_locationnum + +Previous locationnum + =back Note: setup, last_bill, bill, adjourn, susp, expire, cancel and change_date @@ -620,7 +624,7 @@ sub cancel { if ( !$options{'quiet'} && $conf->exists('emailcancel') && @invoicing_list ) { my $conf = new FS::Conf; my $error = send_email( - 'from' => $conf->config('invoice_from'), + 'from' => $conf->config('invoice_from', $self->cust_main->agentnum), 'to' => \@invoicing_list, 'subject' => ( $conf->config('cancelsubject') || 'Cancellation Notice' ), 'body' => [ map "$_\n", $conf->config('cancelmessage') ], @@ -803,7 +807,8 @@ sub suspend { if ( $conf->config('suspend_email_admin') ) { my $error = send_email( - 'from' => $conf->config('invoice_from'), #??? well as good as any + 'from' => $conf->config('invoice_from', $self->cust_main->agentnum), + #invoice_from ??? well as good as any 'to' => $conf->config('suspend_email_admin'), 'subject' => 'FREESIDE NOTIFICATION: Customer package suspended', 'body' => [ @@ -1001,6 +1006,148 @@ sub unadjourn { } + +=item change HASHREF | OPTION => VALUE ... + +Changes this package: cancels it and creates a new one, with a different +pkgpart or locationnum or both. All services are transferred to the new +package (no change will be made if this is not possible). + +Options may be passed as a list of key/value pairs or as a hash reference. +Options are: + +=over 4 + +=item locaitonnum + +New locationnum, to change the location for this package. + +=item cust_location + +New FS::cust_location object, to create a new location and assign it +to this package. + +=item pkgpart + +New pkgpart (see L). + +=item refnum + +New refnum (see L). + +=back + +At least one option must be specified (otherwise, what's the point?) + +Returns either the new FS::cust_pkg object or a scalar error. + +For example: + + my $err_or_new_cust_pkg = $old_cust_pkg->change + +=cut + +#some false laziness w/order +sub change { + my $self = shift; + my $opt = ref($_[0]) ? shift : { @_ }; + +# my ($custnum, $pkgparts, $remove_pkgnum, $return_cust_pkg, $refnum) = @_; +# + + my $conf = new FS::Conf; + + # Transactionize this whole mess + 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; + + my $error; + + my %hash = (); + + my $time = time; + + #$hash{$_} = $self->$_() foreach qw( last_bill bill ); + + #$hash{$_} = $self->$_() foreach qw( setup ); + + $hash{'setup'} = $time if $self->setup; + + $hash{'change_date'} = $time; + $hash{"change_$_"} = $self->$_() + foreach qw( pkgnum pkgpart locationnum ); + + if ( $opt->{'cust_location'} && + ( ! $opt->{'locationnum'} || $opt->{'locationnum'} == -1 ) ) { + $error = $opt->{'cust_location'}->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "inserting cust_location (transaction rolled back): $error"; + } + $opt->{'locationnum'} = $opt->{'cust_location'}->locationnum; + } + + # Create the new package. + my $cust_pkg = new FS::cust_pkg { + custnum => $self->custnum, + pkgpart => ( $opt->{'pkgpart'} || $self->pkgpart ), + refnum => ( $opt->{'refnum'} || $self->refnum ), + locationnum => ( $opt->{'locationnum'} || $self->locationnum ), + %hash, + }; + + $error = $cust_pkg->insert( 'change' => 1 ); + if ($error) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + # Transfer services and cancel old package. + + $error = $self->transfer($cust_pkg); + if ($error and $error == 0) { + # $old_pkg->transfer failed. + $dbh->rollback if $oldAutoCommit; + return $error; + } + + if ( $error > 0 && $conf->exists('cust_pkg-change_svcpart') ) { + warn "trying transfer again with change_svcpart option\n" if $DEBUG; + $error = $self->transfer($cust_pkg, 'change_svcpart'=>1 ); + if ($error and $error == 0) { + # $old_pkg->transfer failed. + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + if ($error > 0) { + # Transfers were successful, but we still had services left on the old + # package. We can't change the package under this circumstances, so abort. + $dbh->rollback if $oldAutoCommit; + return "Unable to transfer all services from package ". $self->pkgnum; + } + + #Good to go, cancel old package. + $error = $self->cancel( quiet=>1 ); + if ($error) { + $dbh->rollback; + return $error; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + $cust_pkg; + +} + =item last_bill Returns the last bill date, or if there is no last bill date, the setup date. @@ -2246,8 +2393,8 @@ sub order { my $dbh = dbh; my $error; - my $cust_main = qsearchs('cust_main', { custnum => $custnum }); - return "Customer not found: $custnum" unless $cust_main; +# my $cust_main = qsearchs('cust_main', { custnum => $custnum }); +# return "Customer not found: $custnum" unless $cust_main; my @old_cust_pkg = map { qsearchs('cust_pkg', { pkgnum => $_ }) } @$remove_pkgnum; @@ -2257,15 +2404,19 @@ sub order { my %hash = (); if ( scalar(@old_cust_pkg) == 1 && scalar(@$pkgparts) == 1 ) { - my $time = time; + my $err_or_cust_pkg = + $old_cust_pkg[0]->change( 'pkgpart' => $pkgparts->[0], + 'refnum' => $refnum, + ); - #$hash{$_} = $old_cust_pkg[0]->$_() foreach qw( last_bill bill ); - - #$hash{$_} = $old_cust_pkg[0]->$_() foreach qw( setup ); - $hash{'setup'} = $time if $old_cust_pkg[0]->setup; + unless (ref($err_or_cust_pkg)) { + $dbh->rollback if $oldAutoCommit; + return $err_or_cust_pkg; + } + + push @$return_cust_pkg, $err_or_cust_pkg; + return ''; - $hash{'change_date'} = $time; - $hash{"change_$_"} = $old_cust_pkg[0]->$_() foreach qw( pkgnum pkgpart ); } # Create the new packages. @@ -2328,8 +2479,10 @@ sub order { =item bulk_change PKGPARTS_ARYREF, REMOVE_PKGNUMS_ARYREF [ RETURN_CUST_PKG_ARRAYREF ] +A bulk change method to change packages for multiple customers. + PKGPARTS is a list of pkgparts specifying the the billing item definitions (see -L) to order for this customer. Duplicates are of course +L) to order for each customer. Duplicates are of course permitted. REMOVE_PKGNUMS is an list of pkgnums specifying the billing items to diff --git a/httemplate/edit/process/change-cust_pkg.html b/httemplate/edit/process/change-cust_pkg.html new file mode 100644 index 000000000..7356e6122 --- /dev/null +++ b/httemplate/edit/process/change-cust_pkg.html @@ -0,0 +1,46 @@ +% if ($error) { +% $cgi->param('error', $error); +% $cgi->redirect(popurl(3). 'misc/change_pkg.cgi?'. $cgi->query_string ); +% } else { + + <% header("Package changed") %> + + + + +% } +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $cust_pkg = qsearchs({ + #'select' => 'cust_pkg.*', + 'table' => 'cust_pkg', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'pkgnum' => scalar($cgi->param('pkgnum')), }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, +}); +die 'unknown pkgnum' unless $cust_pkg; + +my %change = map { $_ => scalar($cgi->param($_)) } + qw( locationnum pkgpart ); + +if ( $cgi->param('locationnum') == -1 ) { + my $cust_location = new FS::cust_location { + 'custnum' => $cust_pkg->custnum, + map { $_ => scalar($cgi->param($_)) } + qw( address1 address2 city county state zip country ) + }; + $change{'cust_location'} = $cust_location; +} + +my $pkg_or_error = $cust_pkg->change( \%change ); + +my $error = ref($pkg_or_error) ? '' : $pkg_or_error; + + diff --git a/httemplate/edit/process/cust_pkg.cgi b/httemplate/edit/process/cust_pkg.cgi index 272ddcc47..94c084eae 100755 --- a/httemplate/edit/process/cust_pkg.cgi +++ b/httemplate/edit/process/cust_pkg.cgi @@ -1,22 +1,15 @@ % if ($error) { % $cgi->param('error', $error); -% $cgi->redirect(popurl(3). $error_redirect. '?'. $cgi->query_string ); -% } elsif ( $action eq 'change' ) { - - <% header("Package changed") %> - - - - -% } elsif ( $action eq 'bulk' ) { -<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum") %> +% $cgi->redirect(popurl(3). 'edit/cust_pkg.cgi?'. $cgi->query_string ); % } else { -% die "guru exception #5: action is neither change nor bulk!"; -% } +<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum") %> <%init> +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Bulk change customer packages'); + my $error = ''; #untaint custnum @@ -28,46 +21,19 @@ my @remove_pkgnums = map { $1; } $cgi->param('remove_pkg'); -my $curuser = $FS::CurrentUser::CurrentUser; - my( $action, $error_redirect ) = ( '', '' ); my @pkgparts = (); -if ( $cgi->param('action') eq 'change' ) { #came from misc/change_pkg.cgi - - $action = 'change'; - $error_redirect = "misc/change_pkg.cgi"; - die "access denied" - unless $curuser->access_right('Change customer package'); - - if ( $cgi->param('new_pkgpart') =~ /^(\d+)$/ ) { - @pkgparts = ($1); - } else { - $error = 'Select a new package'; - } - -} elsif ( $cgi->param('action') eq 'bulk' ) { #came from edit/cust_pkg.cgi - - $action = 'bulk'; - $error_redirect = "edit/cust_pkg.cgi"; - - die "access denied" - unless $curuser->access_right('Bulk change customer packages'); - - foreach my $pkgpart ( map /^pkg(\d+)$/ ? $1 : (), $cgi->param ) { - if ( $cgi->param("pkg$pkgpart") =~ /^(\d+)$/ ) { - my $num_pkgs = $1; - while ( $num_pkgs-- ) { - push @pkgparts,$pkgpart; - } - } else { - $error = "Illegal quantity"; - last; +foreach my $pkgpart ( map /^pkg(\d+)$/ ? $1 : (), $cgi->param ) { + if ( $cgi->param("pkg$pkgpart") =~ /^(\d+)$/ ) { + my $num_pkgs = $1; + while ( $num_pkgs-- ) { + push @pkgparts,$pkgpart; } + } else { + $error = "Illegal quantity"; + last; } - -} else { - die "guru exception #5: action is neither change nor bulk!"; } $error ||= FS::cust_pkg::order($custnum,\@pkgparts,\@remove_pkgnums); diff --git a/httemplate/elements/location.html b/httemplate/elements/location.html index f21b8ad01..b0b30d3b1 100644 --- a/httemplate/elements/location.html +++ b/httemplate/elements/location.html @@ -22,7 +22,7 @@ Example: NAME = "<%$pre%>address1" ID = "<%$pre%>address1" VALUE = "<% $object->get($pre.'address1') |h %>" - SIZE = 70 + SIZE = 58 onChange = "<% $onchange %>" <% $disabled %> <% $style %> @@ -37,7 +37,7 @@ Example: NAME = "<%$pre%>address2" ID = "<%$pre%>address2" VALUE = "<% $object->get($pre.'address2') |h %>" - SIZE = 70 + SIZE = 58 onChange = "<% $onchange %>" <% $disabled %> <% $style %> @@ -56,7 +56,7 @@ Example: <% $disabled %> <% $style %> > - + ><%$r%>County <% include('/elements/select-county.html', %select_hash ) %> diff --git a/httemplate/elements/tr-select-cust_location.html b/httemplate/elements/tr-select-cust_location.html index b62c65c03..5b023f165 100644 --- a/httemplate/elements/tr-select-cust_location.html +++ b/httemplate/elements/tr-select-cust_location.html @@ -118,7 +118,7 @@ Example: - Service location + Service location - - +
+ <% ntable('#cccccc') %> - Current package:  - - <% $part_pkg->pkgpart %>: <% $part_pkg->pkg %> - <% $part_pkg->comment %> + Current package + + <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><% $part_pkg->pkg |h %> - <% $part_pkg->comment |h %> - New package: - <% include('/elements/select-cust-part_pkg.html', - 'cust_main' => $cust_main, - 'element_name' => 'new_pkgpart', - 'extra_sql' => ' AND pkgpart != '. $cust_pkg->pkgpart, - 'curr_value' => ( $cgi->param('error') - ? scalar($cgi->param('new_pkgpart')) - : '' - ), - ) - %> + New package + + <% include('/elements/select-cust-part_pkg.html', + 'cust_main' => $cust_main, + 'element_name' => 'pkgpart', + #'extra_sql' => ' AND pkgpart != '. $cust_pkg->pkgpart, + 'curr_value' => scalar($cgi->param('pkgpart')), + ) + %> + <% include('/elements/tr-select-cust_location.html', + 'cgi' => $cgi, + 'cust_main' => $cust_main, + ) + %> +
@@ -42,28 +44,28 @@ <%init> +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Change customer package'); - -my $pkgnum; -if ( $cgi->param('error') ) { - $pkgnum = ($cgi->param('remove_pkg'))[0]; -} else { - $pkgnum = $cgi->param('pkgnum'); -} + unless $curuser->access_right('Change customer package'); + +my $pkgnum = scalar($cgi->param('pkgnum')); $pkgnum =~ /^(\d+)$/ or die "illegal pkgnum $pkgnum"; $pkgnum = $1; -my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } ) - or die "unknown pkgnum $pkgnum"; -my $custnum = $cust_pkg->custnum; - -my $conf = new FS::Conf; +my $cust_pkg = + qsearchs({ + 'table' => 'cust_pkg', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'pkgnum' => $pkgnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, + }) or die "unknown pkgnum $pkgnum"; my $cust_main = $cust_pkg->cust_main or die "can't get cust_main record for custnum ". $cust_pkg->custnum. " ( pkgnum ". cust_pkg->pkgnum. ")"; -my $agent = $cust_main->agent; my $part_pkg = $cust_pkg->part_pkg; diff --git a/httemplate/view/cust_main/packages/location.html b/httemplate/view/cust_main/packages/location.html index 0f58b36fc..3c641304a 100644 --- a/httemplate/view/cust_main/packages/location.html +++ b/httemplate/view/cust_main/packages/location.html @@ -19,17 +19,40 @@ +% if ($FS::CurrentUser::CurrentUser->access_right('Change customer package')) { + + ( <%pkg_change_location_link($cust_pkg)%> ) + +% } + <%init> my %opt = @_; +my $conf = new FS::Conf; + my $bgcolor = $opt{'bgcolor'}; my $cust_pkg = $opt{'cust_pkg'}; my $part_pkg = $opt{'part_pkg'}; my $conf = new FS::Conf; my $countrydefault = $conf->config('countrydefault') || 'US'; +my $statedefault = $conf->config('statedefault') + || ($countrydefault eq 'US' ? 'CA' : ''); my $loc = $cust_pkg->cust_location_or_main; +sub pkg_change_location_link { + my $cust_pkg = shift; + my $pkgpart = $cust_pkg->pkgpart; + include( '/elements/popup_link-cust_pkg.html', + 'action' => $p. "misc/change_pkg.cgi?locationnum=-1;pkgpart=$pkgpart;". + "address1=;address2=;city=;county=;state=$statedefault;". + "zip=;country=$countrydefault", + 'label' => 'Change location', + 'actionlabel' => 'Change', + 'cust_pkg' => $cust_pkg, + ); +} + diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html index 4311d8cf2..b07e1af94 100644 --- a/httemplate/view/cust_main/packages/package.html +++ b/httemplate/view/cust_main/packages/package.html @@ -184,12 +184,14 @@ sub pkg_link { } sub pkg_change_link { + my $cust_pkg = shift; + my $locationnum = $cust_pkg->locationnum; include( '/elements/popup_link-cust_pkg.html', - 'action' => $p. 'misc/change_pkg.cgi?dummy=value', - 'label' => 'Change package', - 'actionlabel' => 'Change', - 'cust_pkg' => shift, - ) + 'action' => $p. "misc/change_pkg.cgi?locationnum=$locationnum", + 'label' => 'Change package', + 'actionlabel' => 'Change', + 'cust_pkg' => $cust_pkg, + ); } sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', 'Edit dates', @_ ); } -- 2.11.0