diff --git a/lib/NGCP/Panel/Controller/Customer.pm b/lib/NGCP/Panel/Controller/Customer.pm index d6fde4b58d..ad132b3d90 100644 --- a/lib/NGCP/Panel/Controller/Customer.pm +++ b/lib/NGCP/Panel/Controller/Customer.pm @@ -17,6 +17,8 @@ use NGCP::Panel::Form::Customer::PbxFieldDevice; use NGCP::Panel::Form::Customer::PbxFieldDeviceEdit; use NGCP::Panel::Form::Customer::PbxFieldDeviceSync; use NGCP::Panel::Form::Customer::InvoiceTemplate; + +use NGCP::Panel::Model::DB::InvoiceTemplate; use NGCP::Panel::Utils::Message; use NGCP::Panel::Utils::Navigation; use NGCP::Panel::Utils::DateTime; @@ -839,25 +841,36 @@ sub calls :Chained('base') :PathPart('calls') :Args(0) { $c->stash(zonecalls_rs => [1..100] ); } $c->stash(template => 'customer/calls.tt'); + #$c->stash(zonecalls_rs => $c->stash{zonecalls_rs}); + #$c->detach($c->view('SVG')); +# return; + #$c->response->body(JSON::to_json({ methods => $allowed_methods })."\n"); + #$c->stash(template => 'customer/calls_svg.tt'); + + #$c->stash(close_target => $c->uri_for_action("/customer/details", [$c->stash->{contract}->id])); + #$c->stash(template => 'customer/calls.tt'); +# $c->stash(contract => $contract_rs->first); } sub calls_svg :Chained('base') :PathPart('calls/template') :Args { - my ($self, $c, $in); - ($self,$c,@$in{qw/tt_type tt_viewmode tt_sourcestate/}) = @_; + my ($self, $c) = @_; + #$c->log->debug($c->model('DB')); + #return; + #my $db = NGCP::Panel::Model::DB::InvoiceTemplate->new(); + #$c->log->debug($db); #my $contract_id = $in->{contract_id} = ; no warnings 'uninitialized'; - my($validator,$backend,$in); + my($validator,$db,$in); #input - (undef,undef,@$in{qw/tt_type tt_viewmode tt_sourcestate tt_output_type tt_id/}) = @_ ; - $in->{contract_id} = $c->stash->{contract}->id; + (undef,undef,@$in{qw/contract_id tt_type tt_viewmode tt_sourcestate tt_id/}) = ( $c->stash->{contract}->id, @_ ); $in->{tt_string} = $c->request->body_parameters->{template} || ''; #output - my $out={}; + my $tt_string; #input checking & simple preprocessing $validator = NGCP::Panel::Form::Customer::InvoiceTemplate->new; @@ -867,45 +880,37 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args { #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') ); + $db = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') ); #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( + #just use as already implemented fields checking and defaults applying + $validator->setup_form( posted => 1, params => $in, ); - #$validator->validate_form(); - #die(); - #$c->view('SVG'); - #handle request -# my $tt_viewmode //= ''; -# my $tt_state //= 'saved'; -# my $tt_type //= 'svg'; - my $invoicetemplate = $c->request->body_parameters->{template} || ''; + $c->log->debug("validated=".$validator->validated.";\n"); + my $in_validated = $validator->fif; + #dirty hack + $in = $in_validated; - #$c->log->debug("1.invoicetemplate is empty=".($invoicetemplate?0:1).";viewbox=".($invoicetemplate !~/^/is ).";\n"); - $c->log->debug("1.invoicetemplate is empty=".($invoicetemplate?0:1).";viewbox=".($invoicetemplate !~/^/is ).";\n"); - my $form = NGCP::Panel::Form::Customer::InvoiceTemplate->new; - $form->process( - posted => 1, - params => $in, - action => $c->uri_for_action("/customer/calls_svg", [$c->stash->{contract}->id]), - ); - $form->validate(); - if(!$invoicetemplate){ - #getCustomerActiveInvoiceTemplateFromDB. + #really this is for code for field default in validator. The question is how to pass DB model to validator (formhandler) - ideologically correctly? + $tt_string = $in->{tt_string}; + if(!$tt_string){ + #here we also may be better should contact model, not DB directly. Will return to this separation later + #at the end - we can figure out rather basic controller behaviour + $tt_string = $db->getCustomerInvoiceTemplate( %$in ); } - - #we need to get default to 1) sanitize (if in->tt_string) or 2)if not in->tt_string and no customer->tt_string - if($in->{tt_string} || !$tt_string_customer || $tt_string_force_default ){ + + + if(!$tt_string){ + #getDefault + NGCP::Panel::Utils::InvoiceTemplate::getDefaultInvoiceTemplate( c => $c, result => \$tt_string ); try{ - #Utils... mmm - if it were model - there would be no necessity in utils using - NGCP::Panel::Utils::InvoiceTemplate::getDefaultInvoiceTemplate( c => $c, type => $in->{tt_type}, result => \$tt_string_default ); + #Utils... mmm - maybe model? + NGCP::Panel::Utils::InvoiceTemplate::getDefaultInvoiceTemplate( c => $c, result => \$tt_string ); } catch($e) { NGCP::Panel::Utils::Message->error( c => $c, @@ -913,140 +918,49 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args { desc => $c->loc('There is no one invoice template in the system.'), ); } - if($in->{tt_string} && !$tt_string_force_default){ - #sanitize - my $tt_string_sanitized = $in->{tt_string}; - $tt_string_sanitized =~s///gs; - my $tokens_re = qr/\[%(.*?)%\]/; - my $token_shape_re = qr/\s+/; - my %tokens_valid = map{$_=~s/$token_shape_re//sg; $_ => 1;} ($tt_string_default=~/$tokens_re/sg); - foreach( $tt_string_sanitized=~/$tokens_re/sg ){ - my $token_shape=$_; - $token_shape=~s/$token_shape_re//sg; - if(! exists $tokens_valid{$token_shape}){ - $c->log->debug('Not allowed token in invoice template:'.$_.";\n"); - $tt_string_sanitized=~s/(?:\[%)+\s*\Q$_\E\s*(?:%\])+//g; - } - } - #/sanitize - to sub, later - - #irka::loglong(Dumper($tt_string_sanitized)); - $backend->storeCustomerInvoiceTemplate( - %$in, - tt_string_sanitized => \$tt_string_sanitized, - ); - - $out->{tt_string} = $tt_string_sanitized; - }elsif(!$tt_string_customer || $tt_string_force_default){ - $out->{tt_string} = $tt_string_default; - $c->log->debug("apply default;"); - } - }else{#we have customer template, we don't have dynamic template string, we weren't requested to show default - $out->{tt_string} = $tt_string_customer; - } - #/model logic + }#else{ +# #here we have invoice content - of customer or default, so no checking of tt_string is necessary + #if($tt_string){ + #sub candidate, preSaveCustomTemplate + #if it is presaving, making it for default isn't necessary, default should contain it + #but while let it be here + ##moved to correct place - to js, generating svg +##### $c->log->debug("3.tt_string is empty=".($tt_string?0:1).";viewbox=".($tt_string !~/^/is).";\n"); +##### if( $tt_string !~/^/is ){ +##### (my ($width)) = ($tt_string =~/^/is ); +##### $c->log->debug("width=$width;\n"); +##### (my ($height)) = ($tt_string =~/^/is ); +##### my($replaced) = $tt_string =~s/^log->debug("replaced=$replaced;\n"); +##### #storeToDB +##### } + #} #prepare response $c->response->content_type('image/svg+xml'); - $c->log->debug("tt_viewmode=".$in->{tt_viewmode}.";\n"); + #$c->log->debug("tt_viewmode=".$in->{tt_viewmode}.";\n"); + $c->log->debug("tt_viewmode=;\n"); if($in->{tt_viewmode} eq 'raw'){ #$c->stash->{VIEW_NO_TT_PROCESS} = 1; - $c->response->body($out->{tt_string}); + $c->response->body($tt_string); return; }else{ - my $contacts = $c->model('DB')->resultset('contacts')->search({ id => $in->{contract_id} }); - $c->stash( provider => $contacts->first ); - #some preprocessing should be done only before showing. So, there will be: #preSaveCustomTemplate prerpocessing #preShowCustomTemplate prerpocessing { #preShowInvoice #also to model - $out->{tt_string}=~s/(?:{\s*)?(?:\s*})?//gs; + $tt_string =~s/(?:{\s*)?(?:\s*})?//gs; } - - if( ($in->{tt_output_type} eq 'svg') || ( $in->{tt_output_type} eq 'html') ){ - #$c->response->content_type('image/svg+xml'); - $c->stash( template => \$out->{tt_string} ); - $c->detach( $c->view('SVG') ); - }elsif($in->{tt_output_type} eq 'pdf'){ - $c->response->content_type('application/pdf'); - my $svg = $c->view('SVG')->getTemplateProcessed($c,\$out->{tt_string}, $c->stash ); - my(@pages) = $svg=~/())/sig; - - #$c->log->debug($svg); - #my $kit = PDF::WebKit->new(\$svg, page_size => 'A4'); - #push @{ $kit->stylesheets }, "/path/to/css/file"; - # Get an inline PDF - #$out->{tt_string} = $kit->to_pdf; - #$c->response->body($out->{tt_string}); - my ($tempdirbase,$tempdir ); - use File::Temp qw/tempfile tempdir/; - #my($fh, $tempfilename) = tempfile(); - $tempdirbase = join('/',File::Spec->tmpdir,@$in{qw/contract_id tt_type tt_sourcestate/}, $out->{tt_id}); - use File::Path qw( mkpath ); - ! -e $tempdirbase and mkpath( $tempdirbase, 0, 0777 ); - $tempdir = tempdir( DIR => $tempdirbase , CLEANUP => 1 ); - $c->log->debug("tempdirbase=$tempdirbase; tempdir=$tempdir;"); - #try{ - #} catch($e){ - # NGCP::Panel::Utils::Message->error( - # c => $c, - # error => "Can't create temporary directory at: $tempdirbase;" , - # desc => $c->loc("Can't create temporary directory."), - # ); - #} - my $pagenum = 1; - my @pagefiles; - foreach my $page (@pages){ - my $fh; - my $pagefile = "$tempdir/$pagenum.svg"; - push @pagefiles, $pagefile; - open($fh,">",$pagefile); - #try{ - #} catch($e){ - # NGCP::Panel::Utils::Message->error( - # c => $c, - # error => "Can't create temporary page file at: $tempdirbase/$page.svg;" , - # desc => $c->loc("Can't create temporary file."), - # ); - #} - print $fh $page; - close $fh; - $pagenum++; - } - - #$fh->unlink_on_destroy( 0 ); - #my $filename = "/tmp/bbb.svg"; - #open my $fh, ">$filename"; - #binmode $fh; - #print $fh $svg; - #close $fh; - #my $cmd = "/tmp/wkhtmltox/bin/wkhtmltopdf $filename - "; - my $cmd = "rsvg-convert -f pdf ".join(" ", @pagefiles); - $c->log->debug($cmd); - - #`chmod ugo+rwx $filename`; - - #binmode(STDOUT); - #binmode(STDIN); - #$out->{tt_string} = `$cmd`; - { - #$cmd = "fc-list"; - open B, "$cmd |"; - binmode B; - local $/ = undef; - $out->{tt_string} = ; - close B; - } - $c->response->body($out->{tt_string}); - return; - - #$out->{tt_string} = `cat $filename `; - } - + + $c->stash( provider => $contacts->first ); + #use irka; + #irka::loglong(\$tt_string); + $c->stash( template => \$tt_string ); + $c->log->debug("before_detach;\n"); + $c->detach($c->view('SVG')); } } diff --git a/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm b/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm index deeceea7c6..ece21676d7 100644 --- a/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm @@ -4,45 +4,48 @@ use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; use Moose::Util::TypeConstraints; -enum 'TemplateType' => [ qw/svg/ ];#html +enum 'TemplateType' => [ qw/svg html/ ];#html enum 'TemplateViewMode' => [ qw/raw parsed/ ]; enum 'TemplateSourceState' => [ qw/saved previewed/ ]; no Moose::Util::TypeConstraints; -#while use only for validation, no rendering is necessary -#use HTML::FormHandler::Widget::Block::Bootstrap; - -#looks as often repeated -#has '+widget_wrapper' => ( default => 'Bootstrap' ); -#sub build_form_element_class { [qw/form-horizontal/] } - -#Attempt to use Moose to validation -#has 'sort_order' => ( -# is => 'ro', -# isa => enum([qw[ ascending descending ]]), -#); +has '+use_fields_for_input_without_param' => ( default => 1 ); has_field 'tt_type' => ( -# is => 'rw', -# isa => enum([qw[ svg ]]),#html type => 'Text', - required => 0, - #apply => [ 'enum' ], - #apply => [ { check => [qw/svg/] } ], + required => 1, + default => 'svg', + #apply => [ qw/svg/ ], apply => [ 'TemplateType' ], - ); has_field 'tt_viewmode' => ( type => 'Text', required => 0, + apply => [ 'TemplateViewMode' ], + #check => [ qw/raw parsed/ ], + default => 'parsed', ); has_field 'tt_sourcestate' => ( type => 'Text', required => 1, + default => 'saved', + apply => [ 'TemplateSourceState' ], + #check => [ qw/saved previewed/ ], ); +has_field 'tt_string' => ( + type => 'Text', + #default => \& + #apply => [ { check => \&validate_tt_string } ], + required => 0, +); + +sub validate_tt_string{ + #here could be following: take default from file and get all variables and validate variables from customer string +}; + 1; =head1 NAME @@ -51,7 +54,7 @@ NGCP::Panel::Form::InvoiceTemplate =head1 DESCRIPTION -Form to modify a invoice template. +Form to modify an invoice template. =head1 METHODS diff --git a/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm b/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm index c304ed0a79..2380bfe26a 100644 --- a/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm @@ -4,10 +4,9 @@ use base NGCP::Panel::Model::DB::Base; sub getCustomerInvoiceTemplate{ my $self = shift; my (%params) = @_; - my ($contract_id,$tt_sourcestate,$tt_type) = @params{qw/contract_id tt_sourcestate tt_type/}; + my ($contract_id,$tt_sourcestate,$tt_type) = @params{qw/contract_id tt_sourcestate/}; my $result = ''; - my $tt_id = ''; #my $tt_record = $self->resultset('invoice_template')->search({ my $tt_record = $self->schema->resultset('invoice_template')->search({ @@ -20,62 +19,12 @@ sub getCustomerInvoiceTemplate{ #here we will rely on form checking and defaults #if('saved' eq $tt_sourcestate){ if( $tt_record ){ - $result = $tt_record->get_column( 'base64_'.$tt_sourcestate ); - $tt_id = $tt_record->get_column( 'id' ); + $result = \$tt_record->get_column( 'base64_'.$tt_sourcestate ); } if( $result && exists $params{result} ){ ${$params{result}} = $result; } - return ( $tt_id,\$result, $tt_record );#sgorila hata, gori i saray -} - -sub storeCustomerInvoiceTemplate{ - my $self = shift; - my (%params) = @_; - my ($contract_id,$tt_sourcestate,$tt_type, $tt_string, $tt_id) = @params{qw/contract_id tt_sourcestate tt_type tt_string_sanitized tt_id/}; - - #my $tt_record = $self->resultset('invoice_template')->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_template')->update_or_create({ -# reseller_id => $contract_id, -# type => $tt_type, -# is_active => 1, -# 'base64_'.$tt_sourcestate => $$tt_string, -# }); - - my $tt_record = $self->schema->resultset('invoice_template')->search({ - reseller_id => $contract_id, - type => $tt_type, - is_active => 1, - })->first; - #here may be base64 decoding - -# $self->schema->resultset('ivoice_template')->search({ -# reseller_id => $contract_id, -# type => $tt_type, -# })->update_all({ -# is_active => 0, -# }); - - if( !$tt_record ){ - $self->schema->resultset('invoice_template')->create({ - reseller_id => $contract_id, - type => $tt_type, - is_active => 1, - 'base64_'.$tt_sourcestate => $$tt_string, - }); - }else{ - $self->schema->resultset('invoice_template')->update({ - reseller_id => $contract_id, - type => $tt_type, - is_active => 1, - 'base64_'.$tt_sourcestate => $$tt_string, - id => $tt_record->get_column( 'id' ), - }, - { key => 'id' }); - } - }); + return $result; } 1; \ No newline at end of file diff --git a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm index ba6385d239..e7436fe570 100644 --- a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm @@ -3,17 +3,11 @@ use strict; use warnings; use Moose; use Sipwise::Base; -use DBIx::Class::Exception; -use NGCP::Panel::Utils::DateTime; -#use NGCP::Panel::Utils::DateTime; - -sub getDefault{ - my %params = @_; sub getDefaultInvoiceTemplate{ my (%in) = @_; #in future may be we will store root default in Db too, but now it is convenient to edit template as file - my $result = $in{c}->view('SVG')->getTemplateContent($in{c}, 'customer/calls_'.$in{type}.'.tt'); + my $result = $in{c}->view('SVG')->getTemplateContent($in{c}, 'customer/calls_svg.tt'); #$in{c}->log->debug("result=$result;"); @@ -23,24 +17,4 @@ sub getDefaultInvoiceTemplate{ return \$result; } -sub getCustomerTemplate{ - my %params = @_; - - my $c = $params{c}; - my $contract_id = $params{contract_id} || $c->stash->{contract}->id; - my $tt_state = $params{tt_state} || 'saved'; - my $result; - - my $template_record = $c->model('DB')->resultset('invoice_template')->search({ - reseller_id => $contract_id, - is_active => 1, - })->first; - #here may be base64 decoding - if('saved' eq $tt_state){ - $result = \$template_record->get_column('base64_'.$tt_state); - } - return $result; -} - - 1; \ No newline at end of file diff --git a/lib/NGCP/Panel/View/SVG.pm b/lib/NGCP/Panel/View/SVG.pm index 5ee61f801e..d1eb7b37ea 100644 --- a/lib/NGCP/Panel/View/SVG.pm +++ b/lib/NGCP/Panel/View/SVG.pm @@ -38,7 +38,9 @@ sub process } return 1; } -sub getTemplate{ +#method is necessary to apply APP specific template configurations, e.g. path, tt file extensions etc +#may be moved to main view class, but as on template_invoice experiments stage it would be ok to leave it in separated class +sub getTemplateContent{ my ( $self, $c, $template ) = @_; if(defined $template){ $c->log->debug("getTemplate: template=$template;");