From 5de5bbec61cd12a4abe335f069e76c0ac47c68d4 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Tue, 11 May 2021 07:51:45 -0400 Subject: [PATCH] Bug 26370: Add ability to disable demagnetizing items via SIP2 for arbitrary patron categories Some libraries have certain patron categories that can only do in house checkouts via SIP self check machines. In these cases, the items should not be demagnetized since the items cannot leave the library. Test Plan: 1) Apply this patch 2) prove t/db_dependent/SIP/Message.t Signed-off-by: Martin Renvoize --- C4/SIP/Sip/MsgType.pm | 27 ++++++- t/db_dependent/SIP/Message.t | 151 ++++++++++++++++++++++++++++++++++- 2 files changed, 175 insertions(+), 3 deletions(-) diff --git a/C4/SIP/Sip/MsgType.pm b/C4/SIP/Sip/MsgType.pm index d18029dcd0..5cc65baa79 100644 --- a/C4/SIP/Sip/MsgType.pm +++ b/C4/SIP/Sip/MsgType.pm @@ -556,7 +556,7 @@ sub handle_checkout { } # We never return the obsolete 'U' value for 'desensitize' - $resp .= sipbool( $status->desensitize ); + $resp .= sipbool( desensitize( { status => $status, patron => $patron, server => $server } ) ); $resp .= timestamp; # Now for the variable fields @@ -1486,7 +1486,7 @@ sub handle_renew { } else { $resp .= 'U'; } - $resp .= sipbool( $status->desensitize ); + $resp .= sipbool( desensitize( { status => $status, patron => $patron, server => $server } ) ); $resp .= timestamp; $resp .= add_field( FID_PATRON_ID, $patron->id, $server ); $resp .= add_field( FID_ITEM_ID, $item->id, $server ); @@ -1735,6 +1735,29 @@ sub api_auth { return $status; } +sub desensitize { + my ($params) = @_; + + my $status = $params->{status}; + my $desensitize = $status->desensitize(); + + # If desenstize is already false, no need to do anything + return unless $desensitize; + + my $patron = $params->{patron}; + my $server = $params->{server}; + + my $patron_categories = $server->{account}->{never_demagnitize}; + + # If no patron categories are set for never desensitize, no need to do anything + return $desensitize unless $patron_categories; + + my $patron_category = $patron->ptype(); + my @patron_categories = split( /,/, $patron_categories ); + + return !grep( /^$patron_category$/, @patron_categories ); +} + 1; __END__ diff --git a/t/db_dependent/SIP/Message.t b/t/db_dependent/SIP/Message.t index 08aaaf101e..46ca9b2253 100755 --- a/t/db_dependent/SIP/Message.t +++ b/t/db_dependent/SIP/Message.t @@ -21,7 +21,7 @@ # along with Koha; if not, see . use Modern::Perl; -use Test::More tests => 11; +use Test::More tests => 13; use Test::Exception; use Test::MockObject; use Test::MockModule; @@ -77,6 +77,24 @@ subtest 'Checkout V2' => sub { $schema->storage->txn_rollback; }; +subtest 'Test checkout desensitize' => sub { + my $schema = Koha::Database->new->schema; + $schema->storage->txn_begin; + plan tests => 3; + $C4::SIP::Sip::protocol_version = 2; + test_checkout_desensitize(); + $schema->storage->txn_rollback; +}; + +subtest 'Test renew desensitize' => sub { + my $schema = Koha::Database->new->schema; + $schema->storage->txn_begin; + plan tests => 3; + $C4::SIP::Sip::protocol_version = 2; + test_renew_desensitize(); + $schema->storage->txn_rollback; +}; + subtest 'Checkin V2' => sub { my $schema = Koha::Database->new->schema; $schema->storage->txn_begin; @@ -841,6 +859,137 @@ sub test_hold_patron_bcode { is( $resp, q{}, "maybe_add returns empty string for SIP item with no hold returns empty string" ); } +sub test_checkout_desensitize { + my $builder = t::lib::TestBuilder->new(); + my $branchcode = $builder->build({ source => 'Branch' })->{branchcode}; + my ( $response, $findpatron ); + my $mocks = create_mocks( \$response, \$findpatron, \$branchcode ); + + # create some data + my $patron1 = $builder->build({ + source => 'Borrower', + value => { + password => hash_password( PATRON_PW ), + }, + }); + my $card1 = $patron1->{cardnumber}; + my $sip_patron1 = C4::SIP::ILS::Patron->new( $card1 ); + my $patron_category = $sip_patron1->ptype(); + $findpatron = $sip_patron1; + my $item_object = $builder->build_sample_item({ + damaged => 0, + withdrawn => 0, + itemlost => 0, + restricted => 0, + homebranch => $branchcode, + holdingbranch => $branchcode, + }); + + my $mockILS = $mocks->{ils}; + my $server = { ils => $mockILS, account => {} }; + $mockILS->mock( 'institution', sub { $branchcode; } ); + $mockILS->mock( 'supports', sub { return; } ); + $mockILS->mock( 'checkout', sub { + shift; + return C4::SIP::ILS->checkout(@_); + }); + my $today = dt_from_string; + t::lib::Mocks::mock_userenv({ branchcode => $branchcode, flags => 1 }); + t::lib::Mocks::mock_preference( 'CheckPrevCheckout', 'hardyes' ); + + my $siprequest = CHECKOUT . 'YN' . siprequestdate($today) . + siprequestdate( $today->clone->add( days => 1) ) . + FID_INST_ID . $branchcode . '|'. + FID_PATRON_ID . $sip_patron1->id . '|' . + FID_ITEM_ID . $item_object->barcode . '|' . + FID_TERMINAL_PWD . 'ignored' . '|'; + + undef $response; + my $msg = C4::SIP::Sip::MsgType->new( $siprequest, 0 ); + $server->{account}->{never_demagnitize} = "A,$patron_category,Z"; + $msg->handle_checkout( $server ); + my $respcode = substr( $response, 5, 1 ); + is( $respcode, 'N', "Desensitize flag was not set for patron category in never_demagnitize" ); + + undef $response; + $server->{account}->{never_demagnitize} = "A,B,C"; + $msg->handle_checkout( $server ); + $respcode = substr( $response, 5, 1 ); + is( $respcode, 'Y', "Desensitize flag was set for patron category not in never_demagnitize" ); + + undef $response; + $server->{account}->{never_demagnitize} = ""; + $msg->handle_checkout( $server ); + $respcode = substr( $response, 5, 1 ); + is( $respcode, 'Y', "Desensitize flag was set for empty never_demagnitize" ); +} + +sub test_renew_desensitize { + my $builder = t::lib::TestBuilder->new(); + my $branchcode = $builder->build({ source => 'Branch' })->{branchcode}; + my ( $response, $findpatron ); + my $mocks = create_mocks( \$response, \$findpatron, \$branchcode ); + + # create some data + my $patron1 = $builder->build({ + source => 'Borrower', + value => { + password => hash_password( PATRON_PW ), + }, + }); + my $card1 = $patron1->{cardnumber}; + my $sip_patron1 = C4::SIP::ILS::Patron->new( $card1 ); + my $patron_category = $sip_patron1->ptype(); + $findpatron = $sip_patron1; + my $item_object = $builder->build_sample_item({ + damaged => 0, + withdrawn => 0, + itemlost => 0, + restricted => 0, + homebranch => $branchcode, + holdingbranch => $branchcode, + }); + + my $mockILS = $mocks->{ils}; + my $server = { ils => $mockILS, account => {} }; + $mockILS->mock( 'institution', sub { $branchcode; } ); + $mockILS->mock( 'supports', sub { return; } ); + $mockILS->mock( 'checkout', sub { + shift; + return C4::SIP::ILS->checkout(@_); + }); + my $today = dt_from_string; + t::lib::Mocks::mock_userenv({ branchcode => $branchcode, flags => 1 }); + + my $issue = Koha::Checkout->new({ branchcode => $branchcode, borrowernumber => $patron1->{borrowernumber}, itemnumber => $item_object->itemnumber })->store; + + my $siprequest = RENEW . 'YN' . siprequestdate($today) . + siprequestdate( $today->clone->add( days => 1) ) . + FID_INST_ID . $branchcode . '|'. + FID_PATRON_ID . $sip_patron1->id . '|' . + FID_ITEM_ID . $item_object->barcode . '|' . + FID_TERMINAL_PWD . 'ignored' . '|'; + + undef $response; + my $msg = C4::SIP::Sip::MsgType->new( $siprequest, 0 ); + $server->{account}->{never_demagnitize} = "A,$patron_category,Z"; + $msg->handle_checkout( $server ); + my $respcode = substr( $response, 5, 1 ); + is( $respcode, 'N', "Desensitize flag was not set for patron category in never_demagnitize" ); + + undef $response; + $server->{account}->{never_demagnitize} = "A,B,C"; + $msg->handle_checkout( $server ); + $respcode = substr( $response, 5, 1 ); + is( $respcode, 'Y', "Desensitize flag was set for patron category not in never_demagnitize" ); + + undef $response; + $server->{account}->{never_demagnitize} = ""; + $msg->handle_checkout( $server ); + $respcode = substr( $response, 5, 1 ); + is( $respcode, 'Y', "Desensitize flag was set for empty never_demagnitize" ); +} + # Helper routines sub create_mocks { -- 2.20.1