planning management
[koha.git] / admin / aqplan.pl
1 #!/usr/bin/perl
2
3 # Copyright 2008-2009 BibLibre SARL
4 # This file is part of Koha.
5 #
6 # Koha is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
9 # version.
10 #
11 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
17 # Suite 330, Boston, MA  02111-1307 USA
18
19 #script to administer the aqbudgets0 table
20 #written 20/02/2002 by paul.poulain@free.fr
21 # This software is placed under the gnu General Public License, v2 (http://www.gnu.org/licenses/gpl.html)
22
23 use strict;
24 use CGI;
25 use List::Util qw/min/;
26 use Date::Calc qw/Delta_YMD Easter_Sunday Today Decode_Date_EU/;
27 use Date::Manip qw/ ParseDate UnixDate DateCalc/;
28 use C4::Dates qw/format_date format_date_in_iso/;
29 use Number::Format qw(format_price);      
30 use Text::CSV_XS;
31
32 use C4::Acquisition;
33 use C4::Budgets;
34 use C4::Context;
35 use C4::Output;
36 use C4::Koha;
37 use C4::Auth;
38 use C4::Input;
39 use C4::Debug;
40
41 my $input = new CGI;
42 ####  $input
43
44 my $dbh = C4::Context->dbh;
45
46 my ( $template, $borrowernumber, $cookie, $staff_flags ) = get_template_and_user(
47     {   template_name   => "admin/aqplan.tmpl",
48         query           => $input,
49         type            => "intranet",
50         authnotrequired => 1,
51         flagsrequired   => { acquisition => 'planning_manage' },
52         debug           => 1,
53     }
54 );
55
56 my $budget_period_id = $input->param('budget_period_id');
57 # ' ------- get periods stuff ------------------'
58 # IF PERIOD_ID IS DEFINED,  GET THE PERIOD - ELSE GET THE ACTIVE PERIOD BY DEFAULT
59 my $period = GetBudgetPeriod($budget_period_id);
60 my $count  = GetPeriodsCount();
61 my $cur    = GetCurrency;
62
63 $template->param( period_button_only => 1 ) if $count == 0;
64
65 # authcats_loop populates the YUI planning button
66 my @auth_cats_loop            = GetBudgetAuthCats();
67 my $budget_period_id          = $period->{'budget_period_id'};
68 my $budget_period_startdate   = $period->{'budget_period_startdate'};
69 my $budget_period_enddate     = $period->{'budget_period_enddate'};
70 my $budget_period_locked      = $period->{'budget_period_locked'};
71 my $budget_period_description = $period->{'budget_period_description'};
72 my $budget_period_dropbox     = GetBudgetPeriodsDropbox($budget_period_id );
73
74 $template->param(
75     budget_period_id          => $budget_period_id,
76     budget_period_locked      => $budget_period_locked,
77     budget_period_description => $budget_period_description,
78     budget_period_dropbox     => $budget_period_dropbox,
79     auth_cats_loop            => \@auth_cats_loop,
80 );
81
82 # ------- get periods stuff ------------------
83
84 my $borrower_id         = $template->{param_map}->{'USER_INFO'}[0]->{'borrowernumber'};
85 my $borrower_branchcode = $template->{param_map}->{'USER_INFO'}[0]->{'branchcode'};
86
87 my $periods;
88 my $authcat      = $input->param('authcat');
89 my $show_active  = $input->param('show_active');
90 my $show_actual  = $input->param('show_actual');
91 my $show_percent = $input->param('show_percent');
92 my $output       = $input->param("output");
93 my $basename     = $input->param("basename");
94 my $mime         = $input->param("MIME");
95 my $del          = $input->param("sep");
96
97 my $show_mine    = 1; #SHOW BY DEFAULT
98 my $show         = $input->param('show'); # SET TO 1, BY A FORM SUMBIT
99 $show_mine       = $input->param('show_mine') if $show == 1;
100
101 my $cur_format = C4::Context->preference("CurrencyFormat");
102 my $num;
103
104 if ( $cur_format eq 'FR' ) {
105     $num = new Number::Format(
106         'decimal_fill'      => '2',
107         'decimal_point'     => ',',
108         'int_curr_symbol'   => '',
109         'mon_thousands_sep' => ' ',
110         'thousands_sep'     => ' ',
111         'mon_decimal_point' => ','
112     );
113 } else {  # US by default..
114     $num = new Number::Format(
115         'int_curr_symbol'   => '',
116         'mon_thousands_sep' => ',',
117         'mon_decimal_point' => '.'
118     );
119 }
120
121 if ( $budget_period_locked == 1  && not defined  $show_actual ) { 
122      $show_actual  = 1;
123 }
124
125 $authcat = 'Asort1' if  not defined $authcat; # defaults to Asort if no authcat given
126
127 my $budget_id = $input->param('budget_id');
128 my $op        = $input->param("op");
129
130 my $budgets_ref = GetBudgetHierarchy( $budget_period_id, $show_mine?$template->{param_map}->{'USER_INFO'}[0]->{'branchcode'}:'', $show_mine?$template->{param_map}->{'USER_INFO'}[0]->{'borrowernumber'}:'' );
131
132 # build categories list
133 my $sth = $dbh->prepare("select distinct category from authorised_values where category like 'A%' ");
134 $sth->execute;
135
136 # the list
137 my @category_list;
138
139 # a hash, to check that some hardcoded categories exist.
140 my %categories;
141 while ( my ($category) = $sth->fetchrow_array ) {
142     push( @category_list, $category );
143     $categories{$category} = 1;
144 }
145
146 push( @category_list, 'MONTHS' );
147 push( @category_list, 'ITEMTYPES' );
148 push( @category_list, 'BRANCHES' );
149
150 # push koha system categories
151
152 #reorder the list
153 @category_list = sort { $a cmp $b } @category_list;
154 my $tab_list = CGI::scrolling_list(
155     -name     => 'authcat',
156     -id       => 'authcat',
157     -values   => \@category_list,
158     -default  => $authcat,
159     -size     => 1,
160     -tabindex => '',
161     -multiple => 0,
162 );
163
164 $template->param( authcat_dropbox => $tab_list );
165
166 my @budgets = @$budgets_ref;
167 my $CGISort;
168 my @authvals;
169 my %labels;
170
171 if ( $authcat =~ m/^Asort/ ) {
172
173     # ----------- copied from C4::Input::buildCGIsort()
174     my $query = qq{SELECT * FROM authorised_values WHERE category=? order by lib};
175     my $sth   = $dbh->prepare($query);
176     $sth->execute($authcat);
177
178     if ( $sth->rows > 0 ) {
179         for ( my $i = 0 ; $i < $sth->rows ; $i++ ) {
180             my $results = $sth->fetchrow_hashref;
181             push @authvals, $results->{authorised_value};
182             $labels{ $results->{authorised_value} } = $results->{lib};
183         }
184     }
185     $sth->finish;
186     @authvals = sort { $a <=> $b } @authvals;
187
188 }
189 elsif ( $authcat eq 'MONTHS' ) {
190
191     # build months
192     my @start_date = UnixDate( $budget_period_startdate, ( '%Y', '%m', '%d' ) );
193     my @end_date   = UnixDate( $budget_period_enddate,   ( '%Y', '%m', '%d' ) );
194
195     my ( $Dy, $Dm, $Dd ) = Delta_YMD( @start_date, @end_date );
196
197     #calc number of months between
198     my $months      = ( $Dy * 12 ) + $Dm;
199     my $start_month = @start_date[1];
200     my $end_month   = ( $Dy * 12 ) + $Dm;
201
202     for my $mth ( 0 ... $months ) {
203         $mth = DateCalc( $budget_period_startdate, "+ $mth months" );
204         $mth = UnixDate( $mth, "%Y-%m" );
205         push( @authvals, $mth );
206     }
207     foreach my $vv (@authvals) {
208         $labels{$vv} = $vv;
209     }
210 }
211
212 elsif ( $authcat eq 'ITEMTYPES' ) {
213
214     my $query = qq| SELECT itemtype, description FROM itemtypes |;
215     my $sth   = $dbh->prepare($query);
216     $sth->execute();
217
218     if ( $sth->rows > 0 ) {
219         for ( my $i = 0 ; $i < $sth->rows ; $i++ ) {
220             my $results = $sth->fetchrow_hashref;
221             push @authvals, $results->{itemtype};
222             $labels{ $results->{itemtype} } = $results->{description};
223         }
224     }
225     $sth->finish;
226
227 } elsif ( $authcat eq 'BRANCHES' ) {
228
229     my $query = qq| SELECT branchcode, branchname FROM branches |;
230     my $sth   = $dbh->prepare($query);
231     $sth->execute();
232
233     if ( $sth->rows > 0 ) {
234         for ( my $i = 0 ; $i < $sth->rows ; $i++ ) {
235             my $results = $sth->fetchrow_hashref;
236             push @authvals, $results->{branchcode};
237             $labels{ $results->{branchcode} } = $results->{branchname};
238         }
239     }
240     $sth->finish;
241 }
242
243 my @authvals_row;
244 foreach my $val (@authvals) {
245     my %auth_hash;
246     $auth_hash{val} =   $labels{$val};
247     push( @authvals_row, \%auth_hash );
248 }
249
250 # ------------------------------------------------------------
251 if ( $op eq 'save' ) {
252     ### ---------------------  save
253     my @names = $input->param();
254
255     #get budgets
256     my ( @buds, @auth_values );
257     foreach my $n (@names) {
258         next if $n =~ m/^[^0-9]/;
259         $n =~ m/(\d*),(.*)/;
260         push @buds, $1;
261         push @auth_values, $2;
262     }
263
264     #uniq buds and auth
265     my %seen;
266     @buds        = grep { !$seen{$_}++ } @buds;
267     @auth_values = grep { !$seen{$_}++ } @auth_values;
268     my @budget_ids;
269     my @budget_lines;
270
271     foreach my $budget (@buds) {
272         my %budget_line;
273         my @cells_line;
274         my %cell_hash;
275         foreach my $authvalue (@auth_values) {
276             # get actual stats
277             my $cell_name        = "$budget,$authvalue";
278             my $estimated_amount = $input->param("$cell_name");
279             my %cell_hash = (
280                 estimated_amount => $estimated_amount,
281                 authvalue        => $authvalue,
282                 authcat          => $authcat,
283                 budget_id        => $budget,
284                 budget_period_id => $budget_period_id,
285             );
286             push( @cells_line, \%cell_hash );
287         }
288         %budget_line = (
289             lines => \@cells_line,
290         );
291         push( @budget_lines, \%budget_line );
292     }
293     my $plan = \@budget_lines;
294     ModBudgetPlan( $plan, $budget_period_id, $authcat );
295 }
296 # ------------------------------------------------------------
297 #         DEFAULT DISPLAY BEGINS
298
299 my @mime = ( C4::Context->preference("MIME") );
300 foreach my $mime (@mime) {
301     #               warn "".$mime;
302 }
303
304 my $CGIextChoice = CGI::scrolling_list(
305     -name     => 'MIME',
306     -id       => 'MIME',
307     -values   => \@mime,
308     -size     => 1,
309     -multiple => 0
310 );
311
312 my @dels         = ( C4::Context->preference("delimiter") );
313 my $CGIsepChoice = CGI::scrolling_list(
314     -name     => 'sep',
315     -id       => 'sep',
316     -values   => \@dels,
317     -size     => 1,
318     -multiple => 0
319 );
320
321 my ( @budget_lines, %cell_hash );
322
323 foreach my $budget (@budgets) {
324     my $budget_lock;
325
326     # check budget permission
327     if ( $period->{budget_period_locked} == 1 ) {
328         $budget_lock = 1;
329     } elsif ( $budget->{budget_permission} == 1 ) {
330         $budget_lock = 1 if $borrower_id != $budget->{'budget_owner_id'};
331     } elsif ( $budget->{budget_permission} == 2 ) {
332         $budget_lock = 1 if $borrower_branchcode ne $budget->{budget_branchcode};
333     }
334
335     # allow hard-coded itemtype and branch planning
336     unless ( $authcat eq 'ITEMTYPES'
337         or  $authcat eq 'BRANCHES'
338         or  $authcat eq 'MONTHS' ) {
339
340         # but skip budgets that dont match the current auth-category
341         next if ( $budget->{'sort1_authcat'} ne $authcat
342             && $budget->{'sort2_authcat'} ne $authcat );
343     }
344
345     my %budget_line;
346     my @cells_line;
347     my $actual_spent;
348     my $estimated_spent;
349     foreach my $authvalue (@authvals) {
350
351         # get actual stats
352         my %cell = (
353             budget_id        => $budget->{'budget_id'},
354             budget_period_id => $budget->{'budget_period_id'},
355             cell_name        => $budget->{'budget_id'} . ',' . $authvalue,
356             authvalue        => $authvalue,
357             authcat          => $authcat,
358             cell_authvalue   => $authvalue,
359             budget_lock      => $budget_lock,
360         );
361
362         my ( $actual, $estimated ) = GetBudgetsPlanCell( \%cell, $period, $budget );
363         $cell{actual_amount}    = sprintf( "%.2f", $actual );
364         $cell{estimated_amount} = sprintf( "%.2f", $estimated );
365         $actual_spent    += $cell{actual_amount};
366         $estimated_spent += $cell{estimated_amount};
367         push( @cells_line, \%cell );
368     }
369
370     #     lines => \@cells_line,
371     my $budget_act_remain = $budget->{budget_amount} - $actual_spent;
372     my $budget_est_remain = $budget->{budget_amount} - $estimated_spent;
373
374     %budget_line = (
375         lines                   => \@cells_line,
376         budget_name_indent      => $budget->{budget_name_indent},
377         budget_amount_formatted => $num->format_price( $budget->{budget_amount} ),
378         budget_amount           => $budget->{budget_amount},
379         budget_alloc            => $budget->{budget_alloc},
380         budget_act_remain       => sprintf( "%.2f", $budget_act_remain ),
381         budget_est_remain       => sprintf( "%.2f", $budget_est_remain ),
382         budget_id               => $budget->{budget_id}
383     );
384
385     $budget_line{est_negative} = '1' if $budget_est_remain < 0;
386     $budget_line{est_positive} = '1' if $budget_est_remain > 0;
387     $budget_line{act_negative} = '1' if $budget_act_remain < 0;
388     $budget_line{act_positive} = '1' if $budget_act_remain > 0;
389
390     # skip if active set , and spent == 0
391     next if ( $show_active == '1' && ( $actual_spent == 0 ) );
392
393     push( @budget_lines, \%budget_line );
394 }
395
396 if ( $output eq "file" ) {
397     _print_to_csv(\@authvals_row, \@budget_lines);
398     exit(1);
399 }
400
401     ## ## @budget_lines
402 $template->param(
403     authvals_row              => \@authvals_row,
404     budget_lines              => \@budget_lines,
405     budget_period_description => $period->{'budget_period_description'},
406     budget_period_locked      => $period->{'budget_period_locked'},
407     budget_period_id          => $budget_period_id,
408     authcat                   => $authcat,
409     show_active               => $show_active,
410     show_actual               => $show_actual,
411     show_percent              => $show_percent,
412     show_mine                  => $show_mine,
413     cur                       => $cur->{symbol},
414     cur_format                => $cur_format,
415     CGIextChoice              => $CGIextChoice,
416     CGIsepChoice              => $CGIsepChoice,
417 );
418
419 output_html_with_http_headers $input, $cookie, $template->output;
420
421 sub _print_to_csv {
422     my ( $header, $results ) = @_;
423
424     my $csv = Text::CSV_XS->new(
425         {   sep_char     => $del,
426             always_quote => 'TRUE',
427         }
428     );
429     print $input->header(
430         -type       => 'application/vnd.sun.xml.calc',
431         -encoding   => 'utf-8',
432         -attachment => "$basename.csv",
433         -name       => "$basename.csv"
434     );
435     my @col = ( 'Budget name', 'Budget total' );
436     foreach my $row (@$header) {
437         push @col, $row->{'val'};
438     }
439     push @col, 'Budget remaining';
440
441     $csv->combine(@col);
442     my $str = $csv->string;
443     print "$str\n";
444
445     foreach my $row (@$results) {
446         my @col = ( $row->{'budget_name'}, $row->{'budget_amount'} );
447         my $l = $row->{'lines'};
448         foreach my $line (@$l) {
449             push @col, $line->{'estimated_amount'};
450         }
451         push @col, $row->{'budget_est_remain'};
452         $csv->combine(@col);
453         my $str = $csv->string;
454         print "$str\n";
455     }
456 }
457