MT#5879 Invoice deletion draft

ipeshinskaya/InvoiceTemplate5
Irina Peshinskaya 12 years ago committed by Victor Seva
parent 8db8a16f7f
commit 70ae0c01c9

@ -13,6 +13,7 @@ use NGCP::Panel::Utils::Message;
use NGCP::Panel::Form::Invoice::Template;
use NGCP::Panel::Form::Invoice::Generate;
use NGCP::Panel::Form::Invoice::Basic;
use NGCP::Panel::Model::DB::InvoiceTemplate;
use NGCP::Panel::Utils::InvoiceTemplate;
@ -208,6 +209,64 @@ sub invoice_data :Chained('invoice') :PathPart('data') :Args(1) {
return;
}
sub invoice_delete :Chained('base') :PathPart('delete') :Args(0) {
my ($self, $c) = @_;
$c->log->debug('invoice_delete');
my($validator,$backend,$in,$out);
$in = $c->request->parameters;
#check that this id really belongs to specified contract? or just add contract condition to delete query?
#checking is more universal
#this is just copy-paste from method above
#of course we are chained and we can put in and out to stash
#input
$in->{provider_id} = $c->stash->{provider}->id;
#output
$out={};
#storage
#pass scheme here is ugly, and should be moved somehow to DB::Base
$backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') );
#input checking & simple preprocessing
$validator = NGCP::Panel::Form::Invoice::Basic->new( backend => $backend );
# $form->schema( $c->model('DB::InvoiceTemplate')->schema );
#to common form package ? removing is necessary due to FormHandler param presence evaluation - it is based on key presence, not on defined/not defined value
#in future this method should be called by ControllerBase
$validator->remove_undef_in($in);
#really, we don't need a form here at all
#just use as already implemented fields checking and defaults applying
#$validator->setup_form(
$validator->process(
posted => 1,
params => $in,
);
#$validator->validate_form();
#multi return...
$c->log->debug("validated=".$validator->validated.";\n");
if(!$validator->validated){
#return;
}
my $in_validated = $validator->fif;
#dirty hack 1
#really model logic should recieve validated input, but raw input also should be saved somewhere
#---------------> $in = $in_validated;
#think about it more
$backend->deleteInvoice(%$in);
#$c->flash(messages => [{type => 'success', text => $c->loc(
$c->stash(messages => [{type => 'success', text => $c->loc(
'Invoice deleted'
) }]);
$c->stash( template => 'helpers/ajax_messages.tt' );
$c->detach( $c->view("SVG") );
}
sub invoice_generate :Chained('base') :PathPart('generate') :Args(0) {
my ($self, $c) = @_;
$c->log->debug($c->action);
@ -216,52 +275,27 @@ sub invoice_generate :Chained('base') :PathPart('generate') :Args(0) {
#from parameters
$in = $c->request->parameters;
my $parser = DateTime::Format::Strptime->new(
#pattern => '%Y-%m-%d %H:%M',
pattern => '%Y-%m-%d %H:%M:%S',
);
if($in->{start}) {
$in->{stime} = $parser->parse_datetime($in->{start});
}
if($in->{end}) {
$in->{etime} = $parser->parse_datetime($in->{end});
}
#$c->log->debug("stime=".$in->{stime}.";etime=".$in->{etime}.";");
$in->{provider_id} = $c->stash->{provider}->id;
#$in->{client_contact_id} = $c->request->parameters->{client_contact_id};
#(undef,undef,@$in{qw/client_contact_id/}) = @_;
if($in->{invoice_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->{invoice_id},undef,$db_object) = $backend->getInvoiceTemplate( %$in );
$out->{invoice_data}->{invoice_id} = $db_object->get_column('id');
$out->{invoice_data}->{provider_id} = $db_object->get_column('reseller_id');
foreach(qw/name is_active/){$out->{invoice_data}->{$_} = $db_object->get_column($_);}
}
if(!$out->{invoice_data}){
$out->{invoice_data} = $in;
}
$validator = NGCP::Panel::Form::Invoice::Generate->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/invoice_generate',[$in->{provider_id}]) );
$validator->name( 'invoice_generate' );#from parameters
#my $posted = 0;
my $posted = exists $in->{submitid};
$c->log->debug("posted=$posted;");
#todo: validate that customer is not terminated and is sip/pbx account
$validator->process(
posted => $posted,
params => $in,
#item => $in,
item => $out->{invoice_data},
#item => $out->{invoice_data},
#no edit supposed for invoice - just creation and deletion, so item from DB is not used
item => $in,
);
my $in_validated = $validator->fif;
if($posted){
$c->forward('parse_invoice_period',[$in]);
$c->log->debug("stime=".$in->{stime}.";etime=".$in->{etime}.";");
$c->log->debug("validated=".$validator->validated.";");
if($validator->validated) {
$c->forward('generate_invoice',[$in, $out]);
@ -282,19 +316,12 @@ sub invoice_generate :Chained('base') :PathPart('generate') :Args(0) {
$c->stash( messages => $c->flash->{messages} );
$c->stash( template => 'helpers/ajax_messages.tt' );
}else{
#$c->stash( m => {create_flag => !$in->{invoice_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->{invoice_id}} );
$c->stash( form => $validator );
#$c->stash( template => 'helpers/ajax_form_modal.tt' );
$c->stash( template => 'invoice/invoice_generate_form.tt' );
}
$c->detach( $c->view("SVG") );#to the sake of nowrapper
@ -303,7 +330,7 @@ sub invoice_generate :Chained('base') :PathPart('generate') :Args(0) {
#absolutely Model method
sub generate_invoice :Private{
my ($self, $c, $in, $out) = @_;
$out ||={};
my $backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') );
$c->log->debug('generate_invoice;');
@ -370,6 +397,20 @@ sub generate_invoice :Private{
NGCP::Panel::Utils::InvoiceTemplate::convertSvg2Pdf($c,\$svg,$in,$out);
#$backend->storeInvoiceData('invoice'=>$invoice,'data'=>\$out->{tt_string_pdf});
}
sub parse_invoice_period :Private{
my ($self, $c, $in) = @_;
my $parser = DateTime::Format::Strptime->new(
#pattern => '%Y-%m-%d %H:%M:%S',
pattern => '%Y-%m-%d',
);
if($in->{start}) {
$in->{stime} = $parser->parse_datetime($in->{start})->truncate(to => 'day');
}
if($in->{end}) {
$in->{etime} = $parser->parse_datetime($in->{end})->truncate(to => 'day')->add(days => 1)->subtract(seconds => 1);
}
}
sub template_base :Chained('base') :PathPart('template') :CaptureArgs(0) {
my ($self, $c) = @_;

@ -0,0 +1,61 @@
package NGCP::Panel::Field::DatePicker;
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/datepicker.tt' );
has 'language_file' => (isa => 'Str', is => 'rw', default => 'dataTables.default.js' );
has 'date_format_js' => (isa => 'Str', is => 'rw', default => 'yy-mm-dd' );
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-panel1444/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,120 @@
package NGCP::Panel::Form::Invoice::Basic;
use Sipwise::Base;
use HTML::FormHandler::Moose;
#extends qw/HTML::FormHandler NGCP::Panel::Form::ValidatorBase/;
extends 'NGCP::Panel::Form::ValidatorBase';
use Moose::Util::TypeConstraints;
use DateTime;
use DateTime::Format::Strptime;
use NGCP::Panel::Utils::DateTime;
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 '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::DatePicker',
label => 'Start Date',
default => NGCP::Panel::Utils::DateTime::current_local()->truncate(to => 'month'),
required => 1,
);
has_field 'end' => (
type => '+NGCP::Panel::Field::DatePicker',
label => 'End Date',
default => NGCP::Panel::Utils::DateTime::current_local()->truncate(to => 'month')->add( months => 1)->subtract(seconds=>1)->truncate(to=>'day'),
required => 1,
);
has_field 'save' => (
type => 'Button',
value => 'Generate',
element_class => [qw/btn btn-primary/],
do_label => 0,
);
has_field 'client_contract_id' => (
type => 'Hidden',
required => 1,
);
has_block 'fields' => (
tag => 'div',
class => [qw/modal-body/],
render_list => [qw/start end client_contract_id/],
);
has_block 'actions' => (
tag => 'div',
class => [qw/modal-footer/],
render_list => [qw/save/],
);
sub validate {
my $self = shift;
my $start = $self->field('start');
my $end = $self->field('end');
my $parser = DateTime::Format::Strptime->new(
#pattern => '%Y-%m-%d %H:%M:%S',
pattern => '%Y-%m-%d',
);
my $sdate = $parser->parse_datetime($start->value);
unless($sdate) {
$start->add_error("Invalid date format, must be YYYY-MM-DD hh:mm:ss");
}
my $edate = $parser->parse_datetime($end->value);
unless($edate) {
$end->add_error("Invalid date format, must be YYYY-MM-DD hh:mm:ss");
}
#unless(DateTime->compare($sdate, $edate) == -1) {
# my $err_msg = 'End time must be later than start time';
# $start->add_error($err_msg);
# $end->add_error($err_msg);
#}
#if(!$self->backend->checkSipPbxAccount()){
#}
}
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:

@ -8,6 +8,7 @@ use Moose::Util::TypeConstraints;
use DateTime;
use DateTime::Format::Strptime;
use NGCP::Panel::Utils::DateTime;
has '+widget_wrapper' => ( default => 'Bootstrap' );
has_field 'submitid' => ( type => 'Hidden' );
@ -29,22 +30,16 @@ has_field 'submitid' => ( type => 'Hidden' );
# 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',
type => '+NGCP::Panel::Field::DatePicker',
label => 'Start Date',
default => NGCP::Panel::Utils::DateTime::current_local()->truncate(to => 'month'),
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',
type => '+NGCP::Panel::Field::DatePicker',
label => 'End Date',
default => NGCP::Panel::Utils::DateTime::current_local()->truncate(to => 'month')->add( months => 1)->subtract(seconds=>1)->truncate(to=>'day'),
required => 1,
);
@ -77,7 +72,8 @@ sub validate {
my $start = $self->field('start');
my $end = $self->field('end');
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
#pattern => '%Y-%m-%d %H:%M:%S',
pattern => '%Y-%m-%d',
);
my $sdate = $parser->parse_datetime($start->value);

@ -7,10 +7,8 @@ use Data::Dumper;
sub getDefaultConditions{
my $self = shift;
my ($params) = @_;
#irka::loglong(Dumper($params));
my ($provider_id,$tt_sourcestate,$tt_type,$tt_id) = @$params{qw/provider_id tt_sourcestate tt_type tt_id/};
my $conditions = {};
#irka::loglong("getDefaultConditions: tt_id=$tt_id;\n");
if($tt_id){
$conditions = { id => $tt_id };
}else{
@ -27,24 +25,12 @@ sub getInvoiceTemplate{
my (%params) = @_;
my ($provider_id,$tt_sourcestate,$tt_type,$tt_id) = @params{qw/provider_id tt_sourcestate tt_type tt_id/};
#irka::loglong("getInvoiceTemplate: tt_id=$tt_id;\n");
#irka::loglong(Dumper(\%params));
my $result = '';
my $conditions = $self->getDefaultConditions(\%params);
#my $tt_record = $self->resultset('invoice_templates')->search({
#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 a option. What a poor "wonabe hibernate" idea and implementation.
#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 }, {
#'+select' => [{'reseller_id' =>'provider_id','-as'=>'provider_id'},{'id' => 'tt_id','-as'=>'tt_id'}]
#'+select' => [
# [ 'reseller_id', {'-as'=>'provider_id'}],
# [ 'id', {'-as'=>'tt_id'}],
#],
#'+select' => [qw/reseller_id id/],
#'+as' => [qw/provider_id tt_id/]
#'-as' => [{reseller_id=>provider_id},{ id=>tt_id}]
}
}
)->first;
#here may be base64 decoding
@ -52,7 +38,6 @@ sub getInvoiceTemplate{
#if('saved' eq $tt_sourcestate){
if( $tt_record ){
$tt_sourcestate and $result = $tt_record->get_column( 'base64_'.$tt_sourcestate );
#$tt_record->reseller_id
$tt_id = $tt_record->get_column( 'id' );
}
if( $result && exists $params{result} ){
@ -77,15 +62,6 @@ sub storeInvoiceTemplateContent{
# });
#here may be base64 decoding
# $self->schema->resultset('ivoice_template')->search({
# reseller_id => $provider_id,
# type => $tt_type,
# })->update_all({
# is_active => 0,
# });
#I think that SQl + DBI are much more flexible and compact
my $tt_record_created;
my $tt_record_updated;
if( !$tt_id ){
@ -119,7 +95,6 @@ sub storeInvoiceTemplateInfo{
my (%params) = @_;
my ($provider_id,$tt_id,$is_active,$name) = @params{qw/provider_id tt_id is_active name/};
#my $tt_record = $self->resultset('invoice_templates')->search({
$self->schema->txn_do(sub {
my $tt_record_created;
my $tt_record_updated;
@ -150,10 +125,6 @@ sub getInvoiceTemplateList{
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_template_fake')->find(\'select * from invoice_templates')->all
#$self->schema->resultset('invoice_templates')->name(\'(select * from invoice_templates)')->all
#];
return $self->schema->resultset('invoice_templates')->search({
reseller_id => $provider_id,
});
@ -397,6 +368,21 @@ sub getInvoice{
'id' => $invoice_id,
}, undef )->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) = @_;

@ -0,0 +1,17 @@
<div class="control-group [% IF errors.size %]error[% END %]">
<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 %]" class="ngcp-datepicker" rel="tooltip" data-original-title="[% date_format_js %]" onclick="
$(this).datepicker({
'dateFormat': '[% date_format_js %]',
});$(this).datepicker('show');"/>
[% IF errors.size -%]
<span class="help-inline">
[% errors.join('<br/>') %]
</span>
[% END -%]
</div>
</div>
[% # vim: set tabstop=4 syntax=html expandtab: -%]

@ -29,6 +29,7 @@
[%messages.unshift( c.loc('Reseller is <b>[_1]</b>', reseller.first.status) ); %]
[% END -%]
<div class="row" id="messages">
[%#here can be just initial messages state, but now it is th same with ajax messages, so there is no sense in repetition-%]
[%PROCESS 'helpers/ajax_messages.tt' -%]
</div>
<script>
@ -128,6 +129,7 @@ function applyClientFilter(table,tr,contact_id){
{ name => 'contract_balances.free_time_balance', title => c.loc('Free Time balance')},
];
helper.dt_buttons = [
{ name = c.loc('Delete'), uri = "javascript:fetch_into(\\'messages\\', \\'" _ c.uri_for_action('/invoice/invoice_delete', [ provider.id ] ) _ "\\',\\'invoice_id='+full.contract_balances_invoice_id+'\\',function(){" _ helper.id_from_name _ "_table.fnDraw();});void(0);", class = 'btn-small btn-secondary', icon = 'icon-trash' },
{ 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';

Loading…
Cancel
Save