implemented billing fees handling: show/edit/delete

1.2@1701
Daniel Tiefnig 18 years ago
parent 1ede1b0397
commit 77b0f36253

@ -126,10 +126,10 @@ sub detail : Local {
} else {
my $product;
return unless $c->model('Provisioning')->call_prov( $c, 'billing', 'get_product',
{ product => $c->session->{voip_account}{product} },
{ handle => $c->session->{voip_account}{product} },
\$product
);
$c->session->{voip_account}{product_name} = $$product{name};
$c->session->{voip_account}{product_name} = $$product{data}{name};
}
$c->stash->{billing_features} = 1;

@ -360,6 +360,293 @@ sub do_delete_bilprof : Local {
return;
}
=head2 search_fees
Search billing profile fees and display the result.
=cut
sub search_fees : Local {
my ( $self, $c ) = @_;
$c->stash->{template} = 'tt/billing_fees.tt';
my $bilprof = $c->request->params->{bilprof};
return unless $c->model('Provisioning')->call_prov( $c, 'billing', 'get_billing_profile',
{ handle => $bilprof },
\$c->stash->{bilprof}
);
my $limit = 10;
my %filter;
my %exact;
if($c->request->params->{use_session}) {
%filter = %{ $c->session->{search_filter} };
%exact = %{ $c->session->{exact_filter} };
$c->stash->{feeerr} = $c->session->{feeerr};
delete $c->session->{feeerr};
} else {
foreach my $sf (qw(destination zone zone_detail)) {
if(( defined $c->request->params->{'search_'.$sf}
and length $c->request->params->{'search_'.$sf})
or $c->request->params->{'exact_'.$sf})
{
$filter{$sf} = $c->request->params->{'search_'.$sf} || '';
$exact{$sf} = 1 if $c->request->params->{'exact_'.$sf};
}
}
$c->session->{search_filter} = { %filter };
$c->session->{exact_filter} = { %exact };
}
foreach my $sf (qw(destination zone zone_detail)) {
# set values for webform
$c->stash->{'exact_'.$sf} = $exact{$sf};
$c->stash->{'search_'.$sf} = $filter{$sf};
next unless defined $filter{$sf};
# alter filter for SOAP call
$filter{$sf} =~ s/\*/\%/g;
$filter{$sf} =~ s/\?/\_/g;
unless($exact{$sf}) {
$filter{$sf} =~ s/^\%*/\%/;
$filter{$sf} =~ s/\%*$/\%/;
}
}
my $offset = $c->request->params->{offset} || 0;
$offset = 0 if $offset !~ /^\d+$/;
my $fee_list;
return unless $c->model('Provisioning')->call_prov( $c, 'billing', 'search_billing_profile_fees',
{ handle => $bilprof,
filter => { %filter,
limit => $limit,
offset => $limit * $offset,
},
},
\$fee_list
);
$c->stash->{searched} = 1;
if(ref $$fee_list{fees} eq 'ARRAY' and @{$$fee_list{fees}}) {
$c->stash->{fee_list} = $$fee_list{fees};
$c->stash->{total_count} = $$fee_list{total_count};
$c->stash->{offset} = $offset;
if($$fee_list{total_count} > @{$$fee_list{fees}}) {
# paginate!
$c->stash->{pagination} = admin::Utils::paginate($c, $fee_list, $offset, $limit);
$c->stash->{max_offset} = $#{$c->stash->{pagination}};
if(@{$$fee_list{fees}} == 1) {
$c->stash->{last_one} = 1;
}
}
}
return 1;
}
=head2 set_fees
Set billing profile fees from CSV data.
=cut
sub set_fees : Local {
my ( $self, $c ) = @_;
my %messages;
my @fees;
my $upload = $c->req->upload('upload_fees');
$messages{feefileerr} = 'Web.Fees.MissingFilename' unless defined $upload;
my $fees = eval { $upload->slurp };
my $bilprof = $c->request->params->{bilprof};
my $purge = $c->request->params->{purge_existing} ? 1 : 0;
my $offset = $c->request->params->{offset} || 0;
my @elements = eval { @{$c->config->{fees_csv}{element_order}} };
my $line = 0;
foreach my $fee (split /\r?\n/, $fees) {
$line++;
my %keyval;
my @values = map { length $_ ? $_ : undef } split / *, */, $fee;
unless(@elements == @values) {
$messages{feeerr} = 'Web.Fees.Fieldcount';
$c->session->{feeerr}{line} = $line;
$messages{feeerrdetail} = 'Web.Fees.FieldsFoundRequired';
$c->session->{feeerr}{detail} = scalar(@values) . '/' . scalar(@elements);
last;
}
@keyval{@elements} = @values;
if($keyval{destination} =~ /^\d+$/) {
$keyval{destination} = '^'. $keyval{destination} .'.*$';
} elsif($keyval{destination} =~ /^(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]+$/i
or $keyval{destination} =~ /^[\d.]+$/)
{
$keyval{destination} = '^.*@'. $keyval{destination} .'$';
} elsif($keyval{destination} =~ /^.+\@(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]+$/i
or $keyval{destination} =~ /^.+\@[\d.]+$/)
{
$keyval{destination} = '^'. $keyval{destination} .'$';
} else {
$messages{feeerr} = 'Web.Fees.InvalidDestination';
$c->session->{feeerr}{line} = $line;
last;
}
push @fees, \%keyval;
}
unless(keys %messages) {
if($c->model('Provisioning')->call_prov( $c, 'billing', 'set_billing_profile_fees',
{ handle => $bilprof,
fees => \@fees,
purge_existing => $purge,
},
undef))
{
$messages{feemsg} = 'Web.Bilprof.Updated';
$c->session->{messages} = \%messages;
$c->response->redirect("/billing/search_fees?bilprof=$bilprof&use_session=1&offset=$offset");
return;
}
}
$c->session->{messages} = \%messages;
# TODO: add offset?
$c->response->redirect("/billing/search_fees?bilprof=$bilprof&use_session=1&offset=$offset");
return;
}
=head2 edit_fee
Display a billing profile fee entry and allow the user to make changes.
=cut
sub edit_fee : Local {
my ( $self, $c ) = @_;
$c->stash->{template} = 'tt/fee_edit.tt';
my $bilprof = $c->stash->{bilprof} = $c->request->params->{bilprof};
my $destination = $c->stash->{destination} = $c->request->params->{destination};
$c->stash->{offset} = $c->request->params->{offset} || 0;
if(ref $c->session->{restore_fee_input} eq 'HASH') {
$c->stash->{fee} = $c->session->{restore_fee_input};
delete $c->session->{restore_fee_input};
} else {
my $fee_list;
return unless $c->model('Provisioning')->call_prov( $c, 'billing', 'search_billing_profile_fees',
{ handle => $bilprof,
filter => { destination => $destination },
},
\$fee_list
);
$c->stash->{searched} = 1;
if(ref $$fee_list{fees} eq 'ARRAY' and @{$$fee_list{fees}}) {
if(@{$$fee_list{fees}} > 1) {
$c->session->{messages}{feeerr} = 'Web.Fees.DuplicatedDestination';
} else {
$c->stash->{fee} = $$fee_list{fees}[0];
}
} else {
$c->session->{messages}{feeerr} = 'Web.Fees.NoSuchDestination';
}
}
return 1;
}
=head2 do_edit_fee
Update a billing profile fee entry.
=cut
sub do_edit_fee : Local {
my ( $self, $c ) = @_;
my %messages;
my %settings;
my $bilprof = $c->request->params->{bilprof};
my $offset = $c->request->params->{offset};
$settings{destination} = $c->request->params->{destination};
if(defined $c->request->params->{new_destination}) {
$settings{destination} = $c->request->params->{new_destination};
}
$settings{zone} = $c->request->params->{zone};
$settings{zone_detail} = $c->request->params->{zone_detail};
$settings{onpeak_init_rate} = $c->request->params->{onpeak_init_rate};
$settings{onpeak_init_interval} = $c->request->params->{onpeak_init_interval};
$settings{onpeak_follow_rate} = $c->request->params->{onpeak_follow_rate};
$settings{onpeak_follow_interval} = $c->request->params->{onpeak_follow_interval};
$settings{offpeak_init_rate} = $c->request->params->{offpeak_init_rate};
$settings{offpeak_init_interval} = $c->request->params->{offpeak_init_interval};
$settings{offpeak_follow_rate} = $c->request->params->{offpeak_follow_rate};
$settings{offpeak_follow_interval} = $c->request->params->{offpeak_follow_interval};
$settings{use_free_time} = $c->request->params->{use_free_time} ? 1 : 0;
for(qw(onpeak_init_rate onpeak_init_interval onpeak_follow_rate onpeak_follow_interval
offpeak_init_rate offpeak_init_interval offpeak_follow_rate offpeak_follow_interval))
{
$settings{$_} = undef unless length $settings{$_};
}
if($c->model('Provisioning')->call_prov( $c, 'billing', 'set_billing_profile_fees',
{ handle => $bilprof,
fees => [ \%settings ],
purge_existing => 0,
},
undef))
{
$c->session->{messages}{stfeemsg} = 'Web.Bilprof.Updated';
$c->response->redirect("/billing/search_fees?bilprof=$bilprof&use_session=1&offset=$offset#stored");
return;
}
$c->session->{restore_fee_input} = \%settings;
$c->response->redirect("/billing/edit_fee?bilprof=$bilprof&offset=$offset");
return;
}
=head2 do_delete_fee
Delete a billing profile fee entry.
=cut
sub do_delete_fee : Local {
my ( $self, $c ) = @_;
my $bilprof = $c->request->params->{bilprof};
my $destination = $c->request->params->{destination};
my $offset = $c->request->params->{offset};
if($c->model('Provisioning')->call_prov( $c, 'billing', 'set_billing_profile_fees',
{ handle => $bilprof,
fees => [ { destination => $destination } ],
purge_existing => 0,
},
undef))
{
$c->session->{messages}{stfeemsg} = 'Web.Bilprof.Updated';
$offset-- if $c->request->params->{last_one};
$c->response->redirect("/billing/search_fees?bilprof=$bilprof&use_session=1&offset=$offset#stored");
return;
}
$c->response->redirect("/billing/search_fees?bilprof=$bilprof&use_session=1&offset=$offset");
return;
}
=head1 BUGS AND LIMITATIONS
=over

