diff --git a/lib/NGCP/Panel/Controller/Customer.pm b/lib/NGCP/Panel/Controller/Customer.pm index ce04a6d5ed..814f2ccee4 100644 --- a/lib/NGCP/Panel/Controller/Customer.pm +++ b/lib/NGCP/Panel/Controller/Customer.pm @@ -812,10 +812,29 @@ sub edit_balance :Chained('base') :PathPart('balance/edit') :Args(0) { $c->stash(form => $form); $c->stash(edit_flag => 1); } +sub invoice_data :Chained('base') :PathPart('invoice') :CaptureArgs(0) { + my ($self, $c) = @_; + $c->log->debug('invoice_data'); + my $contract_id = $c->stash->{contract}->id; + my $stime = NGCP::Panel::Utils::DateTime::current_local()->truncate(to => 'month'); + my $etime = $stime->clone->add(months => 1); -sub invoice_delete :Chained('base') :PathPart('invoice_template/delete') :CaptureArgs(1) { + #look, NGCP::Panel::Utils::Contract - it is kind of backend separation here + my $invoice_details = NGCP::Panel::Utils::Contract::get_contract_calls_rs( + c => $c, + contract_id => $contract_id, + stime => $stime, + etime => $etime, + ); + #FAKE FAKE FAKE FAKE + $invoice_details = [$invoice_details->all()]; + my $i = 1; + $invoice_details = [map{[$i++,$_]} (@$invoice_details) x 21]; + $c->stash(invoice_details => $invoice_details ); +} +sub invoice_template_delete :Chained('base') :PathPart('invoice_template/delete') :Args(1) { my ($self, $c) = @_; - $c->log->debug('invoice_delete'); + $c->log->debug('invoice_template_delete'); my($validator,$backend,$in,$out); (undef,undef,@$in{qw/tt_id/}) = @_; @@ -862,76 +881,33 @@ sub invoice_delete :Chained('base') :PathPart('invoice_template/delete') :Captur #think about it more $backend->deleteCustomerInvoiceTemplate(%$in); + $c->forward( 'invoice_template_list' ); } - -sub invoice_template_aux_embedImage :Chained('list_customer') :PathPart('auxembedimage') :Args(0) { - my ($self, $c) = @_; - - #I know somewhere is logging of all visited methods - $c->log->debug('invoice_template_aux_handleImageUpload'); +sub invoice_template_list_data :Chained('invoice_data') :PathPart('') :CaptureArgs(0) { + my ($self, $c) = @_; + $c->log->debug('invoice_template_list_data'); my($validator,$backend,$in,$out); - - #todo - #mime-type and type checking in form - - $in = $c->request->parameters; - $in->{svg_file} = $c->request->upload('svg_file'); - if($in->{svg_file}) { - my $ft = File::Type->new(); - $out->{image_content} = $in->{svg_file}->slurp; - $out->{image_content_mimetype} = $ft->mime_type($out->{image_content}); - $out->{image_content_base64} = encode_base64($out->{image_content}, ''); - } - $c->log->debug('mime-type '.$out->{image_content_mimetype}); - $c->stash(out => $out); - $c->stash(in => $in); - $c->stash(template => 'customer/invoice_template_aux_embedimage.tt'); - $c->detach( $c->view('SVG') ); - -} -sub invoice_data :Chained('base') :PathPart('invoice') :CaptureArgs(0) { - my ($self, $c) = @_; - $c->log->debug('invoice_data'); - my $contract_id = $c->stash->{contract}->id; - my $stime = NGCP::Panel::Utils::DateTime::current_local()->truncate(to => 'month'); - my $etime = $stime->clone->add(months => 1); - - #look, NGCP::Panel::Utils::Contract - it is kind of backend separation here - my $invoice_details = NGCP::Panel::Utils::Contract::get_contract_calls_rs( - c => $c, - contract_id => $contract_id, - stime => $stime, - etime => $etime, - ); - #FAKE FAKE FAKE FAKE - $invoice_details = [$invoice_details->all()]; - my $i = 1; - $invoice_details = [map{[$i++,$_]} (@$invoice_details) x 21]; - $c->stash(invoice_details => $invoice_details ); + $in->{contract_id} = $c->stash->{contract}->id; + $backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') ); + my $records = $backend->getCustomerInvoiceTemplateList( %$in ); + $c->stash( invoice_template_list => $records ); } -sub invoice_template_list :Chained('invoice_data') :PathPart('') :CaptureArgs(0) { +sub invoice_template_list :Chained('base') :PathPart('') :Args(0) { my ($self, $c) = @_; $c->log->debug('invoice_template_list'); - my($validator,$backend,$in,$out); - $in->{contract_id} = $c->stash->{contract}->id; - $backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') ); - $c->stash( invoice_template_list => $backend->getCustomerInvoiceTemplateList( %$in )->all ); + $c->stash( template => 'customer/invoice_template_list.tt' ); + $c->forward( 'invoice_template_list_data' ); + $c->detach($c->view('SVG'));#just no wrapper - aybe there is some other way? } -sub invoice :Chained('invoice_template_list') :PathPart('') :Args(0) { +sub invoice :Chained('invoice_template_list_data') :PathPart('') :Args(0) { my ($self, $c) = @_; $c->stash(template => 'customer/invoice.tt'); } sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { my ($self, $c) = @_; - #$c->log->debug($c->model('DB')); - #return; - #my $db = NGCP::Panel::Model::DB::InvoiceTemplate->new(); $c->log->debug('invoice_template'); - - #my $contract_id = $in->{contract_id} = ; - no warnings 'uninitialized'; my($validator,$backend,$in,$out); @@ -970,28 +946,11 @@ sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { return; } my $in_validated = $validator->fif; - #use irka; - #use Data::Dumper; - #irka::loglong(Dumper($in)); - #irka::loglong(Dumper($in_validated)); #dirty hack 1 #really model logic should recieve validated input, but raw input also should be saved somewhere $in = $in_validated; - #dirty hack 2 - #validate methods in form configuration don't change fields values, will find why later - #for other values see defaults in form - if($in->{tt_type} eq 'svgpdf'){ - $in->{tt_type} = 'svg'; - $in->{tt_output_type} = 'pdf'; - }elsif($in->{tt_type} eq 'html'){ - $in->{tt_output_type} = 'html'; - } - #use irka; - #use Data::Dumper; - #irka::loglong(Dumper($in)); - #model logic my $tt_string_default = ''; my $tt_string_customer = ''; @@ -1000,7 +959,7 @@ sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { if(!$in->{tt_string} && !$tt_string_force_default){ #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 - ($out->{tt_id}) = $backend->getCustomerInvoiceTemplate( %$in, result => \$tt_string_customer ); + ($out->{tt_id},undef,$out->{tt_data}) = $backend->getCustomerInvoiceTemplate( %$in, result => \$tt_string_customer ); } #we need to get default to 1) sanitize (if in->tt_string) or 2)if not in->tt_string and no customer->tt_string @@ -1032,7 +991,6 @@ sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { } #/sanitize - to sub, later - #irka::loglong(Dumper($tt_string_sanitized)); $backend->storeCustomerInvoiceTemplate( %$in, tt_string_sanitized => \$tt_string_sanitized, @@ -1052,23 +1010,26 @@ sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { #mess,mess,mess here if($in->{tt_output_type} eq 'svg'){ $c->response->content_type('text/html'); + #multi-svg document (as well as one-svg documet) is shown ok with text/html # $c->response->content_type('image/svg+xml'); }elsif($in->{tt_output_type} eq 'pdf'){ $c->response->content_type('application/pdf'); }elsif($in->{tt_output_type} eq 'html'){ $c->response->content_type('text/html'); + }elsif($in->{tt_output_type}=~m'zip'){ + $c->response->content_type('application/zip'); } + if($in->{tt_viewmode} eq 'raw'){ #$c->stash->{VIEW_NO_TT_PROCESS} = 1; $c->response->body($out->{tt_string}); return; - }else{ + }else{#parsed 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 @@ -1082,20 +1043,30 @@ sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { #$c->response->content_type('image/svg+xml'); $c->stash( template => \$out->{tt_string} ); $c->detach( $c->view('SVG') ); + }elsif($in->{tt_output_type} eq 'json'){ + my $aaData = { + template =>{ + raw => $out->{tt_string}, + parsed => $c->view('SVG')->getTemplateProcessed($c,\$out->{tt_string}, $c->stash ), + }, + form => { + tt_id => $out->{tt_data}->get_column('id'), + } + }; + foreach(qw/name is_active/){ + $aaData->{form}->{$_} = $out->{tt_data}->get_column($_); + } + #$c->stash( aaData => $out ); + $c->detach( $c->view('JSON') ); }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(); + #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 ); @@ -1129,13 +1100,6 @@ sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { $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`; @@ -1158,19 +1122,31 @@ sub invoice_template :Chained('invoice_data') :PathPart('template') :Args { } } -sub subscriber_ajax :Chained('base') :PathPart('subscriber/ajax') :Args(0) { +sub invoice_template_aux_embedImage :Chained('list_customer') :PathPart('auxembedimage') :Args(0) { my ($self, $c) = @_; - my $res = $c->stash->{contract}->voip_subscribers->search({ - 'provisioning_voip_subscriber.is_pbx_group' => 0, - 'me.status' => { '!=' => 'terminated' }, - - },{ - join => 'provisioning_voip_subscriber', - }); - NGCP::Panel::Utils::Datatables::process($c, $res, $c->stash->{subscriber_dt_columns}); - $c->detach( $c->view("JSON") ); + + #I know somewhere is logging of all visited methods + $c->log->debug('invoice_template_aux_handleImageUpload'); + my($validator,$backend,$in,$out); + + #todo + #mime-type and type checking in form + + $in = $c->request->parameters; + $in->{svg_file} = $c->request->upload('svg_file'); + if($in->{svg_file}) { + my $ft = File::Type->new(); + $out->{image_content} = $in->{svg_file}->slurp; + $out->{image_content_mimetype} = $ft->mime_type($out->{image_content}); + $out->{image_content_base64} = encode_base64($out->{image_content}, ''); + } + $c->log->debug('mime-type '.$out->{image_content_mimetype}); + $c->stash(out => $out); + $c->stash(in => $in); + $c->stash(template => 'customer/invoice_template_aux_embedimage.tt'); + $c->detach( $c->view('SVG') ); + } - sub pbx_group_ajax :Chained('base') :PathPart('pbx/group/ajax') :Args(0) { my ($self, $c) = @_; my $res = $c->stash->{contract}->voip_subscribers->search({ diff --git a/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm b/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm index 5491fac7e5..d665643274 100644 --- a/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Form/Customer/InvoiceTemplate.pm @@ -4,7 +4,7 @@ use HTML::FormHandler::Moose; extends 'NGCP::Panel::Form::ValidatorBase'; use Moose::Util::TypeConstraints; -enum 'TemplateType' => [ qw/svg html svgpdf/ ];#html +enum 'TemplateType' => [ qw/svg html/ ];#html enum 'TemplateTypeOutput' => [ qw/svg html pdf svgzip htmlzip pdfzip/ ];#html enum 'TemplateViewMode' => [ qw/raw parsed/ ]; enum 'TemplateSourceState' => [ qw/saved previewed default/ ]; @@ -18,7 +18,6 @@ has_field 'tt_type' => ( default => 'svg', apply => [ { type => 'TemplateType' }, - #{ transform => sub{ $_[0] eq 'svgpdf' and return 'svg'; } }, ], ); @@ -28,7 +27,6 @@ has_field 'tt_output_type' => ( default => 'svg', apply => [ { type => 'TemplateTypeOutput' }, - #{ when => { tt_type => 'svgpdf' }, transform => sub{ 'pdf' } }, ], ); @@ -69,22 +67,6 @@ has_field 'tt_id' => ( required => 0, ); -#sub validate_tt_string{ - #here could be following: take default from file and get all variables and validate variables from customer string -#}; -#sub validate { -# my ( $self ) = @_; # self is the form -# if( $self->field('tt_type')->value eq 'svgpdf'){ -# use irka; -# use Data::Dumper; -# irka::loglong("\n\n\nin validate\nBBBBBBBBBBBBBBBBBBBBB\naaaaaaaaaaaaaaa\n"); -# #die(); -# $self->field('tt_output_type')->value('pdf'); -# $self->field('tt_type')->value('svg'); -# } -# return 1; -#}; - 1; =head1 NAME diff --git a/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm b/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm index 01f16e12d7..6c572a6a6f 100644 --- a/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm @@ -4,17 +4,22 @@ 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,$tt_id) = @params{qw/contract_id tt_sourcestate tt_type tt_id/}; my $result = ''; - my $tt_id = ''; + my $conditions = {}; #my $tt_record = $self->resultset('invoice_template')->search({ - my $tt_record = $self->schema->resultset('invoice_template')->search({ - reseller_id => $contract_id, - is_active => 1, - type => $tt_type - })->first; + if($tt_id){ + $conditions = { id => $tt_id }; + }else{ + $conditions = { + reseller_id => $contract_id, + is_active => 1, + type => $tt_type + }; + } + my $tt_record = $self->schema->resultset('invoice_template')->search($conditions)->first; #here may be base64 decoding #here we will rely on form checking and defaults @@ -26,7 +31,7 @@ sub getCustomerInvoiceTemplate{ if( $result && exists $params{result} ){ ${$params{result}} = $result; } - return ( $tt_id,\$result, $tt_record );#sgorila hata, gori i saray + return ( $tt_id, \$result, $tt_record );#sgorila hata, gori i saray } sub storeCustomerInvoiceTemplate{ @@ -81,9 +86,10 @@ sub getCustomerInvoiceTemplateList{ 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/}; - return $self->schema->resultset('invoice_template')->search({ + + return [ $self->schema->resultset('invoice_template')->search({ reseller_id => $contract_id, - }); + })->all ]; } sub deleteCustomerInvoiceTemplate{ my $self = shift; diff --git a/share/templates/customer/invoice.tt b/share/templates/customer/invoice.tt index fb1e11b4ce..a799d5af07 100644 --- a/share/templates/customer/invoice.tt +++ b/share/templates/customer/invoice.tt @@ -1,4 +1,9 @@ [% USE Dumper %] +[% USE format %] +[% money_format = format('%.2f') %] +[% IF !c.user.read_only && (c.user.roles == 'admin' || c.user.roles == 'reseller') -%] +[% write_access = 1 %] +[%END%] [%PROCESS 'helpers/datatables_vars.tt' no_auto_helper = 1 @@ -10,9 +15,6 @@ [% site_config.title = c.loc('Customer Invoice template for #[_1] ([_2])',contract.id, product.name) -%] [% END -%] -[% IF !c.user.read_only && (c.user.roles == 'admin' || c.user.roles == 'reseller') -%] -[% write_access = 1 %] -[%END%] @@ -22,7 +24,6 @@ function init_embed() { var svgEditFrameName = 'svgedit'; var frame = document.getElementById(svgEditFrameName); svgCanvas = new EmbeddedSVGEdit(frame); - //svgCanvas.zoomImage(2); // Hide main button, as we will be controlling new/load/save etc from the host document var doc; doc = frame.contentDocument; @@ -33,42 +34,118 @@ function init_embed() { //var mainButton = doc.getElementById('main_button'); //mainButton.style.display = 'none'; } -function loadSvg(params) { - //alert('[%- c.uri_for_action("/customer/invoice_template", [contract.id]) -%]'+params); - $.ajax({ - url: '[%- c.uri_for_action("/customer/invoice_template", [contract.id]) -%]'+params, - }).done(function(svgParsedString){ - svgCanvas.setSvgString(svgParsedString)( +function setSvgStringToEditor( svgParsedString ){ + svgCanvas.setSvgString( svgParsedString )( function(data,error){ if(error){ }else{ - //var svgEditIframe = $("#svgedit").contents().find('#fit_to_canvas'); - //var objToClick = $("#svgedit").contents().find('#fit_to_canvas'); svgCanvas.zoomChanged('', 'canvas'); - //alert('iframe id='+objToClick.attr("someattr")+';'); - //alert('mousedown='+objToClick.attr("onmousedown")+';'); - //alert('click='+objToClick.attr("onclick")+';'); - //alert('mouseup='+objToClick.attr("onmouseup")+';'); - //alert($._data(objToClick,'events')); - //.contents().find('#fit_to_canvas') - //alert(jQuery.data($("#svgedit"),'mouseup')); - //objToClick.bind('click',function(){alert('Bound onclick for canvas option.');}); - //jQuery.each(objToClick.data('mouseup'), function(i, event){alert('i='+i+';event='+event);}); - //alert('iframe id='+$("#svgedit").contents().find('#iframebutton').attr("onclick")+';'); - //$("#svgedit").contents().find('#iframebutton').click(); - //objToClick.mousedown(); - //objToClick.mouseup(); - //objToClick.click(); - //$("#svgedit").contents().find('#fit_to_canvas').mousedown(); } } - ); + ); +} +var uriForAction = function( data, type ){ + //also we can think about getting URI's via ajax ) + var q_template; + switch(type){ + case 'invoice_template_previewed': + //q_template = '[%- c.uri_for_action("/customer/invoice_template", ['contract_id','svg','parsed','previewed','svg','tt_id']) -%]'; + q_template = '[%- c.uri_for_action("/customer/invoice_template", ["contract_id"]) -%]'+'/svg/parsed/previewed/svg/tt_id'; + break; + case 'invoice_template_saved': + //q_template = '[%- c.uri_for_action("/customer/invoice_template", ['contract_id','svg','parsed','saved','svg','tt_id']) -%]'; + q_template = '[%- c.uri_for_action("/customer/invoice_template", ["contract_id"]) -%]'+'/svg/parsed/previewed/svg/tt_id'; + break; + case 'invoice_template_list': + q_template = '[%- c.uri_for_action("/customer/invoice_template_list", ['contract_id']) -%]'; + break; + case 'invoice_template': + default: + //q_template = '[%- c.uri_for_action("/customer/invoice_template", ['contract_id','tt_type','tt_viewmode','tt_sourcestate','tt_output_type','tt_id']) -%]'; + q_template = '[%- c.uri_for_action("/customer/invoice_template", ["contract_id"]) -%]'+'/tt_type/tt_viewmode/tt_sourcestate/tt_output_type/tt_id'; + break; + } + //alert('1.q_template='+q_template); + //alert('contract_id='+data.contract_id+';tt_id='+data.tt_id); + if(!data.tt_id){data.tt_id = '';} + if(!data.tt_type){data.tt_type = 'svg';} + if(!data.tt_output_type){data.tt_output_type = 'svg';} + var params = ['contract_id','tt_id','tt_type','tt_output_type','tt_viewmode','tt_sourcestate']; + params.forEach(function(key){ + q_template=q_template.replace(key,data[key]); }); + /* + q_template=q_template.replace('contract_id',data.contract_id); + q_template=q_template.replace('tt_id',data.tt_id); + q_template=q_template.replace('tt_type',data.tt_type); + q_template=q_template.replace('tt_output_type',data.tt_output_type); + q_template=q_template.replace('tt_viewmode',data.tt_viewmode); + q_template=q_template.replace('tt_sourcestate',data.tt_sourcestate); + */ + q_template=q_template.replace(/([^:])\/{2,}/g,'$1/'); + q_template=q_template.replace(/\/+$/,''); + //alert('2.q_template='+q_template); + return q_template; +} +//function loadInvoiceTemplateData(params) { +//function loadInvoiceTemplateData(tt_type,tt_viewmode,tt_sourcestate,tt_output_type,tt_id,contract_id) { +function loadInvoiceTemplateData( data ){ + //params spec: tt_type=[svg|html]/tt_viewmode[parsed|raw]/tt_sourcestate[default|previewed]/tt_output_type[svg|pdf|html|json|svgzip|pdfzip|htmlzip]/tt_id + //tt_output_type=svg really outputs text/html mimetype. But it will be couple of tags ( per page). + var q = uriForAction( data, 'invoice_template' ); + alert('loadInvoiceTemplateData: q='+q+';'); + $.ajax({ + url: q, + datatype: "json", + }).done(function(jsonres){ + var templatedata = $.parseJson(res); + svgRawString = templatedata.template.raw; + setSvgStringToEditor( svgRawString ); + }); +} +function fetchSvgToEditor( data ) { + var q = uriForAction( data, 'invoice_template' ); + //alert('fetchSvgToEditor: q='+q+';'); + $.ajax({ + url: q, + }).done( function ( httpResponse ){ + setSvgStringToEditor( httpResponse ); + } ); } -function showSvgParsed(){ - svgCanvas.getSvgString()(handleShowSvgParsedData); +var setSvgStringToPreview = function( svgParsedString, q ) { + var previewIframe = document.getElementById('svgpreview'); + if ($.browser.msie) { + //we need to repeat query to server for msie if we don't want send template string via GET method + previewIframe.src = q; + }else{ + previewIframe.src = "data:text/html," + encodeURIComponent(svgParsedString); + } +} +function refreshTemplateList ( contract_id ){ + fetch_into( + 'collapse_invoice_template_list', + uriForAction( {'contract_id': contract_id}, 'invoice_template_list' ), + '', + function(){ mainWrapperInit(); } + ); } +function savePreviewedAndShowParsed( data ){ + var svgString = svgCanvas.getSvgString(handleShowSvgParsedData); + var q = uriForAction( data, 'invoice_template_previewed' ); + alert('svgString='+svgString+'; q='+q+';'); + //save + $.post( q, { template: svgString } ) + .done( function( httpResponse ){ + // & show template + alert('httpResponse='+httpResponse+';'); + + setSvgStringToPreview( httpResponse, q ) + //refresh list after saving + refreshTemplateList( data.contract_id ); + } ); +} + function handleShowSvgParsedData(svgString, error) { if (error) { @@ -76,6 +153,8 @@ function handleShowSvgParsedData(svgString, error) { } else { + return svgString; + /* var q = '[%- c.uri_for_action("/customer/invoice_template", [contract.id]) -%]'+'/svg/parsed/previewed'; $.post( q, { template: svgString }) .done( function( svgParsedString ) { @@ -101,26 +180,16 @@ function handleShowSvgParsedData(svgString, error) { previewIframe.src = "data:image/svg+xml," + encodeURIComponent(svgParsedString); } } - }); + });*/ } } - -function saveSvg() { - svgCanvas.getSvgString()(handleSaveSvgData); -} -function handleSaveSvgData(data, error) { - if (error) - { - alert('error ' + error); - } - else - { - var q = '[%- c.uri_for_action("/customer/invoice_template", [contract.id]) -%]'+'/svg/parsed/saved'; - $.post( q, { template: encodeURIComponent(data) }) - .done(function( httpResponse ) { - - }); - } +function saveTemplate( contract_id, tt_id ) { + var svgString = svgCanvas.getSvgString(); + var q = uriForAction( data, 'invoice_template_saved' ); + $.post( q, { template: encodeURIComponent( svgString ) }) + .done( function( httpResponse ) { + refreshTemplateList( data.contract_id ); + }); } @@ -145,17 +214,18 @@ function handleSaveSvgData(data, error) { [% #while we don't due to local -# clearHelper(); -# helper.name = c.loc('Invoice Details'); -# helper.name_single = c.loc('Invoice Record'); -# helper.identifier = 'invoice_details'; -# initHelperAuto(); -# PROCESS 'helpers/datatables.tt'; + clearHelper(); + helper.name = c.loc('Invoice Details'); + helper.name_single = c.loc('Invoice Record'); + helper.identifier = 'invoice_details'; + initHelperAuto(); + PROCESS 'helpers/datatables.tt'; -%] + @@ -167,12 +237,13 @@ function handleSaveSvgData(data, error) { [%# Dumper.dump_html(invoice_details.as_query)%] [% FOR call IN invoice_details -%] - [%IF call.1; call = call.1; END%] + [%IF call.1; row_number = call.0; call = call.1; END%] [% total_number = total_number + call.get_column('number') %] [% total_duration = total_duration + call.get_column('duration') %] [% total_free_time = total_free_time + call.get_column('free_time') %] [% total_cost = total_cost + call.get_column('cost') %] + @@ -181,7 +252,7 @@ function handleSaveSvgData(data, error) { [%END%] - + @@ -200,22 +271,43 @@ function handleSaveSvgData(data, error) { [% c.loc('Invoice Templates') %]
- [%PROCESS 'customer/invoice_template_list.tt'%] + [%PROCESS 'customer/invoice_template_list.tt' %]
+[%#It can be separated later to form template and loaded with ajax and fillinform template::toolkit plugin. %] +[%#It is reliable and easy to implement solution, but requires additional modules. For now populate small form with jquery.%] +[%# USE FillInForm %]
+
+
- [% c.loc('Refresh Preview')%] + [% c.loc('Refresh Preview')%] - [% c.loc('Save template')%] + [% c.loc('Save template')%]
[%initial = 'default'%] - +
+ \ No newline at end of file diff --git a/share/templates/customer/invoice_template_aux.tt b/share/templates/customer/invoice_template_aux.tt index 4a01cbcc0d..cfd4591908 100644 --- a/share/templates/customer/invoice_template_aux.tt +++ b/share/templates/customer/invoice_template_aux.tt @@ -1,5 +1,6 @@ [%USE Dumper%] [%USE Math%] +[% total = {perpage => [], global => {} } -%] [%MACRO row_y_re(tt_type) BLOCK -%] [% IF tt_type == 'svg' -%] @@ -50,7 +51,7 @@ [%page%] [%END%] -[%MACRO adjustrow(data, rowtype, tt_type, row_vertical_interval, rownumber) BLOCK -%] +[%MACRO adjustrow(data, page, rowtype, tt_type, row_vertical_interval, rownumber) BLOCK -%] [%# y_re = row_y_re(tt_type) %] [% row = get_row(data, rowtype) %] @@ -65,13 +66,17 @@ [%row%] [%END -%] -[%MACRO list_calls(callsdata, rowtype, total, tt_type, row_vertical_interval) BLOCK-%] +[%MACRO list_calls(callsdata, page, rowtype, total, tt_type, row_vertical_interval) BLOCK-%] [% FOR call IN callsdata -%][%#invoice_details%] - [% total.number = total.number + call.get_column('number') -%] - [% total.duration = total.duration + call.get_column('duration') -%] - [% total.free_time = total.free_time + call.get_column('free_time') -%] - [% total.cost = total.cost + call.get_column('cost') -%] - [% adjustrow(call, rowtype, tt_type, row_vertical_interval, loop.count) -%] + [% total.global.number = total.number + call.get_column('number') -%] + [% total.global.duration = total.duration + call.get_column('duration') -%] + [% total.global.free_time = total.free_time + call.get_column('free_time') -%] + [% total.global.cost = total.cost + call.get_column('cost') -%] + [% total.perpage.${page}.number = total.number + call.get_column('number') -%] + [% total.perpage.${page}.duration = total.duration + call.get_column('duration') -%] + [% total.perpage.${page}.free_time = total.free_time + call.get_column('free_time') -%] + [% total.perpage.${page}.cost = total.cost + call.get_column('cost') -%] + [% adjustrow(call, page, rowtype, tt_type, row_vertical_interval, loop.count) -%] [%END -%] [%END -%] diff --git a/share/templates/customer/invoice_template_list.tt b/share/templates/customer/invoice_template_list.tt index dfb71d29d2..537ab220fb 100644 --- a/share/templates/customer/invoice_template_list.tt +++ b/share/templates/customer/invoice_template_list.tt @@ -1,10 +1,22 @@ +[% USE Dumper %] +[% USE format %] +[% money_format = format('%.2f') %] +[% IF !c.user.read_only && (c.user.roles == 'admin' || c.user.roles == 'reseller') -%] +[% write_access = 1 %] +[%END%] +
[% IF write_access -%] - [% c.loc('Create invoice template')%] + [% c.loc('Create invoice template')%]
[% END -%] + [%IF invoice_template_list.size %]
[% c.loc('Num') %] [% c.loc('Zone') %] [% c.loc('Calls amount') %] [% c.loc('Duration') %]
[% row_number %] [% call.get_column('zone') %]
[% call.get_column('number') %]
[% call.get_column('duration')|format('%.3f') %]
[% c.loc('Total') %][% c.loc('Total') %]
[% total_number %]
[% total_duration | format('%.3f') %]
[% total_free_time | format('%d')%]
@@ -15,32 +27,37 @@ - [%# Dumper.dump_html(invoice_template_list.as_query)%] [% FOR template IN invoice_template_list -%] + [%# Dumper.dump_html(invoice_template_list.as_query)%] + [%# Dumper.dump_html(template)%] - +
[% template.get_column('is_active') %] [% template.get_column('type') %][%# template.get_column('name') %]=[%template.get_column('id')%]:[%- c.uri_for_action("/customer/invoice_template_delete", [contract.id, template.get_column('id')]) -%]= [%# template.get_column('name') %]
+ [%END%] diff --git a/share/templates/customer/invoice_template_svg.tt b/share/templates/customer/invoice_template_svg.tt index 4b4a80ae17..20a729178e 100644 --- a/share/templates/customer/invoice_template_svg.tt +++ b/share/templates/customer/invoice_template_svg.tt @@ -134,10 +134,9 @@ g, text, tspan { - - - - + + + @@ -181,10 +180,9 @@ g, text, tspan { 0.00 - - - - + + + @@ -232,8 +230,8 @@ g, text, tspan { - - + +