From 974df926673b2f8367807d10383b916367db710e Mon Sep 17 00:00:00 2001 From: Andrew Isherwood Date: Fri, 29 Nov 2019 15:40:58 +0000 Subject: [PATCH] Bug 23971: Add logging for basket related actions This patch adds logging for the following Acq actions: - Basket creation - Basket editing - Basket approval (via EDI) - Basket closure --- C4/Acquisition.pm | 38 ++++++++++++++++++- C4/UsageStats.pm | 1 + Koha/EDI.pm | 4 +- acqui/addorder.pl | 10 +++++ acqui/basket.pl | 15 +++++--- acqui/basketgroup.pl | 3 +- acqui/basketheader.pl | 3 +- .../atomicupdate/bug_23971_AcqLog_pref.perl | 7 ++++ installer/data/mysql/mandatory/sysprefs.sql | 1 + .../en/modules/admin/preferences/logs.pref | 6 +++ .../prog/en/modules/tools/viewlog.tt | 6 ++- 11 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_23971_AcqLog_pref.perl diff --git a/C4/Acquisition.pm b/C4/Acquisition.pm index e29cbe8733..2fbb4b6afd 100644 --- a/C4/Acquisition.pm +++ b/C4/Acquisition.pm @@ -27,6 +27,7 @@ use C4::Suggestions; use C4::Biblio; use C4::Contract; use C4::Debug; +use C4::Log qw(logaction); use C4::Templates qw(gettemplate); use Koha::DateUtils qw( dt_from_string output_pref ); use Koha::Acquisition::Baskets; @@ -203,6 +204,12 @@ sub NewBasket { $basketbooksellernote ||= q{}; ModBasketHeader( $basket, $basketname, $basketnote, $basketbooksellernote, $basketcontractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items ); + + # Log the basket creation + if (C4::Context->preference("AcqLog")) { + logaction('ACQUISITIONS', 'ADD_BASKET', $basket); + } + return $basket; } @@ -217,7 +224,7 @@ close a basket (becomes unmodifiable, except for receives) =cut sub CloseBasket { - my ($basketno) = @_; + my ($basketno, $user, $edi_approval) = @_; my $dbh = C4::Context->dbh; $dbh->do('UPDATE aqbasket SET closedate=now() WHERE basketno=?', {}, $basketno ); @@ -225,6 +232,19 @@ sub CloseBasket { q{UPDATE aqorders SET orderstatus = 'ordered' WHERE basketno = ? AND orderstatus NOT IN ( 'complete', 'cancelled')}, {}, $basketno ); + + # Log the closure + if (C4::Context->preference("AcqLog")) { + my $action = $edi_approval ? 'APPROVE_BASKET' : 'CLOSE_BASKET'; + my $infos = $user ? sprintf("%010d", $user) : undef; + logaction( + 'ACQUISITIONS', + $action, + $basketno, + $infos + ); + } + return; } @@ -522,6 +542,19 @@ sub ModBasket { my $sth = $dbh->prepare($query); $sth->execute(@params); + # Log the basket update + if (C4::Context->preference("AcqLog")) { + my $infos = $basketinfo->{borrowernumber} ? + sprintf("%010d", $basketinfo->{borrowernumber}) : + undef; + logaction( + 'ACQUISITIONS', + 'MODIFY_BASKET', + $basketinfo->{'basketno'}, + $infos + ); + } + return; } @@ -561,7 +594,7 @@ case the AcqCreateItem syspref takes precedence). =cut sub ModBasketHeader { - my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items) = @_; + my ($basketno, $basketname, $note, $booksellernote, $contractnumber, $booksellerid, $deliveryplace, $billingplace, $is_standing, $create_items, $borrowernumber) = @_; $is_standing ||= 0; my $query = qq{ @@ -579,6 +612,7 @@ sub ModBasketHeader { my $sth2 = $dbh->prepare($query2); $sth2->execute($contractnumber,$basketno); } + return; } diff --git a/C4/UsageStats.pm b/C4/UsageStats.pm index 6f9b27c20f..e344cd7a22 100644 --- a/C4/UsageStats.pm +++ b/C4/UsageStats.pm @@ -217,6 +217,7 @@ sub BuildReport { TagsEnabled CalendarFirstDayOfWeek opaclanguagesdisplay + AcqLog AuthoritiesLog BorrowersLog CataloguingLog diff --git a/Koha/EDI.pm b/Koha/EDI.pm index 8fc8d0d828..2f4082f3ed 100644 --- a/Koha/EDI.pm +++ b/Koha/EDI.pm @@ -592,7 +592,9 @@ sub process_quote { basketno => $b, } ); - CloseBasket($b); + # Close the basket, passing a flag indicating that this action + # originated from an approval + CloseBasket($b, undef, 1); } } diff --git a/acqui/addorder.pl b/acqui/addorder.pl index b9915e6aec..bef3dc8171 100755 --- a/acqui/addorder.pl +++ b/acqui/addorder.pl @@ -126,6 +126,7 @@ use C4::Biblio; # AddBiblio TransformKohaToMarc use C4::Budgets; use C4::Items; use C4::Output; +use C4::Log qw(logaction); use Koha::Acquisition::Currencies; use Koha::Acquisition::Orders; use C4::Barcodes; @@ -360,6 +361,15 @@ if ( $basket->{is_standing} || $orderinfo->{quantity} ne '0' ) { } +if (C4::Context->preference("AcqLog") && $basketno) { + logaction( + 'ACQUISITIONS', + 'MODIFY_BASKET', + $basketno, + sprintf("%010d", $loggedinuser) + ); +} + my $booksellerid=$$orderinfo{booksellerid}; if (my $import_batch_id=$$orderinfo{import_batch_id}) { print $input->redirect("/cgi-bin/koha/acqui/addorderiso2709.pl?import_batch_id=$import_batch_id&basketno=$basketno&booksellerid=$booksellerid"); diff --git a/acqui/basket.pl b/acqui/basket.pl index d0fa4f2eb7..95f214bbe8 100755 --- a/acqui/basket.pl +++ b/acqui/basket.pl @@ -193,7 +193,7 @@ if ( $op eq 'delete_confirm' ) { if ($confirm) { my $basketno = $query->param('basketno'); my $booksellerid = $query->param('booksellerid'); - $basketno =~ /^\d+$/ and CloseBasket($basketno); + $basketno =~ /^\d+$/ and CloseBasket($basketno, $loggedinuser); # if requested, create basket group, close it and attach the basket if ($query->param('createbasketgroup')) { my $branchcode; @@ -207,7 +207,8 @@ if ( $op eq 'delete_confirm' ) { closed => 1, }); ModBasket( { basketno => $basketno, - basketgroupid => $basketgroupid } ); + basketgroupid => $basketgroupid, + borrowernumber => $loggedinuser } ); print $query->redirect('/cgi-bin/koha/acqui/basketgroup.pl?booksellerid='.$booksellerid.'&closed=1'); } else { print $query->redirect('/cgi-bin/koha/acqui/booksellers.pl?booksellerid=' . $booksellerid); @@ -240,7 +241,8 @@ elsif ( $op eq 'ediorder' ) { $branch = undef if(defined $branch and $branch eq ''); ModBasket({ basketno => $basket->{basketno}, - branch => $branch + branch => $branch, + borrowernumber => $loggedinuser }); print $query->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno"); exit; @@ -534,7 +536,7 @@ sub edi_close_and_order { if ( create_edi_order($edi_params) ) { #$template->param( edifile => 1 ); } - CloseBasket($basketno); + CloseBasket($basketno, $loggedinuser); # if requested, create basket group, close it and attach the basket if ( $query->param('createbasketgroup') ) { @@ -555,8 +557,9 @@ sub edi_close_and_order { ); ModBasket( { - basketno => $basketno, - basketgroupid => $basketgroupid + basketno => $basketno, + basketgroupid => $basketgroupid, + borrowernumber => $loggedinuser } ); print $query->redirect( diff --git a/acqui/basketgroup.pl b/acqui/basketgroup.pl index 3b53bd9602..962296aa6e 100755 --- a/acqui/basketgroup.pl +++ b/acqui/basketgroup.pl @@ -307,7 +307,8 @@ if ( $op eq "add" ) { my $basketno=$input->param('basketno'); my $basketgroupid=$input->param('basketgroupid'); ModBasket( { basketno => $basketno, - basketgroupid => $basketgroupid } ); + basketgroupid => $basketgroupid, + borrowernumber => $loggedinuser } ); print $input->redirect("basket.pl?basketno=" . $basketno); } elsif ( $op eq 'closeandprint') { # diff --git a/acqui/basketheader.pl b/acqui/basketheader.pl index f06900ce85..0cb5737b20 100755 --- a/acqui/basketheader.pl +++ b/acqui/basketheader.pl @@ -153,7 +153,8 @@ if ( $op eq 'add_form' ) { scalar $input->param('deliveryplace'), scalar $input->param('billingplace'), scalar $input->param('is_standing') ? 1 : undef, - scalar $input->param('create_items') + scalar $input->param('create_items'), + $loggedinuser ); } else { #New basket $basketno = NewBasket( diff --git a/installer/data/mysql/atomicupdate/bug_23971_AcqLog_pref.perl b/installer/data/mysql/atomicupdate/bug_23971_AcqLog_pref.perl new file mode 100644 index 0000000000..7dd91b8b5b --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_23971_AcqLog_pref.perl @@ -0,0 +1,7 @@ +$DBversion = 'XXX'; # will be replaced by the RM +if( CheckVersion( $DBversion ) ) { + $dbh->do( q| INSERT IGNORE INTO systempreferences (variable, value, explanation, options, type) VALUES ('AcqLog', '0', 'If enabled, log acquisition activity', '', 'YesNo'); | ); + + SetVersion( $DBversion ); + print "Upgrade to $DBversion done (Bug 23971 - Add AcqLog syspref)\n"; +} diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index 890dfcfe8f..49ae198f41 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -276,6 +276,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('IntranetUserJS','','70|10','Custom javascript for inclusion in Intranet','Textarea'), ('intranet_includes','includes',NULL,'The includes directory you want for specific look of Koha (includes or includes_npl for example)','Free'), ('ISBD','#100||{ 100a }{ 100b }{ 100c }{ 100d }{ 110a }{ 110b }{ 110c }{ 110d }{ 110e }{ 110f }{ 110g }{ 130a }{ 130d }{ 130f }{ 130g }{ 130h }{ 130k }{ 130l }{ 130m }{ 130n }{ 130o }{ 130p }{ 130r }{ 130s }{ 130t }|

\r\n#245||{ 245a }{ 245b }{245f }{ 245g }{ 245k }{ 245n }{ 245p }{ 245s }{ 245h }|\r\n#246||{ : 246i }{ 246a }{ 246b }{ 246f }{ 246g }{ 246n }{ 246p }{ 246h }|\r\n#242||{ = 242a }{ 242b }{ 242n }{ 242p }{ 242h }|\r\n#245||{ 245c }|\r\n#242||{ = 242c }|\r\n#250| - |{ 250a }{ 250b }|\r\n#254|, |{ 254a }|\r\n#255|, |{ 255a }{ 255b }{ 255c }{ 255d }{ 255e }{ 255f }{ 255g }|\r\n#256|, |{ 256a }|\r\n#257|, |{ 257a }|\r\n#258|, |{ 258a }{ 258b }|\r\n#260| - |{ 260a }{ 260b }{ 260c }|\r\n#300| - |{ 300a }{ 300b }{ 300c }{ 300d }{ 300e }{ 300f }{ 300g }|\r\n#306| - |{ 306a }|\r\n#307| - |{ 307a }{ 307b }|\r\n#310| - |{ 310a }{ 310b }|\r\n#321| - |{ 321a }{ 321b }|\r\n#340| - |{ 3403 }{ 340a }{ 340b }{ 340c }{ 340d }{ 340e }{ 340f }{ 340h }{ 340i }|\r\n#342| - |{ 342a }{ 342b }{ 342c }{ 342d }{ 342e }{ 342f }{ 342g }{ 342h }{ 342i }{ 342j }{ 342k }{ 342l }{ 342m }{ 342n }{ 342o }{ 342p }{ 342q }{ 342r }{ 342s }{ 342t }{ 342u }{ 342v }{ 342w }|\r\n#343| - |{ 343a }{ 343b }{ 343c }{ 343d }{ 343e }{ 343f }{ 343g }{ 343h }{ 343i }|\r\n#351| - |{ 3513 }{ 351a }{ 351b }{ 351c }|\r\n#352| - |{ 352a }{ 352b }{ 352c }{ 352d }{ 352e }{ 352f }{ 352g }{ 352i }{ 352q }|\r\n#362| - |{ 362a }{ 351z }|\r\n#440| - |{ 440a }{ 440n }{ 440p }{ 440v }{ 440x }|.\r\n#490| - |{ 490a }{ 490v }{ 490x }|.\r\n#800| - |{ 800a }{ 800b }{ 800c }{ 800d }{ 800e }{ 800f }{ 800g }{ 800h }{ 800j }{ 800k }{ 800l }{ 800m }{ 800n }{ 800o }{ 800p }{ 800q }{ 800r }{ 800s }{ 800t }{ 800u }{ 800v }|.\r\n#810| - |{ 810a }{ 810b }{ 810c }{ 810d }{ 810e }{ 810f }{ 810g }{ 810h }{ 810k }{ 810l }{ 810m }{ 810n }{ 810o }{ 810p }{ 810r }{ 810s }{ 810t }{ 810u }{ 810v }|.\r\n#811| - |{ 811a }{ 811c }{ 811d }{ 811e }{ 811f }{ 811g }{ 811h }{ 811k }{ 811l }{ 811n }{ 811p }{ 811q }{ 811s }{ 811t }{ 811u }{ 811v }|.\r\n#830| - |{ 830a }{ 830d }{ 830f }{ 830g }{ 830h }{ 830k }{ 830l }{ 830m }{ 830n }{ 830o }{ 830p }{ 830r }{ 830s }{ 830t }{ 830v }|.\r\n#500|

|{ 5003 }{ 500a }|\r\n#501|

|{ 501a }|\r\n#502|

|{ 502a }|\r\n#504|

|{ 504a }|\r\n#505|

|{ 505a }{ 505t }{ 505r }{ 505g }{ 505u }|\r\n#506|

|{ 5063 }{ 506a }{ 506b }{ 506c }{ 506d }{ 506u }|\r\n#507|

|{ 507a }{ 507b }|\r\n#508|

|{ 508a }{ 508a }|\r\n#510|

|{ 5103 }{ 510a }{ 510x }{ 510c }{ 510b }|\r\n#511|

|{ 511a }|\r\n#513|

|{ 513a }{513b }|\r\n#514|

|{ 514z }{ 514a }{ 514b }{ 514c }{ 514d }{ 514e }{ 514f }{ 514g }{ 514h }{ 514i }{ 514j }{ 514k }{ 514m }{ 514u }|\r\n#515|

|{ 515a }|\r\n#516|

|{ 516a }|\r\n#518|

|{ 5183 }{ 518a }|\r\n#520|

|{ 5203 }{ 520a }{ 520b }{ 520u }|\r\n#521|

|{ 5213 }{ 521a }{ 521b }|\r\n#522|

|{ 522a }|\r\n#524|

|{ 524a }|\r\n#525|

|{ 525a }|\r\n#526|

|{\\n510i }{\\n510a }{ 510b }{ 510c }{ 510d }{\\n510x }|\r\n#530|

|{\\n5063 }{\\n506a }{ 506b }{ 506c }{ 506d }{\\n506u }|\r\n#533|

|{\\n5333 }{\\n533a }{\\n533b }{\\n533c }{\\n533d }{\\n533e }{\\n533f }{\\n533m }{\\n533n }|\r\n#534|

|{\\n533p }{\\n533a }{\\n533b }{\\n533c }{\\n533d }{\\n533e }{\\n533f }{\\n533m }{\\n533n }{\\n533t }{\\n533x }{\\n533z }|\r\n#535|

|{\\n5353 }{\\n535a }{\\n535b }{\\n535c }{\\n535d }|\r\n#538|

|{\\n5383 }{\\n538a }{\\n538i }{\\n538u }|\r\n#540|

|{\\n5403 }{\\n540a }{ 540b }{ 540c }{ 540d }{\\n520u }|\r\n#544|

|{\\n5443 }{\\n544a }{\\n544b }{\\n544c }{\\n544d }{\\n544e }{\\n544n }|\r\n#545|

|{\\n545a }{ 545b }{\\n545u }|\r\n#546|

|{\\n5463 }{\\n546a }{ 546b }|\r\n#547|

|{\\n547a }|\r\n#550|

|{ 550a }|\r\n#552|

|{ 552z }{ 552a }{ 552b }{ 552c }{ 552d }{ 552e }{ 552f }{ 552g }{ 552h }{ 552i }{ 552j }{ 552k }{ 552l }{ 552m }{ 552n }{ 562o }{ 552p }{ 552u }|\r\n#555|

|{ 5553 }{ 555a }{ 555b }{ 555c }{ 555d }{ 555u }|\r\n#556|

|{ 556a }{ 506z }|\r\n#563|

|{ 5633 }{ 563a }{ 563u }|\r\n#565|

|{ 5653 }{ 565a }{ 565b }{ 565c }{ 565d }{ 565e }|\r\n#567|

|{ 567a }|\r\n#580|

|{ 580a }|\r\n#581|

|{ 5633 }{ 581a }{ 581z }|\r\n#584|

|{ 5843 }{ 584a }{ 584b }|\r\n#585|

|{ 5853 }{ 585a }|\r\n#586|

|{ 5863 }{ 586a }|\r\n#020|

|{ 020a }{ 020c }|\r\n#022|

|{ 022a }|\r\n#222| = |{ 222a }{ 222b }|\r\n#210| = |{ 210a }{ 210b }|\r\n#024|

|{ 024a }{ 024c }{ 024d }{ 0242 }|\r\n#027|

|{ 027a }|\r\n#028|

|{ 028a }{ 028b }|\r\n#013|

|{ 013a }{ 013b }{ 013c }{ 013d }{ 013e }{ 013f }|\r\n#030|

|{ 030a }|\r\n#037|

|{ 037a }{ 037b }{ 037c }{ 037f }{ 037g }{ 037n }|\r\n#010|

|{ 010a }|\r\n#015|

|{ 015a }{ 0152 }|\r\n#016|

|{ 016a }{ 0162 }|\r\n#600|

|{\\n6003 }{\\n600a}{ 600b }{ 600c }{ 600d }{ 600e }{ 600f }{ 600g }{ 600h }{--600k}{ 600l }{ 600m }{ 600n }{ 600o }{--600p}{ 600r }{ 600s }{ 600t }{ 600u }{--600x}{--600z}{--600y}{--600v}|\r\n#610|

|{\\n6103 }{\\n610a}{ 610b }{ 610c }{ 610d }{ 610e }{ 610f }{ 610g }{ 610h }{--610k}{ 610l }{ 610m }{ 610n }{ 610o }{--610p}{ 610r }{ 610s }{ 610t }{ 610u }{--610x}{--610z}{--610y}{--610v}|\r\n#611|

|{\\n6113 }{\\n611a}{ 611b }{ 611c }{ 611d }{ 611e }{ 611f }{ 611g }{ 611h }{--611k}{ 611l }{ 611m }{ 611n }{ 611o }{--611p}{ 611r }{ 611s }{ 611t }{ 611u }{--611x}{--611z}{--611y}{--611v}|\r\n#630|

|{\\n630a}{ 630b }{ 630c }{ 630d }{ 630e }{ 630f }{ 630g }{ 630h }{--630k }{ 630l }{ 630m }{ 630n }{ 630o }{--630p}{ 630r }{ 630s }{ 630t }{--630x}{--630z}{--630y}{--630v}|\r\n#648|

|{\\n6483 }{\\n648a }{--648x}{--648z}{--648y}{--648v}|\r\n#650|

|{\\n6503 }{\\n650a}{ 650b }{ 650c }{ 650d }{ 650e }{--650x}{--650z}{--650y}{--650v}|\r\n#651|

|{\\n6513 }{\\n651a}{ 651b }{ 651c }{ 651d }{ 651e }{--651x}{--651z}{--651y}{--651v}|\r\n#653|

|{ 653a }|\r\n#654|

|{\\n6543 }{\\n654a}{--654b}{--654x}{--654z}{--654y}{--654v}|\r\n#655|

|{\\n6553 }{\\n655a}{--655b}{--655x }{--655z}{--655y}{--655v}|\r\n#656|

|{\\n6563 }{\\n656a}{--656k}{--656x}{--656z}{--656y}{--656v}|\r\n#657|

|{\\n6573 }{\\n657a}{--657x}{--657z}{--657y}{--657v}|\r\n#658|

|{\\n658a}{--658b}{--658c}{--658d}{--658v}|\r\n#050|

|{ 050a }{ / 050b }|\r\n#082|

|{ 082a }{ / 082b }|\r\n#080|

|{ 080a }{ 080x }{ / 080b }|\r\n#070|

|{ 070a }{ / 070b }|\r\n#060|

|{ 060a }{ / 060b }|\r\n#074|

|{ 074a }|\r\n#086|

|{ 086a }|\r\n#088|

|{ 088a }|','70|10','ISBD','Textarea'), +('AcqLog','0',NULL,'If ON, log acquisitions activity','YesNo'), ('IssueLog','1',NULL,'If ON, log checkout activity','YesNo'), ('IssueLostItem','alert','Defines what should be done when an attempt is made to issue an item that has been marked as lost.','alert|confirm|nothing','Choice'), ('IssuingInProcess','0',NULL,'If ON, disables fines if the patron is issuing item that accumulate debt','YesNo'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref index 1e2d9b6b5b..ae769e21bf 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref @@ -42,6 +42,12 @@ Logging: on: Log off: "Don't log" - when changes to ILL requests take place. + - + - pref: AcqLog + choices: + on: Log + off: "Don't log" + - when acquisitions actions take place - - pref: IssueLog choices: 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 1a1f8fb18c..70db33d074 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt @@ -102,6 +102,10 @@ [% CASE 'ADDCIRCMESSAGE' %]Add circulation message [% CASE 'DELCIRCMESSAGE' %]Delete circulation message [% CASE 'STATUS_CHANGE' %]Change ILL request status +[% CASE 'ADD_BASKET' %]Create an acquisitions basket +[% CASE 'MODIFY_BASKET' %]Modify an acquisitions basket +[% CASE 'CLOSE_BASKET' %]Close an acquisitions basket +[% CASE 'APPROVE_BASKET' %]Approve an acquisitions basket [% CASE 'Run' %]Run [% CASE %][% action | html %] [% END %] @@ -176,7 +180,7 @@ [% END %] - [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'CHANGE PASS' 'Run' ] %] + [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'CHANGE PASS' 'Run' 'ADD_BASKET' 'MODIFY_BASKET' 'CLOSE_BASKET' 'APPROVE_BASKET' ] %] [% IF actions.grep(actx).size %] [% ELSE %] -- 2.20.1