From b2f21dd777eda684efb49a19453bfe9e86e2052c Mon Sep 17 00:00:00 2001 From: Irka Date: Thu, 17 Jul 2014 11:52:01 +0300 Subject: [PATCH] MT#7861 Use pixels as main unit to be in accordance with svg-edit. (cherry picked from commit bdd8562fb0ee0a98cb1296822fa1e211fa0d8c5f) --- lib/NGCP/Panel/Controller/InvoiceTemplate.pm | 15 +- lib/NGCP/Panel/Utils/InvoiceTemplate.pm | 69 +++--- share/static/js/libs/svg-edit/sanitize.js | 2 +- .../invoice/default/invoice_template_aux.tt | 18 +- .../invoice/default/invoice_template_svg.tt | 200 +++++++++--------- 5 files changed, 169 insertions(+), 135 deletions(-) diff --git a/lib/NGCP/Panel/Controller/InvoiceTemplate.pm b/lib/NGCP/Panel/Controller/InvoiceTemplate.pm index d68bd09c44..80ca26ad1f 100644 --- a/lib/NGCP/Panel/Controller/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Controller/InvoiceTemplate.pm @@ -320,8 +320,10 @@ sub set_content_ajax :Chained('base') :PathPart('editcontent/set/ajax') :Args(0) $c->detach($c->view('JSON')); } -sub preview_content :Chained('base') :PathPart('editcontent/preview') :Args(0) { +sub preview_content :Chained('base') :PathPart('editcontent/preview') :Args { my ($self, $c, @args) = @_; + my($out_type) = @args; + $out_type //= ''; my $tmpl = $c->stash->{tmpl}; my $svg = $tmpl->data; @@ -367,12 +369,17 @@ sub preview_content :Chained('base') :PathPart('editcontent/preview') :Args(0) { NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/invoicetemplate')); return; } - - $c->response->content_type('application/pdf'); - $c->response->body($pdf); + if($out_type eq 'svg'){ + $out = join('', @{NGCP::Panel::Utils::InvoiceTemplate::preprocess_svg_pdf($c, \$out)}); + $c->response->body($out); + }else{ + $c->response->content_type('application/pdf'); + $c->response->body($pdf); + } return; } + sub embed_image :Chained('/') :PathPart('invoicetemplate/embedimage') :Args(0) { my ($self, $c) = @_; diff --git a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm index 5675eaa1ab..bc64b106a5 100644 --- a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm @@ -6,39 +6,22 @@ use XML::XPath; use IPC::System::Simple qw/capturex/; use Template; + + sub svg_pdf { my ($c,$svg_ref,$pdf_ref) = @_; my $svg = $$svg_ref; my $dir = File::Temp->newdir(undef, CLEANUP => 1); my $tempdir = $dir->dirname; - my $pagenum = 1; - my @pagefiles; + my ($pagenum,@pagefiles) = (1); - # file consists of multiple svg tags (invald!), split them up: - my(@pages) = $svg=~/())/sig; - - foreach my $page(@pages) { + foreach my $page ( @{preprocess_svg_pdf($c,$svg_ref)}){ my $fh; my $pagefile = "$tempdir/$pagenum.svg"; push @pagefiles, $pagefile; - my $xp = XML::XPath->new($page); - my $g = $xp->find('//g[contains(@class,"firsty-") and contains(@class,"lasty")]'); - foreach my $node($g->get_nodelist) { - my $class = $node->getAttribute('class'); - my $firsty = $class; my $lasty = $class; - - $firsty =~ s/^.+firsty\-(\d+).*$/$1/; - $lasty =~ s/^.+lasty\-(\d+).*$/$1/; - if(length($firsty) && length($lasty)) { - process_child_nodes($node, $firsty, $lasty); - } - } - $page = ($xp->findnodes('/'))[0]->toString(); - - open($fh, ">", $pagefile); binmode($fh, ":utf8"); print $fh $page; @@ -52,16 +35,48 @@ sub svg_pdf { # so we need to scale it down by 0.8 to get a mediabox of 595,842 # when using 90dpi. # (it doesn't happen with inkscape, no idea what rsvg does) - my @cmd_args = (qw/-a -f pdf -z 0.8/, @pagefiles); + #-z 0.8 , --dpi-x 72 --dpi-y 72 + my @cmd_args = (qw/-a -f pdf/, @pagefiles); my $cmd = 'rsvg-convert'; my $cmd_full = $cmd.' '.join(' ', @cmd_args); $c and $c->log->debug( $cmd_full ); print $cmd_full.";\n"; + #`$cmd_full >./VMHost/data/ngcp-panel/invoice/pdf/pdf1.pdf`; $$pdf_ref = capturex([0], $cmd, @cmd_args); return 1; } +sub preprocess_svg_pdf { + my ($c,$svg_ref) = @_; + my $svg = $$svg_ref; + my (@pages_content); + + # file consists of multiple svg tags (invalid!), split them up: + my(@pages) = $svg=~/())/sig; + foreach my $page(@pages) { + my $xp = XML::XPath->new($page); + my $server_process_spec = ''; + if( my $spec_nodes = $xp->find('//@server-process-units') ){ + $server_process_spec = $spec_nodes->string_value(); + } + my $g = $xp->find('//g[contains(@class,"firsty-") and contains(@class,"lasty")]'); + foreach my $node($g->get_nodelist) { + my $class = $node->getAttribute('class'); + my $firsty = $class; my $lasty = $class; + + $firsty =~ s/^.+firsty\-(\d+).*$/$1/; + $lasty =~ s/^.+lasty\-(\d+).*$/$1/; + if(length($firsty) && length($lasty)) { + process_child_nodes($node, $firsty, $lasty, $server_process_spec); + } + } + $page = ($xp->findnodes('/'))[0]->toString(); + push @pages_content, $page; + } + return \@pages_content; +} + sub preprocess_svg { my($svg_ref) = @_; @@ -76,6 +91,7 @@ sub preprocess_svg { $node->removeAttribute('display'); } } + #we can't process images on server side due to possible access restrictions $$svg_ref = ($xp->findnodes('/'))[0]->toString(); $$svg_ref =~s/^|<\/root>$//; @@ -101,6 +117,7 @@ sub sanitize_svg { } sub get_tt { + #using of the common configuration was the reason for View::SVG my $tt = Template->new({ ENCODING => 'UTF-8', RELATIVE => 1, @@ -142,7 +159,7 @@ sub svg_content{ return $content; } sub process_child_nodes { - my ($node, $firsty, $y) = @_; + my ($node, $firsty, $y, $server_process_spec) = @_; for my $attr (qw/y y1 y2/) { my $a = $node->getAttribute($attr); if($a) { @@ -151,12 +168,14 @@ sub process_child_nodes { my $newy = $y + $delta; $node->removeAttribute($attr); - $node->appendAttribute(XML::XPath::Node::Attribute->new($attr, $newy."mm")); + $node->appendAttribute(XML::XPath::Node::Attribute->new($attr, + $newy.(($server_process_spec ne 'none')?'mm':'') + )); } } my @children = $node->getChildNodes(); foreach my $node(@children) { - process_child_nodes($node, $firsty, $y); + process_child_nodes($node, $firsty, $y, $server_process_spec); } } diff --git a/share/static/js/libs/svg-edit/sanitize.js b/share/static/js/libs/svg-edit/sanitize.js index f4e4feaac1..b8be464d3f 100644 --- a/share/static/js/libs/svg-edit/sanitize.js +++ b/share/static/js/libs/svg-edit/sanitize.js @@ -36,7 +36,7 @@ var svgWhiteList_ = { "feGaussianBlur": ["class", "color-interpolation-filters", "id", "requiredFeatures", "stdDeviation"], "filter": ["class", "color-interpolation-filters", "filterRes", "filterUnits", "height", "id", "primitiveUnits", "requiredFeatures", "width", "x", "xlink:href", "y"], "foreignObject": ["class", "font-size", "height", "id", "opacity", "requiredFeatures", "style", "transform", "width", "x", "y"], - "g": ["class", "clip-path", "clip-rule", "id", "display", "fill", "fill-opacity", "fill-rule", "filter", "mask", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform", "font-family", "font-size", "font-style", "font-weight", "text-anchor", "rows", "zone-rows", "call-rows", "rows-interval", "zone-rows-interval", "call-rows-interval"], + "g": ["class", "clip-path", "clip-rule", "id", "display", "fill", "fill-opacity", "fill-rule", "filter", "mask", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform", "font-family", "font-size", "font-style", "font-weight", "text-anchor", "rows", "zone-rows", "call-rows", "rows-interval", "zone-rows-interval", "call-rows-interval","server-process-units"], "image": ["class", "clip-path", "clip-rule", "filter", "height", "id", "mask", "opacity", "requiredFeatures", "style", "systemLanguage", "transform", "width", "x", "xlink:href", "xlink:title", "y"], "line": ["class", "clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "id", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform", "x1", "x2", "y1", "y2"], "linearGradient": ["class", "id", "gradientTransform", "gradientUnits", "requiredFeatures", "spreadMethod", "systemLanguage", "x1", "x2", "xlink:href", "y1", "y2"], diff --git a/share/templates/invoice/default/invoice_template_aux.tt b/share/templates/invoice/default/invoice_template_aux.tt index 93f1d72a69..dd26806457 100644 --- a/share/templates/invoice/default/invoice_template_aux.tt +++ b/share/templates/invoice/default/invoice_template_aux.tt @@ -16,10 +16,10 @@ MACRO svgopen BLOCK; aux.page = aux.page + 1; - ''; + ''; draw_background; IF open_g; - ''; + ''; END; END; @@ -54,7 +54,7 @@ x = x + f.dx; format_field(field=f, val=zone.${f.name}); val = aux.val; - ''; + ''; val; ''; END; @@ -67,7 +67,15 @@ END; aux.lasty = y; END; - + MACRO apply_units(item) BLOCK; + IF server_process_units == 'none'; + ''; + ELSIF item == 'fontsize' ; + 'pt'; + ELSIF item == 'position'; + 'mm'; + END; + END; MACRO calllist BLOCK; fontfamily = fontfamily || 'Arial'; fontsize = fontsize || 8; @@ -87,7 +95,7 @@ l = f.masklen > val.length ? val.length : f.masklen; val = val.substr(l - 1, val.length - 1, f.mask); END; - ''; + ''; val; ''; END; diff --git a/share/templates/invoice/default/invoice_template_svg.tt b/share/templates/invoice/default/invoice_template_svg.tt index 42298af01c..143e769f93 100644 --- a/share/templates/invoice/default/invoice_template_svg.tt +++ b/share/templates/invoice/default/invoice_template_svg.tt @@ -12,134 +12,134 @@ cur = billprof.currency; p_start = date_format(thedate=invoice.period_start, format='%Y-%m-%d'); p_end = date_format(thedate=invoice.period_end, format='%Y-%m-%d'); - + server_process_units = 'none'; -%] }--> - + - + Background - [% rescontact.company %] - [% rescontact.street %] - [% rescontact.postcode %] [% custcontact.city %] - [% rescontact.country %] + [% rescontact.company %] + [% rescontact.street %] + [% rescontact.postcode %] [% custcontact.city %] + [% rescontact.country %] - Company Reg.Nr.: [% rescontact.comregnum %] - VAT.Nr.: [% rescontact.vatnum %] - IBAN: [% rescontact.iban %] - BIC: [% rescontact.bic %] - Page [% aux.page %] + Company Reg.Nr.: [% rescontact.comregnum %] + VAT.Nr.: [% rescontact.vatnum %] + IBAN: [% rescontact.iban %] + BIC: [% rescontact.bic %] + Page [% aux.page %] - + - + Summary - [% custcontact.firstname %] [% custcontact.lastname %] - [% custcontact.street %] - [% custcontact.postcode %] [% custcontact.city %] - [% custcontact.country %] - - Invoice Nr. - [% invoice.serial %] - Customer Nr. - [% customer.external_id %] - Invoice Period - [% p_start %] - [% p_end %] - Date - [% date_now(format='%Y-%m-%d') %] - - Your Monthly Statement - - Dear Customer, - For our services provided in the period of [% p_start %] to [% p_end %], we invoice the following items: - - - Recurring Fees - - Name - Quantity - Unit Price - Total Price in [% cur %] - - [% billprof.name %] - 1 - [% fixfee %] - [% fixfee %] - - Total - [% fixfee %] - - - - - Call Summary - - Zone - Quantity - Usage - Total Price in [% cur %] - - - - - - - - Total - [% zonefee %] - + [% custcontact.firstname %] [% custcontact.lastname %] + [% custcontact.street %] + [% custcontact.postcode %] [% custcontact.city %] + [% custcontact.country %] + + Invoice Nr. + [% invoice.serial %] + Customer Nr. + [% customer.external_id %] + Invoice Period + [% p_start %] - [% p_end %] + Date + [% date_now(format='%Y-%m-%d') %] + + Your Monthly Statement + + Dear Customer, + For our services provided in the period of [% p_start %] to [% p_end %], we invoice the following items: + + + Recurring Fees + + Name + Quantity + Unit Price + Total Price in [% cur %] + + [% billprof.name %] + 1 + [% fixfee %] + [% fixfee %] + + Total + [% fixfee %] + + + + + Call Summary + + Zone + Quantity + Usage + Total Price in [% cur %] + + + + + + + + Total + [% zonefee %] + - - - - - - - Summary - in [% cur %] - - Total Summary - [% netfee %] - VAT ([% customer.vat_rate %]%) - [% vatfee %] - - Amount Due - [% allfee %] - - - The amount is automatically charged via SEPA within 30 days using Mandate ID MID12345 and Creditor ID CID12345 - from your account with IBAN [% rescontact.iban %] and BIC [% rescontact.bic %]. - With best regards, - Your [% rescontact.company %] Service Team + + + + + + + Summary + in [% cur %] + + Total Summary + [% netfee %] + VAT ([% customer.vat_rate %]%) + [% vatfee %] + + Amount Due + [% allfee %] + + + The amount is automatically charged via SEPA within 30 days using Mandate ID MID12345 and Creditor ID CID12345 + from your account with IBAN [% rescontact.iban %] and BIC [% rescontact.bic %]. + With best regards, + Your [% rescontact.company %] Service Team - + CallList - Call Details - - Start Time - Duration - Destination - Zone - Total Amount in [% cur %] + Call Details + + Start Time + Duration + Destination + Zone + Total Amount in [% cur %] - + - +