@ -96,13 +96,20 @@ h3 {
#contentplace .tdkey {
font-weight: bold;
white-space: nowrap;
vertical-align: top;
vertical-align: top;
}
#contentplace .table_header {
font-weight: bold;
white-space: nowrap;
}
.bottom {
vertical-align: bottom;
}
.header_rate_interval {
margin-left: 25px;
margin-right: -25px;
}
#contentplace .nowrap {
white-space: nowrap;
@ -139,6 +146,30 @@ h3 {
border: 1px solid #606060;
}
/*
* input type="file" can't be themed, so we use some magic
*/
/*
#container #contentplace div.fileinputs {
position: relative;
margin-left: 100px;
}
#container #contentplace div.fakefile {
position: absolute;
top: 0px;
left: 0px;
z-index: 1;
}
#container #contentplace input.file {
position: relative;
text-align: right;
-moz-opacity:0 ;
filter:alpha(opacity: 0);
opacity: 0;
z-index: 2;
}
*/
/* sigh, no border for checkboxes */
#contentplace .checkbox {
border: none !important;
@ -271,7 +302,8 @@ h3 {
#contentplace .orders,
#contentplace .contracts,
#contentplace .order_payments,
#contentplace .registered_contacts
#contentplace .registered_contacts,
#contentplace .billing_fees
{
width: 100%;
border-spacing: 0px;

@ -64,6 +64,7 @@
<td>name</td>
<td />
<td />
<td />
</tr>
[% id = 0 %]
[% FOREACH bilprof = bilprofs %]
@ -89,11 +90,14 @@
[% END %]
</td>
</form>
<td>
<a href="/billing/search_fees?bilprof=[% bilprof.handle %]" class="aaction">show fees</a>
</td>
</tr>
[% id = id + 1 %]
[% END %]
[% ELSE %]
<tr><td colspan="4">No billing profiles found in the database.</td></tr>
<tr><td colspan="5">No billing profiles found in the database.</td></tr>
[% END %]
</table>

@ -0,0 +1,148 @@
<h3><a href="/billing#bilprof">[% bilprof.data.name %]</a></h3>
<h3 id="upload">Upload Billing Fees</h3>
<div class="p1">
<form action="/billing/set_fees" method="post" enctype="multipart/form-data" class="search_subscriber">
<input type="hidden" name="bilprof" value="[% bilprof.handle %]" />
<input type="hidden" name="offset" value="[% offset %]" />
[% IF messages.feemsg %]<div class="goodmsg">[% messages.feemsg %]</div>[% END %]
[% IF messages.feeerr %]
<div class="errormsg">[% messages.feeerr %]
[% IF feeerr.line %]
at line [% feeerr.line %]
[% END %]
[% IF messages.feeerrdetail %]
<br />
[% messages.feeerrdetail %]
[% IF feeerr.detail %]
[% feeerr.detail %]
[% END %]
[% END %]
</div>
[% END %]
<label class="search_label" for="upload_fees">Upload file:</label>
<!-- <div class="fileinputs"> -->
<input type="file" class="file" id="upload_fees" name="upload_fees" /> <br />
<!-- <div class="fakefile">
<input type="text" /> <a href="" class="aaction">browse...</a>
</div>
</div>
-->
[% IF messages.feefileerr %]<div class="errormsg">[% messages.feefileerr %]</div>[% END %]
<input type="checkbox" id="purge_existing" name="purge_existing" [% IF purge_existing %]checked="checked"[% END %] />
<label for="purge_existing">purge existing fees</label><br />
<input type="submit" value="Upload &#187;" class="but" />
</form>
</div>
<h3 id="search">Search Billing Fees</h3>
<div class="p1">
<form action="/billing/search_fees" method="post" class="search_subscriber">
<input type="hidden" name="bilprof" value="[% bilprof.handle %]" />
<label class="search_label" for="search_by_destination">Destination:</label>
<input type="text" id="search_by_destination" name="search_destination" value="[% search_destination %]" />
<input type="checkbox" id="exact_destination" name="exact_destination" [% IF exact_destination %]checked="checked"[% END %] />
<label for="exact_destination">exact match</label><br />
<label class="search_label" for="search_by_zone">Zone:</label>
<input type="text" id="search_by_zone" name="search_zone" value="[% search_zone %]" />
<input type="checkbox" id="exact_zone" name="exact_zone" [% IF exact_zone %]checked="checked"[% END %] />
<label for="exact_zone">exact match</label><br />
<label class="search_label" for="search_by_detail">Zone detail:</label>
<input type="text" id="search_by_detail" name="search_detail" value="[% search_detail %]" />
<input type="checkbox" id="exact_detail" name="exact_detail" [% IF exact_detail %]checked="checked"[% END %] />
<label for="exact_detail">exact match</label><br />
<input type="submit" value="Search &#187;" class="but" />
</form>
</div>
<h3 id="stored">Stored Billing Fees</h3>
[% IF fee_list %]
<div class="p1">
[% IF messages.stfeemsg %]<div class="goodmsg">[% messages.stfeemsg %]</div>[% END %]
<table class="billing_fees">
<tr class="table_header bottom">
<td>destination</td>
<td>zone</td>
<td>zone detail</td>
<td />
<td />
</tr>
[% bgflip = 1 %]
[% FOREACH fee = fee_list %]
[% IF bgflip %]
[% bgflip = 0 %]
<tr class="tr_alt">
[% ELSE %]
[% bgflip = 1 %]
<tr>
[% END %]
<td>[% fee.destination %]</td>
<td>[% fee.zone %]</td>
<td>[% fee.zone_detail %]</td>
<td>
<a href="/billing/edit_fee?bilprof=[% bilprof.handle %]&amp;destination=[% fee.destination %]&amp;offset=[% offset %]"
class="aaction">edit</a>
</td>
<td>
<a href="/billing/do_delete_fee?bilprof=[% bilprof.handle %]&amp;destination=[% fee.destination %]&amp;offset=[% offset %][% IF last_one %]&amp;last_one=1[% END %]"
class="aaction">delete</a>
</td>
</tr>
[% END %]
</table>
[% IF pagination %]
<div class="pagination">
<ul>
[% IF offset == 0 %]
<li class="disablepage">&#171; prev</li>
[% ELSE %]
<li class="nextpage">
<a href="/billing/search_fees?bilprof=[% bilprof.handle %]&amp;use_session=1&amp;offset=[% offset - 1 %]#stored">&#171; prev</a>
</li>
[% END %]
[% FOREACH pagine = pagination %]
[% IF pagine.offset == offset %]
<li class="currentpage">
[% pagine.offset + 1 %]
</li>
[% ELSIF pagine.offset == -1 %]
...
[% ELSE %]
<li>
<a href="/billing/search_fees?bilprof=[% bilprof.handle %]&amp;use_session=1&amp;offset=[% pagine.offset %]#stored">[% pagine.offset + 1 %]</a>
</li>
[% END %]
[% END %]
[% IF offset >= max_offset %]
<li class="disablepage">
next &#187;
</li>
[% ELSE %]
<li class="nextpage">
<a href="/billing/search_fees?bilprof=[% bilprof.handle %]&amp;use_session=1&amp;offset=[% offset + 1 %]#stored">next &#187;</a>
</li>
[% END %]
</ul>
</div>
[% END %]
</div>
[% ELSIF searched %]
<div class="p1">
No matching billing fees found.
</div>
[% END %]

@ -0,0 +1,106 @@
[% IF destination %]
<h3>Edit Billing Fee</h3>
[% ELSE %]
<h3>Create New Billing Fee</h3>
[% END %]
<div class="actions">
<a href="/billing/search_fees?bilprof=[% bilprof %]&amp;use_session=1&amp;offset=[% offset %]" class="aaction">cancel</a>
</div>
<div class="p1">
<form action="do_edit_fee" method="post">
<input type="hidden" name="bilprof" value="[% bilprof %]" />
<input type="hidden" name="destination" value="[% fee.destination %]" />
<input type="hidden" name="offset" value="[% offset %]" />
<table>
<tr>
<td class="tdkey">destination:</td>
[% IF destination %]
<td>[% fee.destination %]</td>
[% ELSE %]
<td><input type="text" name="new_destination" value="[% fee.destination %]" /></td>
[% END %]
</tr>
[% IF messages.destination %]
<tr><td /><td><div class="errormsg">[% messages.destination %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">zone:</td>
<td><input type="text" name="zone" value="[% fee.zone %]" /></td>
</tr>
[% IF messages.zone %]
<tr><td /><td><div class="errormsg">[% messages.zone %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">zone detail:</td>
<td><input type="text" name="zone_detail" value="[% fee.zone_detail %]" /></td>
</tr>
[% IF messages.zone_detail %]
<tr><td /><td><div class="errormsg">[% messages.zone_detail %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">onpeak init rate:</td>
<td><input type="text" name="onpeak_init_rate" value="[% fee.onpeak_init_rate %]" /></td>
</tr>
[% IF messages.onpeak_init_rate %]
<tr><td /><td><div class="errormsg">[% messages.onpeak_init_rate %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">onpeak init interval:</td>
<td><input type="text" name="onpeak_init_interval" value="[% fee.onpeak_init_interval %]" /></td>
</tr>
[% IF messages.onpeak_init_interval %]
<tr><td /><td><div class="errormsg">[% messages.onpeak_init_interval %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">onpeak follow rate:</td>
<td><input type="text" name="onpeak_follow_rate" value="[% fee.onpeak_follow_rate %]" /></td>
</tr>
[% IF messages.onpeak_follow_rate %]
<tr><td /><td><div class="errormsg">[% messages.onpeak_follow_rate %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">onpeak follow interval:</td>
<td><input type="text" name="onpeak_follow_interval" value="[% fee.onpeak_follow_interval %]" /></td>
</tr>
[% IF messages.onpeak_follow_interval %]
<tr><td /><td><div class="errormsg">[% messages.onpeak_follow_interval %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">offpeak init rate:</td>
<td><input type="text" name="offpeak_init_rate" value="[% fee.offpeak_init_rate %]" /></td>
</tr>
[% IF messages.offpeak_init_rate %]
<tr><td /><td><div class="errormsg">[% messages.offpeak_init_rate %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">offpeak init interval:</td>
<td><input type="text" name="offpeak_init_interval" value="[% fee.offpeak_init_interval %]" /></td>
</tr>
[% IF messages.offpeak_init_interval %]
<tr><td /><td><div class="errormsg">[% messages.offpeak_init_interval %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">offpeak follow rate:</td>
<td><input type="text" name="offpeak_follow_rate" value="[% fee.offpeak_follow_rate %]" /></td>
</tr>
[% IF messages.offpeak_follow_rate %]
<tr><td /><td><div class="errormsg">[% messages.offpeak_follow_rate %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">offpeak follow interval:</td>
<td><input type="text" name="offpeak_follow_interval" value="[% fee.offpeak_follow_interval %]" /></td>
</tr>
[% IF messages.offpeak_follow_interval %]
<tr><td /><td><div class="errormsg">[% messages.offpeak_follow_interval %]</div></td></tr>
[% END %]
<tr>
<td class="tdkey">use free time:</td>
<td><input type="checkbox" name="use_free_time" [% IF fee.use_free_time %]checked="checked"[% END %] /></td>
</tr>
</table>
<input type="submit" class="but" value="Save &#187;" />
</form>
</div>
Loading…
Cancel
Save