MT#5879 Well, customer can save his invoice. He can't delete. But he can rewrite from default now. But specification of using default (and as action - deletion of his template - is necessary).

ipeshinskaya/InvoiceTemplate5
Irina Peshinskaya 12 years ago committed by Victor Seva
parent 71666884cf
commit d814805244

@ -811,30 +811,23 @@ sub edit_balance :Chained('base') :PathPart('balance/edit') :Args(0) {
$c->stash(form => $form);
$c->stash(edit_flag => 1);
}
#https://10.15.20.100:1444/customer/3/balance/edit?back=https%3A%2F%2F10.15.20.100%3A1444%2Fcustomer%2F3%2Fdetails
sub calls :Chained('base') :PathPart('calls') :Args(0) {
my ($self, $c) = @_;
# 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);
# my $zonecalls_rs = NGCP::Panel::Utils::Contract::get_contract_calls_rs(
# c => $c,
# contract_id => $contract_id,
# stime => $stime,
# etime => $etime,
# );
if( ! $c->stash->{zonecalls_rs} ){
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);
my $zonecalls_rs = NGCP::Panel::Utils::Contract::get_contract_calls_rs(
c => $c,
contract_id => $contract_id,
stime => $stime,
etime => $etime,
);
$c->stash(zonecalls_rs => $zonecalls_rs);
}
$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 {
@ -848,14 +841,20 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args {
no warnings 'uninitialized';
my($validator,$db,$in);
my($validator,$backend,$in);
#input
(undef,undef,@$in{qw/contract_id tt_type tt_viewmode tt_sourcestate tt_id/}) = ( $c->stash->{contract}->id, @_ );
(undef,undef,@$in{qw/tt_type tt_viewmode tt_sourcestate tt_id/}) = @_ ;
$in->{contract_id} = $c->stash->{contract}->id;
$in->{tt_string} = $c->request->body_parameters->{template} || '';
#use irka;
#use Data::Dumper;
#irka::loglong(Dumper($in));
#return;
#output
my $tt_string;
my $output_string;
#input checking & simple preprocessing
$validator = NGCP::Panel::Form::Customer::InvoiceTemplate->new;
@ -865,7 +864,7 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args {
#storage
#pass scheme here is ugly, and should be moved somehow to DB::Base
$db = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') );
$backend = NGCP::Panel::Model::DB::InvoiceTemplate->new( schema => $c->model('DB') );
#really, we don't need a form here at all
@ -880,22 +879,24 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args {
my $in_validated = $validator->fif;
#dirty hack
$in = $in_validated;
#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){
#real logic
my $tt_string_default = '';
my $tt_string_customer = '';
my $tt_string_force_default = $in->{tt_sourcestate} eq 'default';
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
$tt_string = $db->getCustomerInvoiceTemplate( %$in );
$backend->getCustomerInvoiceTemplate( %$in, result => \$tt_string_customer );
}
if(!$tt_string){
#getDefault
NGCP::Panel::Utils::InvoiceTemplate::getDefaultInvoiceTemplate( c => $c, result => \$tt_string );
#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 ){
try{
#Utils... mmm - maybe model?
NGCP::Panel::Utils::InvoiceTemplate::getDefaultInvoiceTemplate( c => $c, result => \$tt_string );
NGCP::Panel::Utils::InvoiceTemplate::getDefaultInvoiceTemplate( c => $c, result => \$tt_string_default );
} catch($e) {
NGCP::Panel::Utils::Message->error(
c => $c,
@ -903,8 +904,32 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args {
desc => $c->loc('There is no one invoice template in the system.'),
);
}
}#else{
# #here we have invoice content - of customer or default, so no checking of tt_string is necessary
if($in->{tt_string} && !$tt_string_force_default){
#sanitize
my $tt_string_sanitized = $in->{tt_string};
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}){
$tt_string_sanitized=~s/\Q$_\E//g;
}
}
$backend->storeCustomerInvoiceTemplate(
%$in,
tt_string_sanitized => \$tt_string_sanitized,
);
$output_string = $tt_string_sanitized;
}elsif(!$tt_string_customer){
$output_string = $tt_string_default;
}
}else{#we have customer template, we don't have dynamic template string, we weren't requested to show default
$output_string = $tt_string_customer;
}
#if($tt_string){
#sub candidate, preSaveCustomTemplate
#if it is presaving, making it for default isn't necessary, default should contain it
@ -915,7 +940,7 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args {
##### (my ($width)) = ($tt_string =~/^<svg.*?width.*?(\d+).*?>/is );
##### $c->log->debug("width=$width;\n");
##### (my ($height)) = ($tt_string =~/^<svg.*?height.*?(\d+).*?>/is );
##### my($replaced) = $tt_string =~s/^<svg(.*?(?:width.*?height|height.*width).*?\d+.*? )/<svg $1 viewBox="0 0 $width $height" /i;
##### my($replaced) = $output_string =~s/^<svg(.*?(?:width.*?height|height.*width).*?\d+.*? )/<svg $1 viewBox="0 0 $width $height" /i;
##### $c->log->debug("replaced=$replaced;\n");
##### #storeToDB
##### }
@ -927,7 +952,7 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args {
$c->log->debug("tt_viewmode=;\n");
if($in->{tt_viewmode} eq 'raw'){
#$c->stash->{VIEW_NO_TT_PROCESS} = 1;
$c->response->body($tt_string);
$c->response->body($output_string);
return;
}else{
my $contacts = $c->model('DB')->resultset('contacts')->search({ id => $in->{contract_id} });
@ -937,13 +962,13 @@ sub calls_svg :Chained('base') :PathPart('calls/template') :Args {
{
#preShowInvoice
#also to model
$tt_string =~s/(?:{\s*)?<!--{|}-->(?:\s*})?//gs;
$output_string =~s/(?:{\s*)?<!--{|}-->(?:\s*})?//gs;
}
$c->stash( provider => $contacts->first );
#use irka;
#irka::loglong(\$tt_string);
$c->stash( template => \$tt_string );
#irka::loglong(\$output_string);
$c->stash( template => \$output_string );
$c->log->debug("before_detach;\n");
$c->detach($c->view('SVG'));
}

@ -6,7 +6,7 @@ extends 'HTML::FormHandler';
use Moose::Util::TypeConstraints;
enum 'TemplateType' => [ qw/svg html/ ];#html
enum 'TemplateViewMode' => [ qw/raw parsed/ ];
enum 'TemplateSourceState' => [ qw/saved previewed/ ];
enum 'TemplateSourceState' => [ qw/saved previewed default/ ];
no Moose::Util::TypeConstraints;
has '+use_fields_for_input_without_param' => ( default => 1 );
@ -42,6 +42,20 @@ has_field 'tt_string' => (
required => 0,
);
has_field 'contract_id' => (
type => 'Text',
#default => \&
#apply => [ { check => \&validate_tt_string } ],
required => 1,
);
has_field 'tt_id' => (
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
};

@ -4,7 +4,7 @@ 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/};
my ($contract_id,$tt_sourcestate,$tt_type) = @params{qw/contract_id tt_sourcestate tt_type/};
my $result = '';
@ -19,12 +19,61 @@ 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 );
$result = $tt_record->get_column( 'base64_'.$tt_sourcestate );
}
if( $result && exists $params{result} ){
${$params{result}} = $result;
}
return $result;
return \$result;
}
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' });
}
});
}
1;

