From d5683c6c03c483241eccbc0260688952588a55dd Mon Sep 17 00:00:00 2001 From: Andrew Isherwood Date: Fri, 6 Mar 2020 10:52:17 +0000 Subject: [PATCH] Bug 24190: Add acquisition logging --- C4/Budgets.pm | 114 ++++++++++++------ acqui/addorder.pl | 43 +++++++ acqui/cancelorder.pl | 5 + acqui/finishreceive.pl | 18 +++ acqui/invoice.pl | 89 +++++++++++++- admin/aqbudgetperiods.pl | 37 ++++-- .../prog/en/modules/tools/viewlog.tt | 13 +- 7 files changed, 270 insertions(+), 49 deletions(-) diff --git a/C4/Budgets.pm b/C4/Budgets.pm index 16eb5a22a0..5086d71715 100644 --- a/C4/Budgets.pm +++ b/C4/Budgets.pm @@ -24,12 +24,13 @@ use Koha::Patrons; use Koha::Acquisition::Invoice::Adjustments; use C4::Debug; use C4::Acquisition; +use C4::Log qw(logaction); use vars qw(@ISA @EXPORT); BEGIN { - require Exporter; - @ISA = qw(Exporter); - @EXPORT = qw( + require Exporter; + @ISA = qw(Exporter); + @EXPORT = qw( &GetBudget &GetBudgetByOrderNumber @@ -39,7 +40,7 @@ BEGIN { &GetBudgetsReport &GetBudgetReport &GetBudgetHierarchy - &AddBudget + &AddBudget &ModBudget &DelBudget &GetBudgetSpent @@ -54,15 +55,15 @@ BEGIN { &CanUserUseBudget &CanUserModifyBudget - &GetBudgetPeriod + &GetBudgetPeriod &GetBudgetPeriods &ModBudgetPeriod &AddBudgetPeriod - &DelBudgetPeriod + &DelBudgetPeriod &ModBudgetPlan - &GetBudgetsPlanCell + &GetBudgetsPlanCell &AddBudgetPlanValue &GetBudgetAuthCats &BudgetHasChildren @@ -71,7 +72,7 @@ BEGIN { &HideCols &GetCols - ); + ); } # ----------------------------BUDGETS.PM-----------------------------"; @@ -341,7 +342,7 @@ sub GetBudgetSpent { quantityreceived > 0 AND datecancellationprinted IS NULL |); - $sth->execute($budget_id); + $sth->execute($budget_id); my $sum = ( $sth->fetchrow_array || 0 ) + 0; $sth = $dbh->prepare(qq| @@ -359,20 +360,20 @@ sub GetBudgetSpent { $sum += $adj->adjustment; } - return $sum; + return $sum; } # ------------------------------------------------------------------- sub GetBudgetOrdered { - my ($budget_id) = @_; - my $dbh = C4::Context->dbh; - my $sth = $dbh->prepare(qq| + my ($budget_id) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(qq| SELECT SUM(| . C4::Acquisition::get_rounding_sql(qq|ecost_tax_included|) . qq| * quantity) AS sum FROM aqorders WHERE budget_id = ? AND quantityreceived = 0 AND datecancellationprinted IS NULL |); - $sth->execute($budget_id); + $sth->execute($budget_id); my $sum = ( $sth->fetchrow_array || 0 ) + 0; my $adjustments = Koha::Acquisition::Invoice::Adjustments->search({budget_id => $budget_id, encumber_open => 1, closedate => undef},{ join => 'invoiceid' }); @@ -380,7 +381,7 @@ sub GetBudgetOrdered { $sum += $adj->adjustment; } - return $sum; + return $sum; } =head2 GetBudgetName @@ -430,7 +431,7 @@ sub GetBudgetAuthCats { # ------------------------------------------------------------------- sub GetBudgetPeriods { - my ($filters,$orderby) = @_; + my ($filters,$orderby) = @_; my $rs = Koha::Database->new()->schema->resultset('Aqbudgetperiod'); $rs = $rs->search( $filters, { order_by => $orderby } ); @@ -451,18 +452,18 @@ sub GetBudgetPeriod { } sub DelBudgetPeriod{ - my ($budget_period_id) = @_; - my $dbh = C4::Context->dbh; - ; ## $total = number of records linked to the record that must be deleted + my ($budget_period_id) = @_; + my $dbh = C4::Context->dbh; + ; ## $total = number of records linked to the record that must be deleted my $total = 0; - ## get information about the record that will be deleted - my $sth = $dbh->prepare(qq| - DELETE + ## get information about the record that will be deleted + my $sth = $dbh->prepare(qq| + DELETE FROM aqbudgetperiods WHERE budget_period_id=? | - ); - return $sth->execute($budget_period_id); + ); + return $sth->execute($budget_period_id); } # ------------------------------------------------------------------- @@ -487,13 +488,13 @@ sub GetBudgetHierarchy { LEFT JOIN borrowers b on b.borrowernumber = aqbudgets.budget_owner_id JOIN aqbudgetperiods USING (budget_period_id)|; - my @where_strings; + my @where_strings; # show only period X if requested if ($budget_period_id) { push @where_strings," aqbudgets.budget_period_id = ?"; push @bind_params, $budget_period_id; } - # show only budgets owned by me, my branch or everyone + # show only budgets owned by me, my branch or everyone if ($owner) { if ($branchcode) { push @where_strings, @@ -509,10 +510,10 @@ sub GetBudgetHierarchy { push @bind_params, $branchcode; } } - $query.=" WHERE ".join(' AND ', @where_strings) if @where_strings; - $debug && warn $query,join(",",@bind_params); - my $sth = $dbh->prepare($query); - $sth->execute(@bind_params); + $query.=" WHERE ".join(' AND ', @where_strings) if @where_strings; + $debug && warn $query,join(",",@bind_params); + my $sth = $dbh->prepare($query); + $sth->execute(@bind_params); my %links; # create hash with budget_id has key @@ -644,7 +645,22 @@ sub AddBudget { undef $budget->{budget_encumb} if defined $budget->{budget_encumb} && $budget->{budget_encumb} eq ''; undef $budget->{budget_owner_id} if defined $budget->{budget_owner_id} && $budget->{budget_owner_id} eq ''; my $resultset = Koha::Database->new()->schema->resultset('Aqbudget'); - return $resultset->create($budget)->id; + my $id = $resultset->create($budget)->id; + + # Log the addition + if (C4::Context->preference("AcqLog")) { + my $infos = + sprintf("%010d", $budget->{budget_amount}) . + sprintf("%010d", $budget->{budget_encumb}) . + sprintf("%010d", $budget->{budget_expend}); + logaction( + 'ACQUISITIONS', + 'CREATE_FUND', + $id, + $infos + ); + } + return $id; } # ------------------------------------------------------------------- @@ -654,6 +670,24 @@ sub ModBudget { my $result = Koha::Database->new()->schema->resultset('Aqbudget')->find($budget); return unless($result); + # Log this modification + if (C4::Context->preference("AcqLog")) { + my $infos = + sprintf("%010d", $budget->{budget_amount}) . + sprintf("%010d", $budget->{budget_encumb}) . + sprintf("%010d", $budget->{budget_expend}) . + sprintf("%010d", $result->budget_amount) . + sprintf("%010d", $result->budget_encumb) . + sprintf("%010d", $result->budget_expend) . + sprintf("%010d", 0 - ($result->budget_amount - $budget->{budget_amount})); + logaction( + 'ACQUISITIONS', + 'MODIFY_FUND', + $budget->{budget_id}, + $infos + ); + } + undef $budget->{budget_encumb} if defined $budget->{budget_encumb} && $budget->{budget_encumb} eq ''; undef $budget->{budget_owner_id} if defined $budget->{budget_owner_id} && $budget->{budget_owner_id} eq ''; $result = $result->update($budget); @@ -663,11 +697,19 @@ sub ModBudget { # ------------------------------------------------------------------- # FIXME Must be replaced by Koha::Acquisition::Fund->delete sub DelBudget { - my ($budget_id) = @_; - my $dbh = C4::Context->dbh; - my $sth = $dbh->prepare("delete from aqbudgets where budget_id=?"); - my $rc = $sth->execute($budget_id); - return $rc; + my ($budget_id) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare("delete from aqbudgets where budget_id=?"); + my $rc = $sth->execute($budget_id); + # Log the deletion + if (C4::Context->preference("AcqLog")) { + logaction( + 'ACQUISITIONS', + 'DELETE_FUND', + $budget_id + ); + } + return $rc; } diff --git a/acqui/addorder.pl b/acqui/addorder.pl index dd43092b05..69cb97cb6a 100755 --- a/acqui/addorder.pl +++ b/acqui/addorder.pl @@ -233,6 +233,23 @@ my $user = $input->remote_user; my $basketno = $$orderinfo{basketno}; my $basket = Koha::Acquisition::Baskets->find($basketno); +# Order related fields we're going to log +my @log_order_fields = ( + 'quantity', + 'listprice', + 'unitprice', + 'unitprice_tax_excluded', + 'unitprice_tax_included', + 'rrp', + 'replacementprice', + 'rrp_tax_excluded', + 'rrp_tax_included', + 'ecost', + 'ecost_tax_excluded', + 'ecost_tax_included', + 'tax_rate_on_ordering' +); + # create, modify or delete biblio # create if $quantity>0 and $existing='no' # modify if $quantity>0 and $existing='yes' @@ -297,9 +314,35 @@ if ( $basket->{is_standing} || $orderinfo->{quantity} ne '0' ) { my $order = Koha::Acquisition::Order->new($orderinfo); if ( $orderinfo->{ordernumber} ) { ModOrder($orderinfo); + # Log the order modification + if (C4::Context->preference("AcqLog")) { + my $infos = ''; + foreach my $field(@log_order_fields) { + $infos .= sprintf("%010d", $orderinfo->{$field}); + } + logaction( + 'ACQUISITIONS', + 'MODIFY_ORDER', + $orderinfo->{ordernumber}, + $infos + ); + } } else { # else, it's a new line $order->store; + # Log the order creation + if (C4::Context->preference("AcqLog")) { + my $infos = ''; + foreach my $field(@log_order_fields) { + $infos .= sprintf("%010d", $orderinfo->{$field}); + } + logaction( + 'ACQUISITIONS', + 'CREATE_ORDER', + $order->ordernumber, + $infos + ); + } } my $order_users_ids = $input->param('users_ids'); my @order_users = split( /:/, $order_users_ids ); diff --git a/acqui/cancelorder.pl b/acqui/cancelorder.pl index bb5086bb4d..71467a10d1 100755 --- a/acqui/cancelorder.pl +++ b/acqui/cancelorder.pl @@ -35,6 +35,7 @@ use CGI; use C4::Auth; use C4::Output; use C4::Acquisition; +use C4::Log qw(logaction); use Koha::Acquisition::Baskets; my $input = new CGI; @@ -64,6 +65,10 @@ if($action and $action eq "confirmcancel") { $template->param(error_delbiblio => 1) if $error->{'delbiblio'}; } else { $template->param(success_cancelorder => 1); + # Log the cancellation of the order + if (C4::Context->preference("AcqLog")) { + logaction('ACQUISITIONS', 'CANCEL_ORDER', $ordernumber); + } } $template->param(confirmcancel => 1); } diff --git a/acqui/finishreceive.pl b/acqui/finishreceive.pl index a6519703c6..5c89985c09 100755 --- a/acqui/finishreceive.pl +++ b/acqui/finishreceive.pl @@ -28,6 +28,7 @@ use C4::Context; use C4::Acquisition; use C4::Biblio; use C4::Items; +use C4::Log qw(logaction); use C4::Search; use Koha::Number::Price; @@ -190,4 +191,21 @@ if ($suggestion_id) { $suggestion->update( { reason => $reason } ) if $suggestion; } +# Log the receipt +if (C4::Context->preference("AcqLog")) { + my $infos = + sprintf("%010d", $quantityrec) . + sprintf("%010d", $bookfund) . + sprintf("%010.2f", $input->param("tax_rate")) . + sprintf("%010.2f", $replacementprice) . + sprintf("%010.2f", $unitprice); + + logaction( + 'ACQUISITIONS', + 'RECEIVE_ORDER', + $ordernumber, + $infos + ); +} + print $input->redirect("/cgi-bin/koha/acqui/parcel.pl?invoiceid=$invoiceid&sticky_filters=1"); diff --git a/acqui/invoice.pl b/acqui/invoice.pl index 26717e99fe..49c5dd1558 100755 --- a/acqui/invoice.pl +++ b/acqui/invoice.pl @@ -33,6 +33,7 @@ use C4::Auth; use C4::Output; use C4::Acquisition; use C4::Budgets; +use C4::Log qw(logaction); use Koha::Acquisition::Booksellers; use Koha::Acquisition::Currencies; @@ -112,7 +113,25 @@ elsif ( $op && $op eq 'delete' ) { elsif ( $op && $op eq 'del_adj' ) { my $adjustment_id = $input->param('adjustment_id'); my $del_adj = Koha::Acquisition::Invoice::Adjustments->find( $adjustment_id ); - $del_adj->delete() if ($del_adj); + if ($del_adj) { + if (C4::Context->preference("AcqLog")) { + my $reason_length = length $del_adj->reason; + my $reason_padded = ( ' ' x (80 - $reason_length) ) . $del_adj->reason; + my $infos = + sprintf("%010d", $del_adj->invoiceid) . + sprintf("%010d", $del_adj->budget_id) . + sprintf("%010d", $del_adj->encumber_open) . + sprintf("%010.2f", $del_adj->adjustment) . + $reason_padded; + logaction( + 'ACQUISITIONS', + 'DELETE_INVOICE_ADJUSTMENT', + $adjustment_id, + $infos + ); + } + $del_adj->delete(); + } } elsif ( $op && $op eq 'mod_adj' ) { my @adjustment_id = $input->multi_param('adjustment_id'); @@ -123,22 +142,53 @@ elsif ( $op && $op eq 'mod_adj' ) { my @encumber_open = $input->multi_param('encumber_open'); my %e_open = map { $_ => 1 } @encumber_open; + my @keys = ('adjustment', 'reason', 'budget_id', 'encumber_open'); for( my $i=0; $i < scalar @adjustment; $i++ ){ if( $adjustment_id[$i] eq 'new' ){ next unless ( $adjustment[$i] || $reason[$i] ); - my $new_adj = Koha::Acquisition::Invoice::Adjustment->new({ - invoiceid => $invoiceid, + my $adj = { + invoiceid => $invoiceid, adjustment => $adjustment[$i], reason => $reason[$i], note => $note[$i], budget_id => $budget_id[$i] || undef, encumber_open => defined $e_open{ $adjustment_id[$i] } ? 1 : 0, - }); + }; + my $new_adj = Koha::Acquisition::Invoice::Adjustment->new($adj); $new_adj->store(); + # Log this addition + if (C4::Context->preference("AcqLog")) { + my $infos = get_log_string($adj); + logaction( + 'ACQUISITIONS', + 'CREATE_INVOICE_ADJUSTMENT', + $new_adj->adjustment_id, + $infos + ); + } } else { my $old_adj = Koha::Acquisition::Invoice::Adjustments->find( $adjustment_id[$i] ); unless ( $old_adj->adjustment == $adjustment[$i] && $old_adj->reason eq $reason[$i] && $old_adj->budget_id == $budget_id[$i] && $old_adj->encumber_open == $e_open{$adjustment_id[$i]} && $old_adj->note eq $note[$i] ){ + # Log this modification + if (C4::Context->preference("AcqLog")) { + my $infos = get_log_string({ + adjustment => $adjustment[$i], + reason => $reason[$i], + budget_id => $budget_id[$i], + encumber_open => $e_open{$adjustment_id[$i]}, + adjustment_old => $old_adj->adjustment, + reason_old => $old_adj->reason, + budget_id_old => $old_adj->budget_id, + encumber_open_old => $old_adj->encumber_open + }); + logaction( + 'ACQUISITIONS', + 'UPDATE_INVOICE_ADJUSTMENT', + $adjustment_id[$i], + $infos + ); + } $old_adj->timestamp(undef); $old_adj->adjustment( $adjustment[$i] ); $old_adj->reason( $reason[$i] ); @@ -266,4 +316,35 @@ sub get_infos { return \%line; } +sub get_log_string { + my ($data) = @_; + + # We specify the keys we're dealing for logging within an array in order + # to preserve order, if we just iterate the hash keys, we could get + # the values in any order + my @keys = ( + 'budget_id', + 'encumber_open', + 'budget_id_old', + 'encumber_open_old' + ); + # Adjustment amount + my $return = sprintf("%010.2f", $data->{adjustment}); + # Left pad "reason" to the maximum length of aqinvoice_adjustments.reason + # (80 characters) + my $reason_len = length $data->{reason}; + $return .= ( ' ' x (80 - $reason_len) ) . $data->{reason}; + # Append the remaining fields + foreach my $key(@keys) { + $return .= sprintf("%010d", $data->{$key}); + } + # Old adjustment amount + $return .= sprintf("%010.2f", $data->{adjustment_old}); + # Left pad "reason_old" to the maximum length of aqinvoice_adjustments.reason + # (80 characters) + my $reason_old_len = length $data->{reason_old}; + $return .= ( ' ' x (80 - $reason_old_len) ) . $data->{reason_old}; + return $return; +} + output_html_with_http_headers $input, $cookie, $template->output; diff --git a/admin/aqbudgetperiods.pl b/admin/aqbudgetperiods.pl index aa2998d91a..d285b8ad92 100755 --- a/admin/aqbudgetperiods.pl +++ b/admin/aqbudgetperiods.pl @@ -57,6 +57,7 @@ use C4::Output; use C4::Acquisition; use C4::Budgets; use C4::Debug; +use C4::Log qw(logaction); use Koha::Acquisition::Currencies; my $dbh = C4::Context->dbh; @@ -116,14 +117,34 @@ elsif ( $op eq 'add_validate' ) { ## add or modify a budget period (confirmation) ## update budget period data - if ( $budget_period_id ne '' ) { - $$budget_period_hashref{$_}||=0 for qw(budget_period_active budget_period_locked); - my $status=ModBudgetPeriod($budget_period_hashref); - } - else { # ELSE ITS AN ADD - my $budget_period_id=AddBudgetPeriod($budget_period_hashref); - } - $op='else'; + if ( $budget_period_id ne '' ) { + # Grab the previous values so we can log them + my $budgetperiod_old=GetBudgetPeriod($budget_period_id); + $$budget_period_hashref{$_}||=0 for qw(budget_period_active budget_period_locked); + my $status=ModBudgetPeriod($budget_period_hashref); + # Log the budget modification + if (C4::Context->preference("AcqLog")) { + my $diff = 0 - ($budgetperiod_old->{budget_period_total} - $budget_period_hashref->{budget_period_total}); + my $infos = + eval { output_pref({ dt => dt_from_string( $input->param('budget_period_startdate') ), dateformat => 'iso', dateonly => 1 } ); } . + eval { output_pref({ dt => dt_from_string( $input->param('budget_period_enddate') ), dateformat => 'iso', dateonly => 1 } ); } . + sprintf("%010d", $budget_period_hashref->{budget_period_total}) . + eval { output_pref({ dt => dt_from_string( $budgetperiod_old->{budget_period_startdate} ), dateformat => 'iso', dateonly => 1 } ); } . + eval { output_pref({ dt => dt_from_string( $budgetperiod_old->{budget_period_enddate} ), dateformat => 'iso', dateonly => 1 } ); } . + sprintf("%010d", $budgetperiod_old->{budget_period_total}) . + sprintf("%010d", $diff); + logaction( + 'ACQUISITIONS', + 'MODIFY_BUDGET', + $budget_period_id, + $infos + ); + } + } + else { # ELSE ITS AN ADD + my $budget_period_id=AddBudgetPeriod($budget_period_hashref); + } + $op='else'; } #-------------------------------------------------- diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt index 76a2c4e753..6f9f59c33d 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt @@ -81,6 +81,17 @@ fieldset.rows label.viewlog { [% CASE 'CLOSE_BASKET' %]Close an acquisitions basket [% CASE 'APPROVE_BASKET' %]Approve an acquisitions basket [% CASE 'REOPEN_BASKET' %]Reopen an acquisitions basket +[% CASE 'CANCEL_ORDER' %]Cancel an order +[% CASE 'CREATE_ORDER' %]Create an order +[% CASE 'MODIFY_ORDER' %]Modify an order +[% CASE 'CREATE_INVOICE_ADJUSTMENT' %]Create an invoice adjustment +[% CASE 'UPDATE_INVOICE_ADJUSTMENT' %]Modify an invoice adjustment +[% CASE 'DELETE_INVOICE_ADJUSTMENT' %]Delete an invoice adjustment +[% CASE 'RECEIVE_ORDER' %]Receive an order +[% CASE 'MODIFY_BUDGET' %]Modify a budget +[% CASE 'CREATE_FUND' %]Create a fund +[% CASE 'MODIFY_FUND' %]Modify a fund +[% CASE 'DELETE_FUND' %]Delete a fund [% CASE 'Run' %]Run [% CASE %][% action | html %] [% END %] @@ -153,7 +164,7 @@ fieldset.rows label.viewlog { [% END %] - [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'CHANGE PASS' 'Run' 'ADD_BASKET' 'MODIFY_BASKET' 'MODIFY_BASKET_HEADER' 'MODIFY_BASKET_USERS' 'CLOSE_BASKET' 'APPROVE_BASKET' 'REOPEN_BASKET' ] %] + [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'CHANGE PASS' 'Run' 'ADD_BASKET' 'MODIFY_BASKET' 'MODIFY_BASKET_HEADER' 'MODIFY_BASKET_USERS' 'CLOSE_BASKET' 'APPROVE_BASKET' 'REOPEN_BASKET' 'CANCEL_ORDER' 'CREATE_ORDER' 'MODIFY_ORDER' 'CREATE_INVOICE_ADJUSTMENT' 'UPDATE_INVOICE_ADJUSTMENT' 'DELETE_INVOICE_ADJUSTMENT' 'RECEIVE_ORDER' 'MODIFY_BUDGET' 'MODIFY_FUND' 'CREATE_FUND' 'DELETE_FUND' ] %] [% IF actions.grep(actx).size %] [% ELSE %] -- 2.20.1