MT#5879 Filter invoices by client. Generate form.

Left to do:
fix filtering by date, if field isn't a eppoch
generation
mark selected client in clients list. add big button to clear client selection
ipeshinskaya/InvoiceTemplate5
Irina Peshinskaya 12 years ago committed by Victor Seva
parent 280b4f3b16
commit 7ab5ab3c85

@ -174,8 +174,10 @@ sub invoice_list_data :Chained('invoice') :PathPart('list') :Args(0) {
my $backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') );
$c->log->debug('invoice_list_data');
my $provider_id = $c->stash->{provider}->id;
my $client_contact_id = $c->request->parameters->{client_contact_id};
my $invoice_list_ajax = $backend->getProviderInvoiceListAjax(
provider_id => $provider_id,
$client_contact_id ? ( client_contact_id => $client_contact_id):(),
);
$c->stash(
invoice_list_data_ajax => $invoice_list_ajax,
@ -183,6 +185,19 @@ sub invoice_list_data :Chained('invoice') :PathPart('list') :Args(0) {
#$c->detach( $c->view() );
}
sub provider_client_list :Chained('invoice') :PathPart('clients/list') :Args(0) {
my ($self, $c) = @_;
my $backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') );
$c->log->debug('provider_client_list');
my $provider_id = $c->stash->{provider}->id;
my $provider_client_list_ajax = $backend->getInvoiceProviderClients(
provider_id => $provider_id,
);
$c->stash(
provider_client_list_ajax => $provider_client_list_ajax,
);
#$c->detach( $c->view() );
}
sub invoice_data :Chained('invoice') :PathPart('data') :Args(1) {
my ($self, $c) = @_;
@ -195,6 +210,88 @@ sub invoice_data :Chained('invoice') :PathPart('data') :Args(1) {
return;
}
sub invoice_generate :Chained('base') :PathPart('generate') :Args(0) {
my ($self, $c) = @_;
$c->log->debug($c->action);
my($validator,$backend,$in,$out);
$backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') );
#from parameters
$in = $c->request->parameters;
$in->{provider_id} = $c->stash->{provider}->id;
#(undef,undef,@$in{qw/tt_id/}) = @_;
if($in->{tt_id}){
#always was sure that i'm calm and even friendly person, but I would kill with pleasure author of dbix.
my $db_object;
($out->{tt_id},undef,$db_object) = $backend->getInvoiceTemplate( %$in );
$out->{tt_data}->{tt_id} = $db_object->get_column('id');
$out->{tt_data}->{provider_id} = $db_object->get_column('reseller_id');
foreach(qw/name is_active/){$out->{tt_data}->{$_} = $db_object->get_column($_);}
}
if(!$out->{tt_data}){
$out->{tt_data} = $in;
}
$validator = NGCP::Panel::Form::Invoice::Template->new( backend => $backend );
$validator->remove_undef_in($in);
#need to think how to automate it - maybe through form showing param through args? what about args for uri_for_action?
#join('/',$c->controller,$c->action)
$validator->action( $c->uri_for_action('invoice/generate',[$in->{provider_id}]) );
$validator->name( 'invoice_generate' );#from parameters
#my $posted = 0;
my $posted = exists $in->{submitid};
$c->log->debug("posted=$posted;");
$validator->process(
posted => $posted,
params => $in,
#item => $in,
item => $out->{tt_data},
#item => $out->{tt_data},
);
my $in_validated = $validator->fif;
if($posted){
if($validator->validated) {
try {
$backend->storeInvoiceTemplateInfo(%$in_validated);
$c->flash(messages => [{type => 'success', text => $c->loc(
$in->{tt_id}
?'Invoice template updated'
:'Invoice template created'
) }]);
} catch($e) {
NGCP::Panel::Utils::Message->error(
c => $c,
error => $e,
desc => $c->loc(
$in->{tt_id}
?'Failed to update invoice template.'
:'Failed to create invoice template.'
),
);
}
$c->stash( messages => $c->flash->{messages} );
$c->stash( template => 'helpers/ajax_messages.tt' );
}else{
#$c->stash( m => {create_flag => !$in->{tt_id}} );
#$c->stash( form => $validator );
##$c->stash( template => 'helpers/ajax_form_modal.tt' );
#$c->stash( template => 'invoice/template_info_form.tt' );
$c->response->headers->header( 'X-Form-Status' => 'error' );
}
}
if(!$validator->validated){
#$c->stash( in => $in );
#$c->stash( out => $out );
$c->stash( m => {create_flag => !$in->{tt_id}} );
$c->stash( form => $validator );
#$c->stash( template => 'helpers/ajax_form_modal.tt' );
$c->stash( template => 'invoice/template_info_form.tt' );
}
$c->detach( $c->view("SVG") );#to the sake of nowrapper
}
sub template_base :Chained('base') :PathPart('template') :CaptureArgs(0) {
my ($self, $c) = @_;
my($validator,$backend,$in,$out);

@ -0,0 +1,71 @@
package NGCP::Panel::Form::Invoice::Generate;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::ValidatorBase';
extends 'HTML::FormHandler::Field::Compound';
use Moose::Util::TypeConstraints;
use HTML::FormHandler::Widget::Block::Bootstrap;
has '+widget_wrapper' => ( default => 'Bootstrap' );
has '+use_fields_for_input_without_param' => ( default => 1 );
sub build_render_list {[qw/fields actions/]}
sub build_form_element_class { [qw/form-horizontal/] }
has_field 'submitid' => ( type => 'Hidden' );
#has_field 'contract.id' => (
# type => '+NGCP::Panel::Field::DataTable',
# label => 'Client',
# do_label => 0,
# do_wrapper => 0,
# required => 1,
# template => 'helpers/datatables_field.tt',
# ajax_src => '/contact/ajax_noreseller',
# table_titles => ['#', 'First Name', 'Last Name', 'Email'],
# table_fields => ['id', 'firstname', 'lastname', 'email'],
#);
has_field 'start' => (
type => '+NGCP::Panel::Field::DateTime',
element_attr => {
rel => ['tooltip'],
title => ['YYYY-MM-DD HH:mm:ss']
},
label => 'Start Date/Time',
required => 1,
);
has_field 'end' => (
type => '+NGCP::Panel::Field::DateTime',
element_attr => {
rel => ['tooltip'],
title => ['YYYY-MM-DD HH:mm:ss']
},
label => 'End Date/Time',
required => 1,
);
1;
=head1 NAME
NGCP::Panel::Form::InvoiceTemplate
=head1 DESCRIPTION
Form to modify an invoice template.
=head1 METHODS
=head1 AUTHOR
Irina Peshinskaya
=head1 LICENSE
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
# vim: set tabstop=4 expandtab:

@ -219,14 +219,14 @@ sub checkInvoiceTemplateProvider{
return 0;
}
sub getInvoiceClientContactInfo{
my $self = shift;
my (%params) = @_;
my ($client_id) = @params{qw/client_id/};
return $tt_record = $self->schema->resultset('invoice_templates')->search({
reseller_id => $client_id,
});
}
#sub getInvoiceClientContactInfo{
# my $self = shift;
# my (%params) = @_;
# my ($client_id) = @params{qw/client_id/};
# return $tt_record = $self->schema->resultset('contacts')->search({
# reseller_id => $client_id,
# });
#}
sub getProviderInvoiceList{
my $self = shift;
my (%params) = @_;
@ -250,13 +250,14 @@ sub getProviderInvoiceList{
sub getProviderInvoiceListAjax{
my $self = shift;
my (%params) = @_;
my ($provider_reseller_id,$stime,$etime) = @params{qw/provider_id stime etime/};
my ($provider_reseller_id,$client_contact_id,$stime,$etime) = @params{qw/provider_id client_contact_id stime etime/};
$stime ||= NGCP::Panel::Utils::DateTime::current_local()->truncate( to => 'month' );
$etime ||= $stime->clone->add( months => 1);
$self->schema->resultset('invoices')->search({
'-and' =>
[
'contact.reseller_id' => $provider_reseller_id, #$client_contract_id - contract of the client
$client_contact_id ? ('contact.id' => $client_contact_id) : (), #$client_contract_id - contract of the client
],
},{
#'select' => [ 'contract_balances.invoice_id','contract_balances.start','contract_balances.end','contract_balances.cash_balance','contract_balances.free_time_balance','reseller.id','reseller.name','contact.id',],
@ -279,28 +280,27 @@ sub getInvoice{
sub getInvoiceProviderClients{
my $self = shift;
my (%params) = @_;
my ($provider_contact_id,$stime,$etime) = @params{qw/provider_contact_id stime etime/};
my ($provider_contact_id,$stime,$etime) = @params{qw/provider_id stime etime/};
$stime ||= NGCP::Panel::Utils::DateTime::current_local()->truncate( to => 'month' );
$etime ||= $stime->clone->add( months => 1);
$self->schema->resultset('contacts')->search_rs({
'-and' =>
[
'reseller_id' => $provider_contact_id, #$client_contract_id - contract of the client
'id' => { '!=' => $provider_contact_id },
'me.reseller_id' => $provider_contact_id, #$client_contract_id - contract of the client
],
'-exists' => $self->schema->resultset('billing_mappings')->search({
'contract.contact_id' => \' = contacts.id',
'contract.contact_id' => \' = me.id',
'product.class' => [ "sipaccount", "pbxaccount" ],
'-and' => [
'start_date' => [ -or =>
{ '<=' => $etime->epoch },
{ -is => undef },
],
'end_date' => [ -or =>
{ '>=' => $stime->epoch },
{ -is => undef },
],
]
#'-and' => [
# 'start_date' => [ -or =>
# { '<=' => $etime->epoch },
# { -is => undef },
# ],
# 'end_date' => [ -or =>
# { '>=' => $stime->epoch },
# { -is => undef },
# ],
# ]
},{
alias => 'billing_mappings_top',
join => ['product','contract'],

@ -52,17 +52,18 @@ sub process {
}
# data-range searching
my $from_date = $c_->request->params->{sSearch_0} // "";
my $to_date = $c_->request->params->{sSearch_1} // "";
my $from_date_in = $c_->request->params->{sSearch_0} // "";
my $to_date_in = $c_->request->params->{sSearch_1} // "";
my($from_date,$to_date);
my $parser = DateTime::Format::Strptime->new(
#pattern => '%Y-%m-%d %H:%M',
pattern => '%Y-%m-%d',
);
if($from_date) {
$from_date = $parser->parse_datetime($from_date);
$from_date = $parser->parse_datetime($from_date_in);
}
if($to_date) {
$to_date = $parser->parse_datetime($to_date);
$to_date = $parser->parse_datetime($to_date_in);
}
@searchColumns = ();
foreach my $c(@{ $cols }) {
@ -71,12 +72,12 @@ sub process {
if($c->{search_from_epoch} && $from_date) {
$rs = $rs->search({
$name => { '>=' => $from_date->epoch },
$name => { '>=' => $c->{search_use_datetime} ? $from_date_in : $from_date->epoch },
});
}
if($c->{search_to_epoch} && $to_date) {
$rs = $rs->search({
$name => { '<=' => $to_date->epoch },
$name => { '<=' => $c->{search_use_datetime} ? $to_date_in : $to_date->epoch },
});
}
}

@ -61,6 +61,16 @@ $(document).ready(function() {
"iDisplayLength": 5,
'iShowPages': 5,
"sAjaxSource": "[% helper.ajax_uri %]",
"fnServerParams": function ( aoData ) {
var params = $('#[% helper.id_from_name %]_table').attr('paramsJSON');
if(params){
var paramsParsed = jQuery.parseJSON(params);
for(var key in paramsParsed){
alert('key='+key+'; value='+paramsParsed[key]+';');
aoData.push( {"name":key,"value":paramsParsed[key]} );
}
}
},
[% IF helper.column_sort -%]
"aaSorting": [
[%

@ -0,0 +1,2 @@
[%m.name = "Invoice Generation"%]
[%PROCESS 'helpers/ajax_form_modal.tt'-%]

@ -6,6 +6,12 @@
[%PROCESS 'helpers/datatables_vars.tt'
no_auto_helper = 1
-%]
[%PROCESS 'helpers/modal.tt' -%]
[%mf_helper = {
ajax_load => 1,
ajax_list_refresh => 'template',
}%]
[%modal_script( m = mf_helper )%]
[% site_config.title = c.loc('Invoices for [_1]', provider.name ) -%]
@ -31,22 +37,50 @@
<div class="accordion" id="invoice">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#invoice" href="#collapse_client_list">[% c.loc('Clients') %]</a>
</div>
<div class="accordion-body collapse" id="collapse_client_list">
<div class="accordion-inner" style="overflow:auto; height: 500px;">
[%#Dumper.dump_html(provider_client_list_ajax)%]
[%
clearHelper();
helper.name = c.loc('Clients');
helper.name_single = c.loc('client');
helper.dt_columns = [
{ name => 'id', title => c.loc('Client Contact Id'), search => 1},
{ name => 'contracts.id', title => c.loc('Client Contract Id'), search => 1},
{ name => 'contracts.external_id', title => c.loc('External #'), search => 1 },
{ name => 'email', title => c.loc('Contact Email'), search => 1 },
{ name => 'contracts.billing_mappings.billing_profile.name', title => c.loc('Billing Profile'), search => 1 },
{ name => 'contracts.status', title => c.loc('Status'), search => 1 },
];
helper.dt_buttons = [
{ name = c.loc('View invoices'), uri = "javascript:alert('+full.id+');invoicesTable = \$(\\'#invoice_list_data_ajax_table\\');if(invoicesTable){invoicesTable.attr(\\'paramsJSON\\',JSON.stringify({\\'client_contact_id\\':'+full.id+'}));invoicesTable.dataTable().fnDraw();}void(0);", class = 'btn-small btn-primary', icon = 'icon-glass' },
{ name = c.loc('Generate invoice'), uri = "javascript:void(0);", class = 'btn-small btn-primary', icon = 'icon-star' },
];
helper.identifier = 'provider_client_list_ajax';
helper.ajax_uri = c.uri_for_action( '/invoice/ajax_datatables_data', [ provider.id, 'provider_client_list' ] ) ;
initHelperAuto();
PROCESS 'helpers/datatables.tt';
datatables.clients = {helper => {}};
datatables.clients.helper.import(helper);
-%]
[%#PROCESS 'invoice/invoice_list.tt' %]
</div>
</div>
</div>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#invoice" href="#collapse_invoice_list">[% c.loc('Invoices') %]</a>
</div>
<div class="accordion-body collapse" id="collapse_invoice_list">
<div class="accordion-inner" style="overflow:auto; height: 300px;">
<div class="accordion-inner" style="overflow:auto; height: 500px;">
[%# [%IF 0 && c.user.roles == 'admin' %]
[%# { name => 'reseller_id', title => c.loc('Reseller Id')},
[%# { name => 'reseller_name', title => c.loc('Reseller Name')},
[%# [%END%]
[%# { name => 'client_contact_id', title => c.loc('Client')},
[%# { name => 'contract_balance_start', title => c.loc('Period Start')},
[%# { name => 'contract_balance_end', title => c.loc('Period End')},
[%# { name => 'cash_balance', title => c.loc('Cash balance')},
[%# { name => 'free_time_balance', title => c.loc('Free time balance')},%]
[%#, title => c.loc('Reseller #')%]
[%#, title => c.loc('Reseller name')%]
[%#Dumper.dump_html(invoice_list_ajax)%]
@ -57,25 +91,27 @@
helper.dt_columns = [
{ name => 'contract_balances.contract.contact.reseller_id'},
{ name => 'contract_balances.contract.contact.reseller.name'},
{ name => 'contract_balances.contract.contact.id', title => c.loc('Client')},
{ name => 'contract_balances.invoice_id', title => c.loc('Invoice #')},
{ name => 'contract_balances.start', title => c.loc('Period Start')},
{ name => 'contract_balances.contract.contact.id', title => c.loc('Client'), search => 1},
{ name => 'contract_balances.invoice_id', title => c.loc('Invoice #'), search => 1},
{ name => 'contract_balances.start', title => c.loc('Period Start'), search_from_epoch => 1, search_to_epoch => 1, search_use_datetime => 1 },
{ name => 'contract_balances.end', title => c.loc('Period End')},
{ name => 'contract_balances.cash_balance', title => c.loc('Cash balance')},
{ name => 'contract_balances.free_time_balance', title => c.loc('Free Time balance')},
];
helper.dt_buttons = [
{ name = c.loc('View PDF'), uri = "javascript:window.open(\\'/invoice/data/' + full.contract_balances_invoice_id + '\\',\\'_blank\\');void(0);", class = 'btn-small btn-primary', icon = 'icon-edit' },
{ name = c.loc('View invoice PDF'), uri = "javascript:window.open(\\'/invoice/data/' + full.contract_balances_invoice_id + '\\',\\'_blank\\');void(0);", class = 'btn-small btn-primary', icon = 'icon-edit' },
];
helper.identifier = 'invoice_list_data_ajax';
helper.ajax_uri = c.uri_for_action( '/invoice/ajax_datatables_data', [ provider.id, 'invoice_list_data' ] ) ;
initHelperAuto();
PROCESS 'helpers/datatables.tt';
datatables.invoices = {helper => {}};
datatables.invoices.helper.import(helper);
-%]
[%#PROCESS 'invoice/invoice_list.tt' %]
</div>
</div>
</div>
</div>
<!--div class="accordion-group">
@ -156,6 +192,7 @@ oTable.fnClose();
</div>
</div-->
</div>
<div id="invoice_generate_form">
</div>

Loading…
Cancel
Save