From 0d39395842fc3ac54a28b3b4e6c1a5e06b05a49b Mon Sep 17 00:00:00 2001 From: Irina Peshinskaya Date: Sun, 27 Apr 2014 23:57:04 +0300 Subject: [PATCH] MT#5879 Script to generate invoices from templates. --- lib/NGCP/Panel/Controller/Invoice.pm | 60 +----- lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm | 163 ++++++++------ lib/NGCP/Panel/Utils/Contract.pm | 45 ++-- lib/NGCP/Panel/Utils/InvoiceTemplate.pm | 68 ++++++ lib/NGCP/Panel/View/SVG.pm | 17 +- .../templates/invoice/invoice_template_aux.tt | 8 +- .../invoice/invoice_template_lorem.tt | 6 + .../templates/invoice/invoice_template_svg.tt | 2 +- share/tools/generate_invoices.pl | 200 ++++++++++++++++++ 9 files changed, 418 insertions(+), 151 deletions(-) create mode 100644 share/tools/generate_invoices.pl diff --git a/lib/NGCP/Panel/Controller/Invoice.pm b/lib/NGCP/Panel/Controller/Invoice.pm index 500721231e..4cd51168d2 100644 --- a/lib/NGCP/Panel/Controller/Invoice.pm +++ b/lib/NGCP/Panel/Controller/Invoice.pm @@ -489,6 +489,9 @@ sub template_view :Chained('template_base') :PathPart('view') :Args { 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); + #use irka; + #use Data::Dumper; + #irka::loglong(Dumper(\%tokens_valid)); foreach( $tt_string_sanitized=~/$tokens_re/sg ){ my $token_shape=$_; $token_shape=~s/$token_shape_re//sg; @@ -558,8 +561,7 @@ sub template_view :Chained('template_base') :PathPart('view') :Args { #even better - to template filters #also to model $out->{tt_string_prepared}=$out->{tt_string_stored}=$out->{tt_string}; - $out->{tt_string_prepared}=~s/(?:{\s*)?(?:\s*})?//gs; - $out->{tt_string_prepared}=~s/()($2.*?>))/$1$3/gs; + NGCP::Panel::Utils::InvoiceTemplate::preprocessInvoiceTemplateSvg($in,\$out->{tt_string_prepared}); } if( ($in->{tt_output_type} eq 'svg') || ( $in->{tt_output_type} eq 'html') ){ @@ -591,59 +593,7 @@ sub template_view :Chained('template_base') :PathPart('view') :Args { #method $c->response->content_type('application/pdf'); my $svg = $c->view('SVG')->getTemplateProcessed($c,\$out->{tt_string_prepared}, $c->stash ); - my(@pages) = $svg=~/())/sig; - - #$c->log->debug($svg); - my ($tempdirbase,$tempdir ); - use File::Temp qw/tempfile tempdir/; - #my($fh, $tempfilename) = tempfile(); - $tempdirbase = join('/',File::Spec->tmpdir,@$in{qw/provider_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++; - } - - 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_pdf} = ; - close B; - } + NGCP::Panel::Utils::InvoiceTemplate::convertSvg2Pdf($c,\$svg,$in,$out); $c->response->body($out->{tt_string_pdf}); return; #$out->{tt_string} = `cat $filename `; diff --git a/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm b/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm index b38604446a..f4c66dba3c 100644 --- a/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Model/DB/InvoiceTemplate.pm @@ -231,81 +231,98 @@ sub getInvoiceClientContactInfo{ sub getInvoiceProviderClients{ my $self = shift; my (%params) = @_; - my ($provider_id) = @params{qw/provider_id/}; - #$schema->resultset('contracts') -# my $mapping_rs = $schema->resultset('billing_mappings'); -# my $rs = $schema->resultset('contracts') -# ->search({ -# 'me.status' => { '!=' => 'terminated' }, -# 'billing_mappings.id' => { -# '=' => $mapping_rs->search({ -# contract_id => { -ident => 'me.id' }, -# start_date => [ -or => -# { '<=' => NGCP::Panel::Utils::DateTime::current_local }, -# { -is => undef }, -# ], -# end_date => [ -or => -# { '>=' => NGCP::Panel::Utils::DateTime::current_local }, -# { -is => undef }, -# ], -# },{ -# alias => 'bilmap', -# rows => 1, -# order_by => {-desc => ['bilmap.start_date', 'bilmap.id']}, -# })->get_column('id')->as_query, -# }, -# },{ -# 'join' => 'billing_mappings', -# '+select' => [ -# 'billing_mappings.id', -# 'billing_mappings.start_date', -# 'billing_mappings.product_id', -# ], -# '+as' => [ -# 'billing_mapping_id', -# 'billing_mapping_start_date', -# 'product_id', -# ], -# alias => 'me', -# }); -# -# return $rs; - - - #very optimistic programming style - - return NGCP::Panel::Utils::Contract::get_contract_rs( - schema => $self->schema, - )->search_rs({ - 'contact.reseller_id' => $provider_id, - },{ - join => 'contact', + my ($provider_contact_id,$stime,$etime) = @params{qw/provider_contact_id stime etime/}; + $stime ||= NGCP::Panel::Utils::DateTime::current_local()->truncate( to => 'month' ); + $etime ||= $stime->clone->add( months => 1); + $self->schema->resultset('contacts')->search_rs({ + '-and' => + [ + 'reseller_id' => $provider_contact_id, #$client_contract_id - contract of the client + 'id' => { '!=' => $provider_contact_id }, + ], + '-exists' => $self->schema->resultset('billing_mappings')->search({ + 'contract.contact_id' => \' = contacts.id', + 'product.class' => [ "sipaccount", "pbxaccount" ], + '-and' => [ + 'start_date' => [ -or => + { '<=' => $etime->epoch }, + { -is => undef }, + ], + 'end_date' => [ -or => + { '>=' => $stime->epoch }, + { -is => undef }, + ], + ] + },{ + alias => 'billing_mappings_top', + join => ['product','contract'], + })->as_query }); } sub get_contract_calls_rs{ my $self = shift; my %params = @_; - (my($c,$provider_id,$client_id,$stime,$etime)) = @params{qw/c provider_id client_id stime etime/}; + (my($c,$provider_contact_id,$client_contact_id,$stime,$etime)) = @params{qw/c provider_id client_id stime etime/};#I think it may be a record (very long var name) my $source_account_id_condition; - if(!$client_id){ - $source_account_id_condition = { 'in' => $self->getInvoiceProviderClients(%params)->search_rs({},{ - 'select' => 'me.id', - })->as_query() - #$self->schema('contracts')->search_rs({},{ - # 'select' => 'me.id', - # 'join' => 'contact', - #})->as_query() - }; + $stime ||= NGCP::Panel::Utils::DateTime::current_local()->truncate( to => 'month' ); + $etime ||= $stime->clone->add( months => 1 ); + if(!$client_contract_id){ + #$source_account_id_condition = { + # 'in' => $self->getInvoiceProviderClients(%params)->search_rs({},{ + # 'select' => 'me.id', + # })->as_query() + #}; + $source_account_id_condition = { 'in' => $self->getInvoiceProviderClients( + provider_contact_id => $provider_contact_id, + stime => $stime, + etime => $etime, + )->search_rs(undef,{ + 'select' => 'me.id', + })->as_query }; }else{ - $source_account_id_condition = $client_id; + $source_account_id_condition = $client_contract_id; } - $sql = ' - select cdr.* from accounting.cdr + #I find that sql is more compact and clear + $sql_of_all_provider_contract_id_clients_contact_ids_sip_pbx = [' + select contacts.* + from contacts + where + contacts.reseller_id=? + and exists (select * + from billing_mappings + inner join contracts on contracts.id=billing_mappings.contract_id + inner join products on billing_mappings.product_id=products.id and products.class in("sipaccount","pbxaccount") + where contracts.contact_id=contacts.id + and (start_date <= ? OR start_date IS NULL) + and (end_date >= ? OR end_date IS NULL) + )',$provider_contract_id, $etime->epoch, $stime->epoch]; + $sql_of_all_client_contract_id_calls = ' + select cdr.* + from accounting.cdr inner join contracts on cdr.source_account_id=contracts.id and contracts.status != "terminated" - inner join contacts on contracts.contact_id=contacts.id - and contacts.reseller_id=1 and contacts.reseller_id!=contacts.id + where + cdr.source_user_id != 0 + and cdr.call_status="ok" + and exists (select * + from billing_mappings + inner join products on billing_mappings.product_id=products.id and products.class in("sipaccount","pbxaccount") + where contracts.id=billing_mappings.contract_id + and (billing_mappings.start_date >= now() OR start_date IS NULL) + and (billing_mappings.end_date <= now() OR end_date IS NULL) + ) + and contracts.contact_id=22 + order by cdr.start_time + '; + + $sql_of_all_provider_contact_id_clients_calls = ' + select cdr.* + from contacts + inner join contracts on contracts.contact_id=contacts.id + and contacts.reseller_id=2 and contacts.reseller_id!=contacts.id + inner join accounting.cdr on cdr.source_account_id=contracts.id + and contracts.status != "terminated" where cdr.source_user_id != 0 and cdr.call_status="ok" @@ -317,20 +334,28 @@ sub get_contract_calls_rs{ and (billing_mappings.end_date <= now() OR end_date IS NULL) ) order by cdr.start_time - '; + '; my $calls_rs = $self->schema->resultset('cdr')->search( { # source_user_id => { 'in' => [ map {$_->uuid} @{$contract->{subscriber}} ] }, 'call_status' => 'ok', 'source_user_id' => { '!=' => '0' }, - 'contact.id' => { '!=' => $provider_id }, + 'contact.id' => { '!=' => $provider_contact_id }, '-and' => [ - #'contact.reseller_id' => $provider_id, + #'contact.reseller_id' => $provider_id, #$client_contract_id - contract of the client 'contact.reseller_id' => { '!=' => undef }, ], 'source_account.status' => { '!=' => 'terminated'}, '-exists' => $self->schema->resultset('billing_mappings')->search({ - 'contract_id' => \'= source_account.id', + 'contract_id' => \'= source_account.id', 'product.class' => [ "sipaccount", "pbxaccount" ], + 'start_date' => [ -or => + { '<=' => 'cdr.start_time' }, + { -is => undef }, + ], + 'end_date' => [ -or => + { '>=' => 'cdr.start_time' }, + { -is => undef }, + ], },{ alias => 'billing_mappings_top', join => 'product', @@ -400,7 +425,7 @@ sub get_contract_zonesfees_rs { #alias => join => 'source_customer_billing_zones_history', group_by => 'source_customer_billing_zones_history.zone', - #order_by => 'source_customer_billing_zones_history.zone', + order_by => 'source_customer_billing_zones_history.zone', } ); return $zonecalls_rs; diff --git a/lib/NGCP/Panel/Utils/Contract.pm b/lib/NGCP/Panel/Utils/Contract.pm index 16c88c1ab9..914f651e30 100644 --- a/lib/NGCP/Panel/Utils/Contract.pm +++ b/lib/NGCP/Panel/Utils/Contract.pm @@ -13,8 +13,6 @@ sub create_contract_balance { my $contract = $params{contract}; my $profile = $params{profile}; - my ($cash_balance, $cash_balance_interval, - $free_time_balance, $free_time_balance_interval) = (0,0,0,0); # first, calculate start and end time of current billing profile # (we assume billing interval of 1 month) @@ -22,20 +20,13 @@ sub create_contract_balance { my $etime = $stime->clone->add(months => 1)->subtract(seconds => 1); # calculate free_time/cash ratio - my $free_time = $profile->interval_free_time || 0; - my $free_cash = $profile->interval_free_cash || 0; - if($free_time or $free_cash) { - $etime->add(seconds => 1); - my $ctime = NGCP::Panel::Utils::DateTime::current_local->truncate(to => 'day'); - my $ratio = ($etime->epoch - $ctime->epoch) / ($etime->epoch - $stime->epoch); - - $cash_balance = sprintf("%.4f", $free_cash * $ratio); - $cash_balance_interval = 0; - - $free_time_balance = sprintf("%.0f", $free_time * $ratio); - $free_time_balance_interval = 0; - $etime->subtract(seconds => 1); - } + my ($cash_balance, $cash_balance_interval, + $free_time_balance, $free_time_balance_interval) = get_contract_balance_values( + interval_free_time => ( $profile->interval_free_time || 0 ), + interval_free_cash => ( $profile->interval_free_cash || 0 ), + stime => $stime, + etime => $etime, + ); try { my $schema = $c->model('DB'); @@ -60,7 +51,27 @@ sub create_contract_balance { }; return; } - +sub get_contract_balance_values{ + my %params = @_; + my($free_time,$free_cash,$stime,$etime) = @params{qw/interval_free_time interval_free_cash stime etime/}; + my ($cash_balance, $cash_balance_interval, + $free_time_balance, $free_time_balance_interval) = (0,0,0,0); + if($free_time or $free_cash) { + $etime->add(seconds => 1); + my $ctime = NGCP::Panel::Utils::DateTime::current_local->truncate(to => 'day'); + if( ( $ctime->epoch >= $stime->epoch ) && ( $ctime->epoch <= $stime->epoch ) ){ + my $ratio = ($etime->epoch - $ctime->epoch) / ($etime->epoch - $stime->epoch); + + $cash_balance = sprintf("%.4f", $free_cash * $ratio); + $cash_balance_interval = 0; + + $free_time_balance = sprintf("%.0f", $free_time * $ratio); + $free_time_balance_interval = 0; + } + $etime->subtract(seconds => 1); + } + return ($cash_balance,$cash_balance_interval,$free_time_balance,$free_time_balance_interval); +} sub recursively_lock_contract { my %params = @_; diff --git a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm index 9ec8b32d28..539627aefd 100644 --- a/lib/NGCP/Panel/Utils/InvoiceTemplate.pm +++ b/lib/NGCP/Panel/Utils/InvoiceTemplate.pm @@ -5,6 +5,8 @@ use strict; use warnings; #use Moose; use Sipwise::Base; +use File::Temp qw/tempfile tempdir/; +use File::Path qw/mkpath/; sub getDefaultInvoiceTemplate{ my (%in) = @_; @@ -18,5 +20,71 @@ sub getDefaultInvoiceTemplate{ } return \$result; } +sub convertSvg2Pdf{ + my($c,$svg_ref,$in,$out) = @_; + my $svg = $$svg_ref; + my(@pages) = $svg=~/())/sig; + + #$c->log->debug($svg); + my ($tempdirbase,$tempdir ); + #my($fh, $tempfilename) = tempfile(); + $tempdirbase = join('/',File::Spec->tmpdir,@$in{qw/provider_id tt_type tt_sourcestate/}, $out->{tt_id}); + ! -e $tempdirbase and mkpath( $tempdirbase, 0, 0777 ); + $tempdir = tempdir( DIR => $tempdirbase , CLEANUP => 1 ); + $c and $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++; + } + + my $cmd = "rsvg-convert -f pdf ".join(" ", @pagefiles); + $c and $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_pdf} = ; + close B; + } +} +sub preprocessInvoiceTemplateSvg{ + my($in,$svg_ref) = @_; + no warnings 'uninitialized'; + #print "1.\n\n\n\n\nsvg=".$out->{tt_string_prepared}.";"; + $$svg_ref=~s/(?:{\s*)?(?:\s*})?//gs; + $$svg_ref=~s/()($2.*?>))/$1$3/gs; + if($in->{no_fake_data}){ + $$svg_ref=~s/\[%[^\[\%]+lorem.*?%\]//gs; + } + #print "\n\n2.\n\n\n\nsvg=".$out->{tt_string_prepared}.";"; +} 1; \ No newline at end of file diff --git a/lib/NGCP/Panel/View/SVG.pm b/lib/NGCP/Panel/View/SVG.pm index df63a5cc2e..164fa9e6a3 100644 --- a/lib/NGCP/Panel/View/SVG.pm +++ b/lib/NGCP/Panel/View/SVG.pm @@ -23,8 +23,7 @@ sub translate_form { NGCP::Panel::Utils::I18N->translate_form(@_); } -sub process -{ +sub process{ my ( $self, $c ) = @_; #$c->res->content_type("image/svg+xml"); $self->{template}->context->define_vmethod( @@ -54,10 +53,10 @@ sub process sub getTemplate{ my ( $self, $c, $template ) = @_; if(defined $template){ - $c->log->debug("getTemplate: template=$template;"); + $c and $c->log->debug("getTemplate: template=$template;"); } - $template ||= ( $c->stash->{template} || $c->action . $self->config->{TEMPLATE_EXTENSION} ); - $c->log->debug("getTemplate: template=$template;"); + $c and $template ||= ( $c->stash->{template} || $c->action . $self->config->{TEMPLATE_EXTENSION} ); + $c and $c->log->debug("getTemplate: template=$template;"); return $template; } #method is necessary to apply APP specific template configurations, e.g. path, tt file extensions etc @@ -69,6 +68,14 @@ sub getTemplateContent{ } sub getTemplateProcessed{ my ( $self, $c, $template, $stash ) = @_; + $self->{template}->context->define_vmethod( + hash => get_column => sub { + my($item,$col) = @_; + if('HASH' eq ref $item){ + return $item->{$col}; + } + } + ); #$c->log->debug("getTemplateProcessed: template=$template;"); #my $result = $self->{template}->context->process($template, $stash); #$c->log->debug("getTemplateProcessed: result=$result;"); diff --git a/share/templates/invoice/invoice_template_aux.tt b/share/templates/invoice/invoice_template_aux.tt index 3f1b76c0ee..e3f8d4f6ae 100644 --- a/share/templates/invoice/invoice_template_aux.tt +++ b/share/templates/invoice/invoice_template_aux.tt @@ -123,7 +123,7 @@ [% matches = page.match( page_interval_re ) -%] [%interval = matches.0 || matches.1 %] - [%interval = Math.int(rows)%] + [%interval = Math.int(interval)%] [%interval%] [%END -%] @@ -137,7 +137,7 @@ [% midzonerows = get_page_rows_number('zonepage','svg') %] [% titlezoneinterval = get_page_interval('titlepage','svg','zone') %] [% midzoneinterval = get_page_interval('zonepage','svg') %] - [% midzonerows = get_page_rows_number('zonepage','svg') %] + [% midzonerows = Math.int(get_page_rows_number('zonepage','svg')) %] [% midzonerows = ( midzonerows < 1 ) ? 30 : midzonerows %] [% allmidzonepages = ( (allzonerowsnumber - titlezonerows) / midzonerows )|format('%d') %] @@ -148,7 +148,7 @@ [% allcallrowsnumber = invoice_details_calls.size() %] [% titlecallrows = get_page_rows_number('titlepage','svg','call') %] - [% midcallrows = get_page_rows_number('callpage','svg') %] + [% midcallrows = Math.int(get_page_rows_number('callpage','svg')) %] [% midcallrows = ( midcallrows < 1 ) ? 30 : midcallrows %] [% titlecallinterval = get_page_interval('titlepage','svg', 'call') %] [% midcallinterval = get_page_interval('callpage','svg') %] @@ -174,7 +174,7 @@ [% bgpage(pagenum) -%] [% document_footer()%] [%END-%] - [%IF ( pagetype == 'zone' || pagetype=='all' ) && allmidzonerows %] + [%IF ( pagetype == 'zone' || pagetype=='all' ) && allzonerowsnumber %] [% pages = pagenum_in ? [ pagenum_in ] : [ 1 .. allmidzonepages ] %] [%FOREACH pagenum IN pages %] [% pagerowsstart = titlezonerows + midzonerows * ( pagenum - 1 )%] diff --git a/share/templates/invoice/invoice_template_lorem.tt b/share/templates/invoice/invoice_template_lorem.tt index 276c29fa1b..92b370cdce 100644 --- a/share/templates/invoice/invoice_template_lorem.tt +++ b/share/templates/invoice/invoice_template_lorem.tt @@ -21,6 +21,7 @@ DEFAULT invoice.serviceallowance='69'; DEFAULT invoice.voice_termination_fees='10'; END; +IF !provider; DEFAULT provider.bic='ABCDEFG1234'; DEFAULT provider.city='Provider City'; DEFAULT provider.company='Provider Gmbh.'; @@ -35,6 +36,11 @@ DEFAULT provider.postcode='65104'; DEFAULT provider.street='Provider Street'; DEFAULT provider.url='http://www.provider.com/'; DEFAULT provider.vat='UATAA1234AA1234'; +ELSE; + FOREACH i in ['bic','city','company','country','email','fax','fn','iban','mobile','phone','postcode','street','url','vat']; + provider.${i} = provider.get_column($i); + END; +END; IF !client.id; DEFAULT client.bic='ABCDEFG1234'; diff --git a/share/templates/invoice/invoice_template_svg.tt b/share/templates/invoice/invoice_template_svg.tt index 1330bc8a90..84eb791245 100644 --- a/share/templates/invoice/invoice_template_svg.tt +++ b/share/templates/invoice/invoice_template_svg.tt @@ -166,7 +166,7 @@ g, text, tspan { 1 - 0001-01-31 23:59:59 + 0001-01-31 23:59:59 0.000 +00000000**** call diff --git a/share/tools/generate_invoices.pl b/share/tools/generate_invoices.pl new file mode 100644 index 0000000000..1a3031858f --- /dev/null +++ b/share/tools/generate_invoices.pl @@ -0,0 +1,200 @@ +#!/usr/bin/perl -w +use lib '/media/sf_/usr/share/VMHost/ngcp-panel/lib'; +use strict; + +use DBI; +use Data::Dumper; +use NGCP::Panel::Utils::DateTime; +use DateTime::TimeZone; +use Net::Domain qw(hostfqdn); +use LWP::UserAgent; +use NGCP::Panel::Utils::Contract; +use NGCP::Panel::Utils::InvoiceTemplate; +use NGCP::Panel; +use NGCP::Panel::View::SVG; +use Test::MockObject; +use Sipwise::Base; +my $debug = 1; + +my ($dbuser, $dbpass); +my $mfile = '/etc/mysql/sipwise.cnf'; +if(-f $mfile) { + open my $fh, "<", $mfile + or die "failed to open '$mfile': $!\n"; + $_ = <$fh>; chomp; + s/^SIPWISE_DB_PASSWORD='(.+)'$/$1/; + $dbuser = 'sipwise'; $dbpass = $_; +} else { + $dbuser = 'root'; + $dbpass = ''; +} +print "using user '$dbuser' with pass '$dbpass'\n" + if($debug); + +#my ($ua, $req, $res); +#use LWP::UserAgent; +#use HTTP::Request; +#$ua = LWP::UserAgent->new; +#$req = HTTP::Request->new('OPTIONS', 'https://192.168.56.7:1444/invoice/3/template'); +##$res = $ua->request($req); +#my $controller = NGCP::Panel->controller('Invoice'); +#my $c = NGCP::Panel->prepare($ua); +##$c->request->param->{tt_id} = 126; +##$c->request->method( 'POST' ); +##$c->request->uri( 'https://192.168.56.7:1444/invoice/3/template'); +#die(); +my $dbh = DBI->connect('dbi:mysql:billing;host=localhost', $dbuser, $dbpass) + or die "failed to connect to billing DB\n"; +#$dbh->trace(SQL); + +#copypasted from tests +#my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443'); +#my $valid_ssl_client_cert = $ENV{API_SSL_CLIENT_CERT} || +# "/etc/ssl/ngcp/api/NGCP-API-client-certificate.pem"; +#my $valid_ssl_client_key = $ENV{API_SSL_CLIENT_KEY} || +# $valid_ssl_client_cert; +#my $ssl_ca_cert = $ENV{API_SSL_CA_CERT} || "/etc/ssl/ngcp/api/ca-cert.pem"; +#$ua->ssl_opts( +# SSL_cert_file => $valid_ssl_client_cert, +# SSL_key_file => $valid_ssl_client_key, +# SSL_ca_file => $ssl_ca_cert, +#); + + +my $stime = NGCP::Panel::Utils::DateTime::current_local()->truncate( to => 'month' ); +my $etime_plus = $stime->clone->add( months => 1 ); +my $etime = $etime_plus->clone->subtract( seconds => 1 ); +my $c_mock = Test::MockObject->new(); +$c_mock->set_false(qw/debug/); +my $view = NGCP::Panel::View::SVG->new($c_mock,{}); +my $svg_default = $view->getTemplateContent(undef,'invoice/invoice_template_svg.tt'); +NGCP::Panel::Utils::InvoiceTemplate::preprocessInvoiceTemplateSvg({no_fake_data => 1},\$svg_default); +#print $etime->ymd; + +foreach my $provider_contract( @{$dbh->selectall_arrayref('select contracts.*,resellers.id as reseller_core_id from resellers inner join contracts on resellers.contract_id=contracts.id where resellers.status != "terminated"', { Slice => {} } ) } ){ + my $provider_contact = $dbh->selectrow_hashref('select * from contacts where id=?', undef, $provider_contract->{contact_id} ); + foreach my $client_contact (@{ $dbh->selectall_arrayref('select contacts.* from contacts where reseller_id = ?', { Slice => {} }, $provider_contract->{reseller_core_id} ) } ){ + my $client_contract = $dbh->selectrow_hashref('select contracts.* from contracts where contracts.contact_id=? ', undef, $client_contact->{id} ); + if( !(my $billing_profile = $dbh->selectrow_hashref('select billing_profiles.* + from billing_mappings + inner join billing_profiles on billing_mappings.billing_profile_id=billing_profiles.id + inner join contracts on contracts.id=billing_mappings.contract_id + inner join products on billing_mappings.product_id=products.id and products.class in("sipaccount","pbxaccount") + where + contracts.status != "terminated" + and contracts.contact_id=? + and (billing_mappings.start_date <= ? OR billing_mappings.start_date IS NULL) + and (billing_mappings.end_date >= ? OR billing_mappings.end_date IS NULL)' +, undef, $client_contract->{id}, $etime->epoch, $stime->epoch +) ) ){ + my $invoice; + if(!(my $contract_balance = $dbh->selectrow_hashref('select * from contract_balances where contract_id=? and date(start)=? and date(end)=?',undef,$client_contract->{id},$stime->ymd,$etime->ymd))){ + + + @$contract_balance{qw/cash_balance cash_balance_interval free_time_balance free_time_balance_interval/} = NGCP::Panel::Utils::Contract::get_contract_balance_values( + %$billing_profile, + stime => $stime, + etime => $etime->datetime, + ); + + $dbh->do('insert into contract_balances(contract_id,cash_balance,cash_balance_interval,free_time_balance,free_time_balance_interval,start,end,invoice_id)values(?,?,?,?,?,?,?,?)',undef,$client_contract->{id},@$contract_balance{qw/cash_balance cash_balance_interval free_time_balance free_time_balance_interval/},$stime->datetime, $etime->datetime,undef ); + $invoice = create_invoice($client_contract->{id},$stime, $etime); + $contract_balance = $dbh->selectrow_hashref('select * from contract_balances where id=?',undef,$dbh->last_insert_id(undef,'billing','contract_balances','id')); + }else{ + $invoice = $dbh->selectrow_hashref('select * from invoices where id=?',undef,$contract_balance->{invoice_id} ); + $invoice = create_invoice($client_contract->{id},$stime, $etime); + } + my $invoice_details_calls = $dbh->selectall_arrayref('select cdr.*,bzh.zone, bzh.detail as zone_detail + from accounting.cdr + LEFT JOIN billing.billing_zones_history bzh ON bzh.id = cdr.source_customer_billing_zone_id + where + cdr.source_user_id != 0 + and cdr.call_status="ok" +-- and cdr.source_account_id=? +-- and cdr.start_time >= ? +-- and cdr.start_time <= ? + order by cdr.start_time + limit 5' + , { Slice => {} } +#, $client_contract->{id},$stime->epoch,$etime->epoch +); + my $invoice_details_zones = $dbh->selectall_arrayref('select SUM(cdr.source_customer_cost) AS cost, COUNT(*) AS number, SUM(cdr.duration) AS duration,sum(cdr.source_customer_free_time) as free_time, bzh.zone + from accounting.cdr + LEFT JOIN billing.billing_zones_history bzh ON bzh.id = cdr.source_customer_billing_zone_id + where + cdr.source_user_id != 0 + and cdr.call_status="ok" +-- and cdr.source_account_id=? +-- and cdr.start_time >= ? +-- and cdr.start_time <= ? + group by bzh.zone + order by bzh.zone' + , {Slice => {} } +#, $client_contract->{id},$stime->epoch,$etime->epoch + + ); + my $i = 1; + $invoice_details_calls = [map{[$i++,$_]} (@$invoice_details_calls) x 1]; + $i = 1; + $invoice_details_zones = [map{[$i++,$_]} (@$invoice_details_zones) x 1]; + + #my $controller = NGCP::Panel->controller('Invoice'); + #my $c = NGCP::Panel->prepare(); + # Monkey with $c to set up a fake context (set req->uri, or params) + my ($in, $out); + #tt_id used only as part in temporary directory + $in = { + no_fake_data => 1, + provider_id => $provider_contract->{reseller_core_id}, + tt_type => 'svg', + tt_sourcestate => 'saved', + tt_id => 1, + }; + $out = { + tt_id => 1, + }; + my $stash = { + provider => $provider_contact, + client => $client_contact, + invoice => $invoice, + invoice_details_zones => $invoice_details_zones, + invoice_details_calls => $invoice_details_calls, + }; + my $svg = $dbh->selectrow_array('select base64_saved from invoice_templates where is_active = 1 and type = "svg" and reseller_id=?',undef,$provider_contract->{reseller_core_id}); + if(!$svg){ + $svg = $svg_default; + #print "svg=$svg;"; + }else{ + NGCP::Panel::Utils::InvoiceTemplate::preprocessInvoiceTemplateSvg($in,\$svg); + } + $svg = $view->getTemplateProcessed($c_mock,\$svg, $stash ); + print $svg; + die(); + NGCP::Panel::Utils::InvoiceTemplate::convertSvg2Pdf(undef,\$svg,$in,$out); + #print $out->{tt_string_pdf}; + die; + #my $result = $c->forward($controller, 'invoice_templaet', [] ); + + #$req = HTTP::Request->new('OPTIONS', $uri.'/invoice/'..'/'); + #$res = $ua->request($req); + } + } +} +sub create_invoice{ + my($contract_id, $stime, $etime) = @_; + #my $invoice_serial = $dbh->selectrow_array('select max(invoices.serial) from invoices inner join contract_balances on invoices.id=contract_balances.invoice_id where contract_balances.contract_id=?',undef,$contract_id ); + my $invoice_serial = $dbh->selectrow_array('select max(invoices.serial) from invoices'); + $invoice_serial += 1; + $dbh->do('insert into invoices(year,month,serial)values(?,?,?)', undef, $stime->year, $stime->month,$invoice_serial ); + my $invoice_id = $dbh->last_insert_id(undef,'billing','invoices','id'); + $dbh->do('update contract_balances set invoice_id = ? where contract_id=? and start=? and end=?', undef, $invoice_id,$contract_id, $stime->datetime, $etime->datetime ); + return $dbh->selectrow_hashref('select * from invoices where id=?',undef, $invoice_id); +} + + + + + + + +# OPTIONS tests \ No newline at end of file