Rework zone fee handling. Implement invoice creation (WIP) - still real template data missing.mr3.3.1
parent
4e3b373df3
commit
b827f73ab4
@ -0,0 +1,300 @@
|
||||
package NGCP::Panel::Controller::Invoice;
|
||||
use Sipwise::Base;
|
||||
use namespace::sweep;
|
||||
BEGIN { extends 'Catalyst::Controller'; }
|
||||
|
||||
use NGCP::Panel::Utils::Message;
|
||||
use NGCP::Panel::Utils::DateTime;
|
||||
use NGCP::Panel::Utils::Contract;
|
||||
use NGCP::Panel::Utils::InvoiceTemplate;
|
||||
use NGCP::Panel::Form::Invoice::Invoice;
|
||||
|
||||
sub auto :Private {
|
||||
my ($self, $c) = @_;
|
||||
$c->log->debug(__PACKAGE__ . '::auto');
|
||||
NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub inv_list :Chained('/') :PathPart('invoice') :CaptureArgs(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) :AllowedRole(subscriberadmin) {
|
||||
my ( $self, $c ) = @_;
|
||||
|
||||
$c->stash->{inv_rs} = $c->model('DB')->resultset('invoices');
|
||||
if($c->user->roles eq "admin") {
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
$c->stash->{inv_rs} = $c->stash->{inv_rs}->search({
|
||||
'contact.reseller_id' => $c->user->reseller_id,
|
||||
},{
|
||||
join => { contract => 'contact' },
|
||||
});
|
||||
} elsif($c->user->roles eq "subscriberadmin") {
|
||||
$c->stash->{inv_rs} = $c->stash->{inv_rs}->search({
|
||||
contract_id => $c->user->account_id,
|
||||
});
|
||||
};
|
||||
|
||||
$c->stash->{inv_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
||||
{ name => 'id', search => 1, title => $c->loc('#') },
|
||||
{ name => 'contract.id', search => 1, title => $c->loc('Customer #') },
|
||||
{ name => 'contract.contact.email', search => 1, title => $c->loc('Customer Email') },
|
||||
{ name => 'serial', search => 1, title => $c->loc('Serial') },
|
||||
]);
|
||||
|
||||
$c->stash(template => 'invoice/invoice_list.tt');
|
||||
}
|
||||
|
||||
sub root :Chained('inv_list') :PathPart('') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
}
|
||||
|
||||
sub ajax :Chained('inv_list') :PathPart('ajax') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
my $rs = $c->stash->{inv_rs};
|
||||
NGCP::Panel::Utils::Datatables::process($c, $rs, $c->stash->{inv_dt_columns});
|
||||
$c->detach( $c->view("JSON") );
|
||||
}
|
||||
|
||||
sub base :Chained('inv_list') :PathPart('') :CaptureArgs(1) {
|
||||
my ($self, $c, $inv_id) = @_;
|
||||
|
||||
unless($inv_id && $inv_id->is_integer) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
log => 'Invalid invoice id detected',
|
||||
desc => $c->loc('Invalid invoice id detected'),
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoice'));
|
||||
}
|
||||
|
||||
my $res = $c->stash->{inv_rs}->find($inv_id);
|
||||
unless(defined($res)) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
log => 'Invoice does not exist',
|
||||
desc => $c->loc('Invoice does not exist'),
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoice'));
|
||||
}
|
||||
$c->stash(inv => $res);
|
||||
}
|
||||
|
||||
sub create :Chained('inv_list') :PathPart('create') :Args() :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $posted = ($c->request->method eq 'POST');
|
||||
my $params = {};
|
||||
$params = $params->merge($c->session->{created_objects});
|
||||
|
||||
my $form;
|
||||
$form = NGCP::Panel::Form::Invoice::Invoice->new(ctx => $c);
|
||||
$form->process(
|
||||
posted => $posted,
|
||||
params => $c->request->params,
|
||||
item => $params,
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
||||
c => $c,
|
||||
form => $form,
|
||||
fields => { },
|
||||
back_uri => $c->req->uri,
|
||||
);
|
||||
if($posted && $form->validated) {
|
||||
try {
|
||||
my $schema = $c->model('DB');
|
||||
$schema->txn_do(sub {
|
||||
my $contract_id = $form->params->{contract}{id};
|
||||
my $customer_rs = NGCP::Panel::Utils::Contract::get_customer_rs(c => $c);
|
||||
my $customer = $customer_rs->find({ 'me.id' => $contract_id });
|
||||
unless($customer) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => "invalid contract_id $contract_id",
|
||||
desc => $c->loc('Customer not found'),
|
||||
);
|
||||
die;
|
||||
}
|
||||
delete $form->params->{contract};
|
||||
$form->params->{contract_id} = $contract_id;
|
||||
|
||||
my $tmpl_id = $form->params->{template}{id};
|
||||
delete $form->params->{template};
|
||||
|
||||
my $tmpl = $schema->resultset('invoice_templates')->search({
|
||||
id => $tmpl_id,
|
||||
});
|
||||
if($c->user->roles eq "admin") {
|
||||
} elsif($c->user->roles eq "reseller") {
|
||||
$tmpl = $tmpl->search({
|
||||
reseller_id => $c->user->reseller_id,
|
||||
});
|
||||
}
|
||||
$tmpl = $tmpl->first;
|
||||
unless($tmpl) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => "invalid template id $tmpl_id",
|
||||
desc => $c->loc('Invoice template not found'),
|
||||
);
|
||||
die;
|
||||
}
|
||||
unless($tmpl->data) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => "invalid template id $tmpl_id, data is empty",
|
||||
desc => $c->loc('Invoice template does not have an SVG stored yet'),
|
||||
);
|
||||
die;
|
||||
}
|
||||
|
||||
unless($customer->contact->reseller_id == $tmpl->reseller_id) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => "template id ".$tmpl->id." has different reseller than contract id $contract_id",
|
||||
desc => $c->loc('Template and customer must belong to same reseller'),
|
||||
);
|
||||
die;
|
||||
}
|
||||
|
||||
my $stime = NGCP::Panel::Utils::DateTime::from_string(
|
||||
delete $form->params->{period}
|
||||
)->truncate(to => 'month');
|
||||
my $etime = $stime->clone->add(months => 1)->subtract(seconds => 1);
|
||||
|
||||
my $zonecalls = NGCP::Panel::Utils::Contract::get_contract_zonesfees(
|
||||
c => $c,
|
||||
contract_id => $contract_id,
|
||||
stime => $stime,
|
||||
etime => $etime,
|
||||
in => 0,
|
||||
out => 1,
|
||||
group_by_detail => 1,
|
||||
);
|
||||
|
||||
my $billing_mapping = $customer->billing_mappings->find($customer->get_column('bmid'));
|
||||
my $billing_profile = $billing_mapping->billing_profile;
|
||||
|
||||
my $balance;
|
||||
try {
|
||||
$balance = NGCP::Panel::Utils::Contract::get_contract_balance(
|
||||
c => $c,
|
||||
profile => $billing_profile,
|
||||
contract => $customer,
|
||||
stime => $stime,
|
||||
etime => $etime
|
||||
);
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to get contract balance.'),
|
||||
);
|
||||
die;
|
||||
}
|
||||
use Data::Printer; say ">>>>>>>>>>>>>>>>>>> balance\n"; p $balance;
|
||||
|
||||
# TODO: generate pdf here, then insert as data
|
||||
$form->params->{serial} = "test".time.int(rand(99999));
|
||||
|
||||
|
||||
$form->params->{amount_net} = $balance->cash_balance_interval;
|
||||
$form->params->{amount_vat} =
|
||||
$form->params->{amount_net} * ($billing_profile->vat_rate/100); # TODO: is it really in percent?
|
||||
$form->params->{amount_total} = $form->params->{amount_net} + $form->params->{amount_vat};
|
||||
|
||||
|
||||
my $svg = $tmpl->data;
|
||||
my $t = NGCP::Panel::Utils::InvoiceTemplate::get_tt();
|
||||
my $out = '';
|
||||
my $pdf = '';
|
||||
my $vars = {};
|
||||
|
||||
try {
|
||||
NGCP::Panel::Utils::InvoiceTemplate::preprocess_svg(\$svg);
|
||||
$t->process(\$svg, $vars, \$out) || do {
|
||||
my $error = $t->error();
|
||||
my $msg = "error processing template, type=".$error->type.", info='".$error->info."'";
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
log => $msg,
|
||||
desc => $c->loc('Failed to render template. Type is ' . $error->type . ', info is ' . $error->info),
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoice'));
|
||||
return;
|
||||
};
|
||||
|
||||
NGCP::Panel::Utils::InvoiceTemplate::svg_pdf($c, \$out, \$pdf);
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
log => $e,
|
||||
desc => $c->loc('Failed to preview template'),
|
||||
);
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoice'));
|
||||
return;
|
||||
}
|
||||
|
||||
$form->params->{data} = $pdf;
|
||||
|
||||
# TODO:
|
||||
#we are two hours off when converting back from epoch due to timezone
|
||||
|
||||
$form->params->{period_start} = $stime->epoch;
|
||||
$form->params->{period_end} = $etime->epoch;
|
||||
|
||||
my $inv = $schema->resultset('invoices')->create($form->params);
|
||||
});
|
||||
$c->flash(messages => [{type => 'success', text => $c->loc('Invoice successfully created')}]);
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to create invoice .'),
|
||||
);
|
||||
}
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoice'));
|
||||
}
|
||||
|
||||
$c->stash(form => $form);
|
||||
$c->stash(create_flag => 1);
|
||||
}
|
||||
|
||||
sub delete :Chained('base') :PathPart('delete') {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
try {
|
||||
my $schema = $c->model('DB');
|
||||
$schema->txn_do(sub{
|
||||
$c->stash->{inv}->delete;
|
||||
});
|
||||
$c->flash(messages => [{type => 'success', text => $c->loc('Invoice successfully deleted')}]);
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to delete invoice .'),
|
||||
);
|
||||
}
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoice'));
|
||||
}
|
||||
|
||||
sub download :Chained('base') :PathPart('download') {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
try {
|
||||
$c->response->content_type('application/pdf');
|
||||
$c->response->body($c->stash->{inv}->data);
|
||||
return;
|
||||
} catch($e) {
|
||||
NGCP::Panel::Utils::Message->error(
|
||||
c => $c,
|
||||
error => $e,
|
||||
desc => $c->loc('Failed to delete invoice .'),
|
||||
);
|
||||
}
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoice'));
|
||||
}
|
||||
|
||||
__PACKAGE__->meta->make_immutable;
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,17 @@
|
||||
package NGCP::Panel::Field::InvoiceTemplate;
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler::Field::Compound';
|
||||
|
||||
has_field 'id' => (
|
||||
type => '+NGCP::Panel::Field::DataTable',
|
||||
label => 'Template',
|
||||
do_label => 0,
|
||||
do_wrapper => 0,
|
||||
required => 1,
|
||||
ajax_src => '/invoicetemplate/ajax',
|
||||
template => 'helpers/datatables_field.tt',
|
||||
table_titles => ['#', 'Reseller', 'Name', 'Active'],
|
||||
table_fields => ['id', 'reseller_name', 'name', 'is_active'],
|
||||
);
|
||||
|
||||
1;
|
||||
@ -0,0 +1,61 @@
|
||||
package NGCP::Panel::Field::MonthPicker;
|
||||
use HTML::FormHandler::Moose;
|
||||
use Template;
|
||||
extends 'HTML::FormHandler::Field';
|
||||
|
||||
has '+widget' => (default => ''); # leave this empty, as there is no widget ...
|
||||
has 'template' => ( isa => 'Str',
|
||||
is => 'rw',
|
||||
default => 'helpers/monthpicker.tt' );
|
||||
has 'language_file' => (isa => 'Str', is => 'rw', default => 'dataTables.default.js' );
|
||||
has 'date_format_js' => (isa => 'Str', is => 'rw', default => 'yy-mm' );
|
||||
|
||||
sub render_element {
|
||||
my ($self) = @_;
|
||||
my $output = '';
|
||||
|
||||
(my $fieldname = $self->html_name) =~ s!\.!!g;
|
||||
|
||||
my $vars = {
|
||||
label => $self->label,
|
||||
field_name => $self->html_name,
|
||||
field_id => $fieldname . "_datepicker",
|
||||
value => $self->value,
|
||||
date_format_js => $self->date_format_js,
|
||||
errors => $self->errors,
|
||||
language_file => $self->language_file,
|
||||
};
|
||||
my $t = new Template({
|
||||
ABSOLUTE => 1,
|
||||
INCLUDE_PATH => [
|
||||
'/usr/share/ngcp-panel/templates',
|
||||
'share/templates',
|
||||
],
|
||||
});
|
||||
|
||||
$t->process($self->template, $vars, \$output) or
|
||||
die "Failed to process Datepicker field template: ".$t->error();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
sub render {
|
||||
my ( $self, $result ) = @_;
|
||||
$result ||= $self->result;
|
||||
die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result;
|
||||
return $self->render_element( $result );
|
||||
}
|
||||
|
||||
sub validate {
|
||||
my ( $self ) = @_;
|
||||
|
||||
return $self->add_error($self->label . " is invalid")
|
||||
if($self->required and (
|
||||
!defined $self->value or !length($self->value)
|
||||
));
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,66 @@
|
||||
package NGCP::Panel::Form::Invoice::Invoice;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler';
|
||||
use Moose::Util::TypeConstraints;
|
||||
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {[qw/submitid fields actions/]}
|
||||
sub build_form_element_class {[qw(form-horizontal)]}
|
||||
|
||||
has_field 'template' => (
|
||||
type => '+NGCP::Panel::Field::InvoiceTemplate',
|
||||
label => 'Invoice Template',
|
||||
validate_when_empty => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The invoice template to use for the invoice generation.']
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'contract' => (
|
||||
type => '+NGCP::Panel::Field::CustomerContract',
|
||||
label => 'Customer',
|
||||
validate_when_empty => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['The contract to create the invoice for.']
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'period' => (
|
||||
#type => '+NGCP::Panel::Field::DateTime',
|
||||
type => '+NGCP::Panel::Field::MonthPicker',
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['YYYY-MM']
|
||||
},
|
||||
label => 'Invoice Period',
|
||||
required => 1,
|
||||
);
|
||||
|
||||
has_field 'save' => (
|
||||
type => 'Submit',
|
||||
value => 'Save',
|
||||
element_class => [qw/btn btn-primary/],
|
||||
label => '',
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
render_list => [qw/template contract period/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -1,605 +0,0 @@
|
||||
package NGCP::Panel::Model::DB::InvoiceTemplate;
|
||||
use base NGCP::Panel::Model::DB::Base;
|
||||
|
||||
#use irka;
|
||||
use Data::Dumper;
|
||||
|
||||
sub getDefaultConditions{
|
||||
my $self = shift;
|
||||
my ($params) = @_;
|
||||
my ($provider_id,$tt_sourcestate,$tt_type,$tt_id) = @$params{qw/provider_id tt_sourcestate tt_type tt_id/};
|
||||
my $conditions = {};
|
||||
if($tt_id){
|
||||
$conditions = { id => $tt_id };
|
||||
}else{
|
||||
$conditions = {
|
||||
reseller_id => $provider_id,
|
||||
type => $tt_type,
|
||||
is_active => 1,
|
||||
};
|
||||
}
|
||||
return $conditions;
|
||||
}
|
||||
sub getInvoiceTemplate{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id,$tt_sourcestate,$tt_type,$tt_id) = @params{qw/provider_id tt_sourcestate tt_type tt_id/};
|
||||
|
||||
my $result = '';
|
||||
|
||||
#it is hard to express my disappointment by DBIx implementation. Where pure SQL is easy to automate, flexible and powerful, with DBIx you can't even get DB as aliases, only additional accessors, which aren't an option. What a poor "wonabe hibernate" idea and implementation.
|
||||
my $tt_record = $self->schema->resultset('invoice_templates')->search(
|
||||
{ id => $tt_id }, {
|
||||
}
|
||||
)->first;
|
||||
#here may be base64 decoding
|
||||
|
||||
#here we will rely on form checking and defaults
|
||||
#if('saved' eq $tt_sourcestate){
|
||||
if( $tt_record ){
|
||||
$tt_sourcestate and $result = $tt_record->get_column( 'base64_'.$tt_sourcestate );
|
||||
$tt_id = $tt_record->get_column( 'id' );
|
||||
}
|
||||
if( $result && exists $params{result} ){
|
||||
${$params{result}} = $result;
|
||||
}
|
||||
return ( $tt_id, \$result, $tt_record );#tt_record - sgorila hata, gori i saray
|
||||
}
|
||||
|
||||
sub storeInvoiceTemplateContent{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id, $tt_sourcestate, $tt_type,$tt_string,$tt_id,$is_active,$name) = @params{qw/provider_id tt_sourcestate tt_type tt_string_sanitized tt_id is_active name/};
|
||||
|
||||
#my $tt_record = $self->resultset('invoice_templates')->search({
|
||||
$self->schema->txn_do(sub {
|
||||
#reseller_id and is_active aren't unique key, because is_active can kepp some 0 values for one reseller, we shouldn't keep active and inactive in one table
|
||||
# $self->schema->resultset('invoice_templates')->update_or_create({
|
||||
# reseller_id => $provider_id,
|
||||
# type => $tt_type,
|
||||
# is_active => 1,
|
||||
# 'base64_'.$tt_sourcestate => $$tt_string,
|
||||
# });
|
||||
|
||||
|
||||
my $tt_record_created;
|
||||
my $tt_record_updated;
|
||||
if( !$tt_id ){
|
||||
$tt_record_created = $self->schema->resultset('invoice_templates')->create({
|
||||
reseller_id => $provider_id,
|
||||
type => $tt_type,
|
||||
# is_active => $is_active,
|
||||
# name => $name,
|
||||
'base64_'.$tt_sourcestate => $$tt_string,
|
||||
});
|
||||
if($tt_record_created){
|
||||
$tt_id = $tt_record_created->id();
|
||||
}
|
||||
}else{
|
||||
my $conditions = $self->getDefaultConditions(\%params);
|
||||
$tt_record_updated = $self->schema->resultset('invoice_templates')->search($conditions);
|
||||
$tt_record_updated->update({
|
||||
# is_active => $is_active,
|
||||
# name => $name,
|
||||
'base64_'.$tt_sourcestate => $$tt_string,
|
||||
});
|
||||
}
|
||||
# if($is_active && $tt_id){
|
||||
# $self->deactivateOtherTemplates($provider_id,$tt_id);
|
||||
# }
|
||||
});
|
||||
return { tt_id => $tt_id };
|
||||
}
|
||||
sub storeInvoiceTemplateInfo{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id,$tt_id,$is_active,$name) = @params{qw/provider_id tt_id is_active name/};
|
||||
|
||||
$self->schema->txn_do(sub {
|
||||
my $tt_record_created;
|
||||
my $tt_record_updated;
|
||||
if( !$tt_id ){
|
||||
$tt_record_created = $self->schema->resultset('invoice_templates')->create({
|
||||
reseller_id => $provider_id,
|
||||
is_active => $is_active,
|
||||
name => $name,
|
||||
});
|
||||
if($tt_record_created){
|
||||
$tt_id = $tt_record_created->id();
|
||||
}
|
||||
}else{
|
||||
$tt_record_updated = $self->schema->resultset('invoice_templates')->search({ id => $tt_id });
|
||||
$tt_record_updated->update({
|
||||
is_active => $is_active,
|
||||
name => $name,
|
||||
});
|
||||
}
|
||||
if($is_active && $tt_id){
|
||||
$self->deactivateOtherTemplates($provider_id,$tt_id);
|
||||
}
|
||||
});
|
||||
return { tt_id => $tt_id };
|
||||
}
|
||||
sub getInvoiceTemplateList{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id,$tt_sourcestate,$tt_type, $tt_string, $tt_id) = @params{qw/provider_id tt_sourcestate tt_type tt_string_sanitized tt_id/};
|
||||
|
||||
return $self->schema->resultset('invoice_templates')->search({
|
||||
reseller_id => $provider_id,
|
||||
});
|
||||
}
|
||||
sub deleteInvoiceTemplate{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id, $tt_id) = @params{qw/provider_id tt_id/};
|
||||
return $self->schema->resultset('invoice_templates')->search({
|
||||
reseller_id => $provider_id,
|
||||
id => $tt_id,
|
||||
})->delete_all;
|
||||
}
|
||||
sub activateInvoiceTemplate{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id, $tt_id) = @params{qw/provider_id tt_id/};
|
||||
$self->schema->txn_do(sub {
|
||||
$self->schema->resultset('invoice_templates')->search({
|
||||
reseller_id => $provider_id,
|
||||
id => $tt_id,
|
||||
})->update({
|
||||
is_active => 1,
|
||||
});
|
||||
$self->deactivateOtherTemplates($provider_id,$tt_id);
|
||||
});
|
||||
}
|
||||
sub deactivateInvoiceTemplate{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id, $tt_id) = @params{qw/provider_id tt_id/};
|
||||
$self->schema->txn_do(sub {
|
||||
$self->schema->resultset('invoice_templates')->search({
|
||||
reseller_id => $provider_id,
|
||||
id => $tt_id,
|
||||
})->update({
|
||||
is_active => 0,
|
||||
});
|
||||
});
|
||||
}
|
||||
sub deactivateOtherTemplates{
|
||||
my $self = shift;
|
||||
my ($provider_id,$tt_id) = @_;
|
||||
$self->schema->resultset('invoice_templates')->search({
|
||||
reseller_id => $provider_id,
|
||||
id => {'!=' => $tt_id },
|
||||
is_active => 1,
|
||||
})->update_all({
|
||||
is_active => 0,
|
||||
});
|
||||
}
|
||||
sub checkInvoiceTemplateProvider{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_id,$tt_id) = @params{qw/provider_id tt_id/};
|
||||
my $tt_record = $self->schema->resultset('invoice_templates')->search({
|
||||
reseller_id => $provider_id,
|
||||
id => $tt_id,
|
||||
});
|
||||
if($tt_record->get_column('id')){
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub getContractInfo{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($contract_id) = @params{qw/contract_id/};
|
||||
return $self->schema->resultset('contracts')->search({
|
||||
id => $contract_id,
|
||||
})->first;
|
||||
}
|
||||
sub getContactInfo{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($contact_id) = @params{qw/contact_id/};
|
||||
return $self->schema->resultset('contacts')->search({
|
||||
id => $contact_id,
|
||||
})->first;
|
||||
}
|
||||
sub getBillingProfile{
|
||||
my $self = shift;
|
||||
my ($params) = @_;
|
||||
my ($client_contract_id, $stime, $etime) = @$params{qw/client_contract_id stime etime/};
|
||||
#select distinct billing_profiles.*
|
||||
#from billing_mappings
|
||||
#inner join billing_profiles on billing_mappings.billing_profile_id=billing_profiles.id
|
||||
#inner join contracts on contracts.id=billing_mappings.contract_id
|
||||
#inner join products on billing_mappings.product_id=products.id and products.class in("sipaccount","pbxaccount")
|
||||
#where
|
||||
# contracts.status != "terminated"
|
||||
# and contracts.contact_id=?
|
||||
# and (billing_mappings.start_date <= ? OR billing_mappings.start_date IS NULL)
|
||||
# and (billing_mappings.end_date >= ? OR billing_mappings.end_date IS NULL)
|
||||
return $self->schema->resultset('billing_profiles')->search({
|
||||
'contract.id' => $client_contract_id,
|
||||
#'contract.status' => { '!=' => 'terminated' },
|
||||
'product.class' => { '-in' => [qw/sipaccount pbxaccount/] },
|
||||
'billing_mappings.start_date' => [
|
||||
{ '<=' => $etime->epoch },
|
||||
{ -is => undef },
|
||||
],
|
||||
'billing_mappings.end_date' => [
|
||||
{ '>=' => $stime->epoch },
|
||||
{ -is => undef },
|
||||
],
|
||||
},{
|
||||
'join' => [ { 'billing_mappings' => [ 'product', 'contract' ] } ],
|
||||
})->first;
|
||||
}
|
||||
sub getContractBalance{
|
||||
my $self = shift;
|
||||
my ($params) = @_;
|
||||
my ($client_contract_id, $stime, $etime) = @$params{qw/client_contract_id stime etime/};
|
||||
#select distinct billing_profiles.*
|
||||
#from billing_mappings
|
||||
#inner join billing_profiles on billing_mappings.billing_profile_id=billing_profiles.id
|
||||
#inner join contracts on contracts.id=billing_mappings.contract_id
|
||||
#inner join products on billing_mappings.product_id=products.id and products.class in("sipaccount","pbxaccount")
|
||||
#where
|
||||
# contracts.status != "terminated"
|
||||
# and contracts.contact_id=?
|
||||
# and (billing_mappings.start_date <= ? OR billing_mappings.start_date IS NULL)
|
||||
# and (billing_mappings.end_date >= ? OR billing_mappings.end_date IS NULL)
|
||||
return $self->schema->resultset('contract_balances')->search({
|
||||
'contract_id' => $client_contract_id,
|
||||
#'contract.status' => { '!=' => 'terminated' },
|
||||
'-and' => [
|
||||
'start' => [
|
||||
{ '=' => $stime->datetime },
|
||||
{ '-is' => undef },
|
||||
],
|
||||
'end' => [
|
||||
{ '=' => $etime->datetime },
|
||||
{ '-is' => undef },
|
||||
],
|
||||
],
|
||||
},undef)->first;
|
||||
}
|
||||
|
||||
sub getProviderInvoiceList{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($provider_reseller_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('invoices')->search({
|
||||
'-and' =>
|
||||
[
|
||||
'contact.reseller_id' => $provider_reseller_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',],
|
||||
'as' => [ 'invoice_id','contract_balance_start','contract_balance_end','cash_balance','free_time_balance', 'reseller_id', 'reseller_name','client_contact_id' ],
|
||||
'prefetch' => [ {'contract_balances' => { 'contract' => { 'contact' => 'reseller' } } } ],
|
||||
#'collapse' => 1,
|
||||
'order_by' => [ { '-desc' => 'contract_balances.start' },{ '-asc' => 'contract_balances.end' }, ],
|
||||
'alias' => 'me',
|
||||
});
|
||||
}
|
||||
sub getProviderInvoiceListAjax{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
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',],
|
||||
#'as' => [ 'invoice_id','contract_balance_start','contract_balance_end','cash_balance','free_time_balance', 'reseller_id', 'reseller_name','client_contact_id' ],
|
||||
#'prefetch' => [ {'contract_balances' => { 'contract' => { 'contact' => 'reseller' } } } ],
|
||||
##'collapse' => 1,
|
||||
#'order_by' => [ { '-desc' => 'contract_balances.start' },{ '-asc' => 'contract_balances.end' }, ],
|
||||
#'alias' => 'me',
|
||||
});
|
||||
}
|
||||
sub createInvoice{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($contract_balance,$data,$stime,$etime) = @params{qw/contract_balance data stime etime/};
|
||||
|
||||
# my($contract_id, $stime, $etime) = @_;
|
||||
##my $invoice_serial = $dbh->selectrow_array('select max(invoices.serial) from invoices inner join contract_balances on invoices.id=contract_balances.invoice_id where contract_balances.contract_id=?',undef,$contract_id );
|
||||
#my $invoice_serial = $dbh->selectrow_array('select max(invoices.serial) from invoices');
|
||||
#$invoice_serial += 1;
|
||||
#$dbh->do('insert into invoices(year,month,serial)values(?,?,?)', undef, $stime->year, $stime->month,$invoice_serial );
|
||||
#my $invoice_id = $dbh->last_insert_id(undef,'billing','invoices','id');
|
||||
#$dbh->do('update contract_balances set invoice_id = ? where contract_id=? and start=? and end=?', undef, $invoice_id,$contract_id, $stime->datetime, $etime->datetime );
|
||||
#return $dbh->selectrow_hashref('select * from invoices where id=?',undef, $invoice_id);
|
||||
my $invoice;
|
||||
|
||||
if( $contract_balance->get_column('invoice_id')){
|
||||
$invoice = $self->schema->resultset('invoices')->search({
|
||||
id => $contract_balance->get_column('invoice_id'),
|
||||
})->first;
|
||||
}else{
|
||||
|
||||
my $invoice_serial = $self->schema->resultset('invoices')->search(undef, {
|
||||
'select' => { 'max' => 'me.serial', '-as' => 'serial_max'},
|
||||
})->first->get_column('serial_max');
|
||||
$invoice_serial +=1;
|
||||
|
||||
my $invoice_record = $self->schema->resultset('invoices')->create({
|
||||
year => $stime->year,
|
||||
month => $stime->month,
|
||||
serial => $invoice_serial,
|
||||
data => $data,
|
||||
});
|
||||
if($invoice_record){
|
||||
$self->schema->resultset('contract_balances')->search({
|
||||
id => $contract_balance->get_column('id'),
|
||||
})->update({
|
||||
invoice_id => $invoice_record->id()
|
||||
});
|
||||
$invoice = $self->schema->resultset('invoices')->search({
|
||||
id => $invoice_record->id(),
|
||||
})->first;
|
||||
}
|
||||
}
|
||||
return $invoice;
|
||||
}
|
||||
sub storeInvoiceData{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($invoice,$data_ref) = @params{qw/invoice data/};
|
||||
$self->schema->resultset('invoices')->search({
|
||||
id => $invoice->get_column('id'),
|
||||
})->update({
|
||||
data => $$data_ref
|
||||
});
|
||||
}
|
||||
sub getInvoice{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($invoice_id) = @params{qw/invoice_id/};
|
||||
return $self->schema->resultset('invoices')->search({
|
||||
'me.id' => $invoice_id,
|
||||
}, undef )->first;
|
||||
}
|
||||
sub getInvoiceContact{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($invoice_id) = @params{qw/invoice_id/};
|
||||
return $self->schema->resultset('invoices')->search({
|
||||
'me.id' => $invoice_id,
|
||||
}, {
|
||||
'+select' => ['contact.email'],
|
||||
'+as' => ['email'],
|
||||
'join' => [ {'contract_balances' => { 'contract' => 'contact' } } ],
|
||||
} )->first;
|
||||
}
|
||||
sub deleteInvoice{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
my ($invoice_id) = @params{qw/invoice_id/};
|
||||
|
||||
$self->schema->resultset('invoices')->search({
|
||||
'id' => $invoice_id,
|
||||
}, undef )->delete;
|
||||
|
||||
$self->schema->resultset('contract_balances')->search({
|
||||
'invoice_id' => $invoice_id,
|
||||
}, undef )->update({
|
||||
'invoice_id' => undef,
|
||||
});
|
||||
}
|
||||
sub getInvoiceProviderClients{
|
||||
my $self = shift;
|
||||
my (%params) = @_;
|
||||
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' =>
|
||||
[
|
||||
'me.reseller_id' => $provider_contact_id, #$client_contract_id - contract of the client
|
||||
],
|
||||
'-exists' => $self->schema->resultset('billing_mappings')->search({
|
||||
#here rely on join generated by datatables
|
||||
'contract.id' => \' = contracts.id',
|
||||
'product.class' => [ "sipaccount", "pbxaccount" ],
|
||||
#'-and' => [
|
||||
# 'start_date' => [ -or =>
|
||||
# { '<=' => $etime->epoch },
|
||||
# { -is => undef },
|
||||
# ],
|
||||
# 'end_date' => [ -or =>
|
||||
# { '>=' => $stime->epoch },
|
||||
# { -is => undef },
|
||||
# ],
|
||||
# ]
|
||||
},{
|
||||
alias => 'billing_mappings_top',
|
||||
join => ['product','contract'],
|
||||
})->as_query
|
||||
});
|
||||
}
|
||||
sub call_owner_condition{
|
||||
my $self = shift;
|
||||
my ($params) = @_;
|
||||
(my($c,$provider_id,$client_contact_id,$client_contract_id)) = @$params{qw/c provider_id client_contact_id client_contract_id/};
|
||||
my %source_account_id_condition;
|
||||
if($client_contract_id){
|
||||
%source_account_id_condition = ( 'source_account_id' => $client_contract_id );
|
||||
}elsif($client_contact_id){
|
||||
%source_account_id_condition = (
|
||||
'source_account.contact_id' => $client_contact_id,
|
||||
'contact.reseller_id' => { '!=' => undef },
|
||||
);
|
||||
}elsif($provider_id){
|
||||
%source_account_id_condition = (
|
||||
'contact.reseller_id' => $client_contact_id,
|
||||
);
|
||||
}
|
||||
return \%source_account_id_condition;
|
||||
}
|
||||
sub get_contract_calls_rs{
|
||||
my $self = shift;
|
||||
my %params = @_;
|
||||
(my($c,$provider_id,$client_contact_id,$client_contract_id,$stime,$etime)) = @params{qw/c provider_id client_contact_id client_contract_id stime etime/};
|
||||
|
||||
$stime ||= NGCP::Panel::Utils::DateTime::current_local()->truncate( to => 'month' );
|
||||
$etime ||= $stime->clone->add( months => 1 );
|
||||
|
||||
my %source_account_id_condition = %{$self->call_owner_condition(\%params)};
|
||||
|
||||
my $calls_rs = $self->schema->resultset('cdr')->search( {
|
||||
# source_user_id => { 'in' => [ map {$_->uuid} @{$contract->{subscriber}} ] },
|
||||
'call_status' => 'ok',
|
||||
'source_user_id' => { '!=' => '0' },
|
||||
'contact.reseller_id' => { '!=' => undef },
|
||||
start_time =>
|
||||
[ -and =>
|
||||
{ '>=' => $stime->epoch},
|
||||
{ '<=' => $etime->epoch},
|
||||
],
|
||||
%source_account_id_condition
|
||||
},{
|
||||
'+select' => [
|
||||
'source_customer_billing_zones_history.zone',
|
||||
'source_customer_billing_zones_history.detail',
|
||||
'destination_user_in',
|
||||
],
|
||||
'+as' => [qw/zone zone_detail destination/],
|
||||
'join' => [
|
||||
{
|
||||
'source_account' => 'contact',
|
||||
},
|
||||
'source_customer_billing_zones_history',
|
||||
],
|
||||
'order_by' => { '-desc' => 'start_time'},
|
||||
} );
|
||||
|
||||
return $calls_rs;
|
||||
}
|
||||
sub get_contract_zonesfees_rs {
|
||||
my $self = shift;
|
||||
my %params = @_;
|
||||
(my($c,$provider_id,$client_contact_id,$client_contract_id,$stime,$etime)) = @params{qw/c provider_id client_contact_id client_contract_id stime etime/};
|
||||
|
||||
$stime ||= NGCP::Panel::Utils::DateTime::current_local()->truncate( to => 'month' );
|
||||
$etime ||= $stime->clone->add( months => 1 );
|
||||
|
||||
my %source_account_id_condition = %{$self->call_owner_condition(\%params)};
|
||||
# SELECT 'out' as direction, SUM(c.source_customer_cost) AS cost, b.zone,
|
||||
# COUNT(*) AS number, SUM(c.duration) AS duration
|
||||
# FROM accounting.cdr c
|
||||
# LEFT JOIN billing.voip_subscribers v ON c.source_user_id = v.uuid
|
||||
# LEFT JOIN billing.billing_zones_history b ON b.id = c.source_customer_billing_zone_id
|
||||
# WHERE v.contract_id = ?
|
||||
# AND c.call_status = 'ok'
|
||||
# $start_time $end_time
|
||||
# GROUP BY b.zone
|
||||
|
||||
my $zonecalls_rs = $self->schema->resultset('cdr')->search( {
|
||||
# source_user_id => { 'in' => [ map {$_->uuid} @{$contract->{subscriber}} ] },
|
||||
'call_status' => 'ok',
|
||||
'source_user_id' => { '!=' => '0' },
|
||||
start_time =>
|
||||
[ -and =>
|
||||
{ '>=' => $stime->epoch},
|
||||
{ '<=' => $etime->epoch},
|
||||
],
|
||||
%source_account_id_condition
|
||||
},{
|
||||
'+select' => [
|
||||
{ sum => 'me.source_customer_cost', -as => 'cost', },
|
||||
{ sum => 'me.source_customer_free_time', -as => 'free_time', } ,
|
||||
{ sum => 'me.duration', -as => 'duration', } ,
|
||||
{ count => '*', -as => 'number', } ,
|
||||
'source_customer_billing_zones_history.zone',
|
||||
'source_customer_billing_zones_history.detail',
|
||||
],
|
||||
'+as' => [qw/cost free_time duration number zone zone_detail/],
|
||||
#alias =>
|
||||
join => 'source_customer_billing_zones_history',
|
||||
group_by => 'source_customer_billing_zones_history.zone',
|
||||
order_by => 'source_customer_billing_zones_history.zone',
|
||||
} );
|
||||
|
||||
return $zonecalls_rs;
|
||||
}
|
||||
|
||||
sub checkResellerClientContract{
|
||||
my($self,$in) = @_;
|
||||
my $res = 0;
|
||||
|
||||
if($in->{client_contract_id} && $in->{provider_id}){
|
||||
if(my $contract = $self->schema->resultset('contracts')->search({
|
||||
'contact.reseller_id' => $in->{provider_id},
|
||||
'me.id' => $in->{client_contract_id},
|
||||
},{
|
||||
'join' => 'contact',
|
||||
})->first){
|
||||
$res = $contract->get_column('id');
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub checkResellerClientContact{
|
||||
my($self,$in) = @_;
|
||||
my $res = 0;
|
||||
|
||||
if($in->{client_contact_id} && $in->{provider_id}){
|
||||
if(my $contact = $self->schema->resultset('contacts')->search({
|
||||
'reseller_id' => $in->{provider_id},
|
||||
'me.id' => $in->{client_contact_id},
|
||||
})->first){
|
||||
$res = $contact->get_column('id');
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub checkResellerInvoice{
|
||||
my($self,$in) = @_;
|
||||
my $res = 0;
|
||||
|
||||
if($in->{invoice_id} && $in->{provider_id}){
|
||||
if(my $invoice = $self->schema->resultset('invoices')->search({
|
||||
'contact.reseller_id' => $in->{provider_id},
|
||||
'me.id' => $in->{invoice_id},
|
||||
},{
|
||||
'join' => { 'contract_balances' => { 'contract' => 'contact' }},
|
||||
})->first){
|
||||
$res = $invoice->get_column('id');
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub checkResellerInvoiceTemplate{
|
||||
my($self,$in) = @_;
|
||||
my $res = 0;
|
||||
#no warnings 'uninitialized';
|
||||
#$in->{c}->log->debug("checkResellerInvoiceTemplate: tt_id=".$in->{tt_id}.";provider_id=".$in->{provider_id}.";");
|
||||
|
||||
if($in->{tt_id} && $in->{provider_id}){
|
||||
#$in->{c}->log->debug("checkResellerInvoiceTemplate: tt_id=".$in->{tt_id}.";provider_id=".$in->{provider_id}.";");
|
||||
if(my $tt = $self->schema->resultset('invoice_templates')->search({
|
||||
'reseller_id' => $in->{provider_id},
|
||||
'me.id' => $in->{tt_id},
|
||||
})->first){
|
||||
$res = $tt->get_column('id');
|
||||
}
|
||||
}
|
||||
#$in->{c}->log->debug("checkResellerInvoiceTemplate: res=".$res.";");
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
@ -0,0 +1,30 @@
|
||||
<div class="control-group [% IF errors.size %]error[% END %]">
|
||||
<style>
|
||||
#ui-datepicker-div .ui-datepicker-calendar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script src="/js/libs/jquery-ui-timepicker-addon.js"></script>
|
||||
[% date_format_js = date_format_js || 'yy-mm-dd' %]
|
||||
<label class="control-label" for="[% field_id %]">[% label %]</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="[% field_name %]" id="[% field_id %]" value="[%value%]" class="ngcp-datepicker" rel="tooltip" data-original-title="[% date_format_js %]" onclick="
|
||||
$(this).datepicker({
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
showButtonPanel: true,
|
||||
dateFormat: '[% date_format_js %]',
|
||||
onClose: function(dateText, inst) {
|
||||
var month = $('#ui-datepicker-div .ui-datepicker-month :selected').val();
|
||||
var year = $('#ui-datepicker-div .ui-datepicker-year :selected').val();
|
||||
$(this).datepicker('setDate', new Date(year, month, 1));
|
||||
}
|
||||
});$(this).datepicker('show');"/>
|
||||
[% IF errors.size -%]
|
||||
<span class="help-inline">
|
||||
[% errors.join('<br/>') %]
|
||||
</span>
|
||||
[% END -%]
|
||||
</div>
|
||||
</div>
|
||||
[% # vim: set tabstop=4 syntax=html expandtab: -%]
|
||||
@ -0,0 +1,31 @@
|
||||
[% site_config.title = c.loc('Invoices ') -%]
|
||||
[%
|
||||
helper.name = c.loc('Invoice');
|
||||
helper.identifier = "Invoice";
|
||||
helper.messages = messages;
|
||||
helper.dt_columns = inv_dt_columns;
|
||||
helper.paginate = 'true';
|
||||
helper.filter = 'true';
|
||||
helper.close_target = close_target;
|
||||
helper.create_flag = create_flag;
|
||||
helper.edit_flag = edit_flag;
|
||||
helper.form_object = form;
|
||||
helper.ajax_uri = c.uri_for_action('/invoice/ajax');
|
||||
|
||||
UNLESS c.user.read_only;
|
||||
helper.dt_buttons = [
|
||||
{ name = c.loc('Download'), uri = "/invoice/'+full.id+'/download", class = 'btn-small btn-primary', icon = 'icon-download-alt' },
|
||||
{ name = c.loc('Delete'), uri = "/invoice/'+full.id+'/delete", class = 'btn-small btn-secondary', icon = 'icon-remove' },
|
||||
];
|
||||
helper.top_buttons = [
|
||||
{ name = c.loc('Create Invoice'), uri = c.uri_for_action('/invoice/create'), class = 'btn-small btn-primary', icon = 'icon-star' },
|
||||
];
|
||||
ELSE;
|
||||
helper.dt_buttons = [
|
||||
{ name = c.loc('Download'), uri = "/invoice/'+full.id+'/download", class = 'btn-small btn-primary', icon = 'icon-download-alt' },
|
||||
];
|
||||
END;
|
||||
|
||||
PROCESS 'helpers/datatables.tt';
|
||||
-%]
|
||||
[% # vim: set tabstop=4 syntax=html expandtab: -%]
|
||||
Loading…
Reference in new issue