@ -110,7 +110,7 @@ function handleShowSvgParsedData(data, error) {
{
//alert('Congratulations. Your SVG string is back in the host page, do with it what you will\n\n' + data);
//alert(encodeURIComponent(data));//works in ie
background('[%- c.uri_for_action("/customer/calls_svg", [contract.id]) -%]'+'/svg','template='+encodeURIComponent(data),
background('[%- c.uri_for_action("/customer/calls_svg", [contract.id]) -%]'+'/svg/parsed/previewed','template='+encodeURIComponent(data),
function(httpResponse){
//alert(httpResponse);
var img = document.getElementById('svgpreview'); //new Image();
@ -131,11 +131,13 @@ function handleSaveSvgData(data, error) {
else
{
//alert('Congratulations. Your SVG string is back in the host page, do with it what you will\n\n' + data);
return data;
//alert(encodeURIComponent(data));//works in ie
background('[%- c.uri_for_action("/customer/calls_svg", [contract.id]) -%]'+'/svg/parsed/saved','template='+encodeURIComponent(data));
}
}
</script>
<button onclick="loadSvg('/svg/raw/default');">Load system default invoice template</button>
<button onclick="loadSvg('/svg/raw/saved');">Load saved invoice template</button>
<button onclick="loadSvg('/svg/raw/previewed');">Load previewed template</button>
<button onclick="showSvgParsed();">Refresh Preview</button>

@ -49,34 +49,41 @@ g {
<tspan x="160" id="calls_freetime">Free time</tspan>
<tspan x="190" id="calls_cost">Cost</tspan>
</text>
<!--{[%calls_height_start = 135-%]}-->
<!--{[% FOR call IN zonecalls_rs.all -%]}-->
<!--{[% 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') -%]}-->
<!--{[% calls_height_start + ( 10 * ( loop.count - 1 ) ) %]}-->
<!--{[% row_vertical_interval = 10 -%]}-->
<!--{[%MACRO datarow BLOCK -%]}-->
<text y="10" text-anchor="end" id="calls[%loop.count-%]" class="datarow">
<tspan x="5" id="calls_zone[%loop.count-%]" text-anchor="start"><!--{[% call.get_column('zone') %]}--><!--[%#-->Example zone<!--%]--></tspan>
<tspan x="95" id="calls_number[%loop.count-%]"><!--{[% call.get_column('number') %]}--><!--[%#-->0<!--%]--></tspan>
<tspan x="130" id="calls_duration[%loop.count-%]"><!--{[% call.get_column('duration')|format('%.3f') %]}--><!--[%#-->0.000<!--%]--></tspan>
<tspan x="160" id="calls_freetime[%loop.count-%]"><!--{[% call.get_column('free_time')|format('%d') %]}--><!--[%#-->0.0<!--%]--></tspan>
<tspan x="190" id="calls_cost[%loop.count-%]"><!--{[% ( call.get_column('cost') / 100 ) |format('%.2f') %]}--><!--[%#-->0.00<!--%]--></tspan>
<tspan x="5" id="calls_zone[%loop.count-%]" text-anchor="start"><!--{[% call.get_column('zone') %]}--><!--{[%#}-->Example zone<!--{%]}--></tspan>
<tspan x="95" id="calls_number[%loop.count-%]"><!--{[% call.get_column('number') %]}--><!--{[%#}-->0<!--{%]}--></tspan>
<tspan x="130" id="calls_duration[%loop.count-%]"><!--{[% call.get_column('duration')|format('%.3f') %]}--><!--{[%#}-->0.000<!--{%]}--></tspan>
<tspan x="160" id="calls_freetime[%loop.count-%]"><!--{[% call.get_column('free_time')|format('%d') %]}--><!--{[%#}-->0.0<!--{%]}--></tspan>
<tspan x="190" id="calls_cost[%loop.count-%]"><!--{[% ( call.get_column('cost') / 100 ) |format('%.2f') %]}--><!--{[%#}-->0.00<!--{%]}--></tspan>
</text>
<!--{[%rows=loop.count%]}-->
<!--{[%END -%]}-->
<script language="Javascript">
//var rows = $(".datarow").toArray();
var yStart = document.getElementById('calls1').getAttribute('y');
for(var i=1; i < [%rows + 1%]; i++){
var row = document.getElementById('calls'+i);
alert('i='+i+'; row='+row+'; y='+ ( i*10 + parseInt(yStart) ) );
if(row){
row.setAttribute( 'y', ( i*10 + parseInt(yStart) ) );
}
}
//rows=document.getElementsById;
</script>
<!--{[%END-%]}-->
<!--{[% BLOCK adjustrow -%]}-->
<!--{[% heights = datarow.match('(?s)(<text[^>]*\s+y\s?=.*?)(\d+)(.*)' ) -%]}-->
<!--{[% y = heights.1 + ( row_vertical_interval * ( rownumber - 1 ) ) %]}-->
<!--{[% heights.0 _ y _ heights.2 %]}-->
<!--{[%END -%]}-->
<!--{[% FOR call IN zonecalls_rs.all -%]}-->
<!--{[% 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') -%]}-->
<!--{[%PROCESS adjustrow rownumber = loop.count -%]}-->
<!--{[%END -%]}-->
<!--{[%MACRO totalrow BLOCK -%]}-->
<text y="20" text-anchor="end" id="calls_total" class="datarow">
<tspan x="5" id="calls_total_title" text-anchor="start">Total:</tspan>
<tspan x="95" id="calls_total_number"><!--{[% total_number %]}--><!--{[%#}-->0<!--{%]}--></tspan>
<tspan x="130" id="calls_total_duration"><!--{[% total_duration|format('%.3f') %]}--><!--{[%#}-->0.000<!--{%]}--></tspan>
<tspan x="160" id="calls_total_freetime"><!--{[% total_free_time|format('%d') %]}--><!--{[%#}-->0.0<!--{%]}--></tspan>
<tspan x="190" id="calls_total_cost"><!--{[% ( total_cost / 100 )|format('%.2f') %]}--><!--{[%#}-->0.00<!--{%]}--></tspan>
</text>
<!--{[%END-%]}-->
<!--{[%PROCESS adjustrow datarow=totalrow, rownumber = zonecalls_rs.all.size -%]}-->
</g>
</g>
<g id="bgpage">

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Loading…
Cancel
Save