Bug 21068: Remove NorwegianPatronDB related code

Bug 11401 introduced code to support Norwegian national library card.
This code is too specific to be part of Koha as it, it should be a
plugin instead.
Moreover nobody uses it, but a modified version (see comment 3).

Test plan:
Add/edit/delete patron and make sure there are no regressions introduced
by these patches

Signed-off-by: Benjamin Rokseth <benjamin.rokseth@deichman.no>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
This commit is contained in:
Jonathan Druart 2018-08-13 13:49:56 -03:00 committed by Nick Clemens
parent 82ec02b538
commit 7c05f4fbe4
22 changed files with 9 additions and 2271 deletions

View File

@ -737,26 +737,6 @@ our $PERL_DEPS = {
'required' => '0',
'min_ver' => '5.836',
},
'SOAP::Lite' => {
'usage' => 'Norwegian national library card',
'required' => '0',
'min_ver' => '0.712',
},
'Crypt::GCrypt' => {
'usage' => 'Norwegian national library card',
'required' => '0',
'min_ver' => '1.24',
},
'Convert::BaseN' => {
'usage' => 'Norwegian national library card',
'required' => '0',
'min_ver' => '0.01',
},
'Digest::SHA' => {
'usage' => 'Norwegian national library card',
'required' => '0',
'min_ver' => '5.61',
},
'PDF::FromHTML' => {
'usage' => 'Discharge generation',
'required' => '0',

View File

@ -50,12 +50,6 @@ use Koha::Schema;
our (@ISA,@EXPORT,@EXPORT_OK,$debug);
use Module::Load::Conditional qw( can_load );
if ( ! can_load( modules => { 'Koha::NorwegianPatronDB' => undef } ) ) {
$debug && warn "Unable to load Koha::NorwegianPatronDB";
}
BEGIN {
$debug = $ENV{DEBUG} || 0;
require Exporter;

View File

@ -1,676 +0,0 @@
package Koha::NorwegianPatronDB;
# Copyright 2014 Oslo Public Library
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Koha; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
=head1 NAME
Koha::NorwegianPatronDB
=head1 SYNOPSIS
use Koha::NorwegianPatronDB;
=head1 CONDITIONAL LOADING
This module depends on some Perl modules that have not been marked as required.
This is because the module only will be of interest to Norwegian libraries, and
it seems polite not to bother the rest of the world with these modules. It is
also good practice to check that the module is actually needed before loading
it. So in a NorwegianPatronDB page or script it will be OK to just do:
use Koha::NorwegianPatronDB qw(...);
But in scripts that are also used by others (like e.g. moremember.pl), it will
be polite to only load the module at runtime, if it is needed:
use Module::Load;
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
load Koha::NorwegianPatronDB, qw( NLGetSyncDataFromBorrowernumber );
}
(Module::Load::Conditional is used for this in other parts of Koha, but it does
not seem to allow for a list of subroutines to import, so Module::Load looks
like a better candidate.)
=head1 FUNCTIONS
=cut
use Modern::Perl;
use C4::Context;
use C4::Members::Attributes qw( UpdateBorrowerAttribute );
use SOAP::Lite;
use Crypt::GCrypt;
use Digest::SHA qw( sha256_hex );
use Convert::BaseN;
use DateTime;
use base 'Exporter';
our %EXPORT_TAGS = ( all => [qw(
NLCheckSysprefs
NLSearch
NLSync
NLGetChanged
NLMarkForDeletion
NLDecodePin
NLEncryptPIN
NLUpdateHashedPIN
NLGetFirstname
NLGetSurname
NLGetSyncDataFromBorrowernumber
)] );
Exporter::export_ok_tags('all');
my $nl_uri = 'http://lanekortet.no';
=head2 SOAP::Transport::HTTP::Client::get_basic_credentials
This is included to set the username and password used by SOAP::Lite.
=cut
sub SOAP::Transport::HTTP::Client::get_basic_credentials {
# Library username and password from Base Bibliotek (stored as system preferences)
my $library_username = C4::Context->preference("NorwegianPatronDBUsername");
my $library_password = C4::Context->preference("NorwegianPatronDBPassword");
# Vendor username and password (stored in koha-conf.xml)
my $vendor_username = C4::Context->config( 'nlvendoruser' );
my $vendor_password = C4::Context->config( 'nlvendorpass' );
# Combine usernames and passwords, and encrypt with SHA256
my $combined_username = "$vendor_username-$library_username";
my $combined_password = sha256_hex( "$library_password-$vendor_password" );
return $combined_username => $combined_password;
}
=head2 NLCheckSysprefs
Check that sysprefs relevant to NL are set.
=cut
sub NLCheckSysprefs {
my $response = {
'error' => 0,
'nlenabled' => 0,
'endpoint' => 0,
'userpass' => 0,
};
# Check that the Norwegian national paron database is enabled
if ( C4::Context->preference("NorwegianPatronDBEnable") == 1 ) {
$response->{ 'nlenabled' } = 1;
} else {
$response->{ 'error' } = 1;
}
# Check that an endpoint is specified
if ( C4::Context->preference("NorwegianPatronDBEndpoint") ne '' ) {
$response->{ 'endpoint' } = 1;
} else {
$response->{ 'error' } = 1;
}
# Check that the username and password for the patron database is set
if ( C4::Context->preference("NorwegianPatronDBUsername") ne '' && C4::Context->preference("NorwegianPatronDBPassword") ne '' ) {
$response->{ 'userpass' } = 1;
} else {
$response->{ 'error' } = 1;
}
return $response;
}
=head2 NLSearch
Search the NL patron database.
SOAP call: "hent" (fetch)
=cut
sub NLSearch {
my ( $identifier ) = @_;
my $client = SOAP::Lite
->on_action( sub { return '""';})
->uri( $nl_uri )
->proxy( C4::Context->preference("NorwegianPatronDBEndpoint") );
my $id = SOAP::Data->type('string');
$id->name('identifikator');
$id->value( $identifier );
my $som = $client->hent( $id );
return $som;
}
=head2 NLSync
Sync a patron that has been changed or created in Koha "upstream" to NL.
Input is a hashref with one of two possible elements, either a patron retrieved
from the database:
my $result = NLSync({ 'patron' => $borrower_from_dbic });
or a plain old borrowernumber:
my $result = NLSync({ 'borrowernumber' => $borrowernumber });
In the latter case, this function will retrieve the patron record from the
database using DBIC.
Which part of the API is called depends on the value of the "syncstatus" column:
=over 4
=item * B<new> = The I<nyPost> ("new record") method is called.
=item * B<edited> = The I<endre> ("change/update") method is called.
=item * B<delete> = The I<slett> ("delete") method is called.
=back
Required values for B<new> and B<edited>:
=over 4
=item * sist_endret (last updated)
=item * adresse, postnr eller sted (address, zip or city)
=item * fdato (birthdate)
=item * fnr_hash (social security number, but not hashed...)
=item * kjonn (gender, M/F)
=back
=cut
sub NLSync {
my ( $input ) = @_;
my $patron;
if ( defined $input->{'borrowernumber'} ) {
$patron = Koha::Database->new->schema->resultset('Borrower')->find( $input->{'borrowernumber'} );
} elsif ( defined $input->{'patron'} ) {
$patron = $input->{'patron'};
}
# There should only be one sync, so we use the first one
my @syncs = $patron->borrower_syncs;
my $sync;
foreach my $this_sync ( @syncs ) {
if ( $this_sync->synctype eq 'norwegianpatrondb' ) {
$sync = $this_sync;
}
}
my $client = SOAP::Lite
->on_action( sub { return '""';})
->uri( $nl_uri )
->proxy( C4::Context->preference("NorwegianPatronDBEndpoint") );
my $cardnumber = SOAP::Data->name( 'lnr' => $patron->cardnumber );
# Call the appropriate method based on syncstatus
my $response;
if ( $sync->syncstatus eq 'edited' || $sync->syncstatus eq 'new' ) {
my $soap_patron = _koha_patron_to_soap( $patron );
if ( $sync->syncstatus eq 'edited' ) {
$response = $client->endre( $cardnumber, $soap_patron );
} elsif ( $sync->syncstatus eq 'new' ) {
$response = $client->nyPost( $soap_patron );
}
}
if ( $sync->syncstatus eq 'delete' ) {
$response = $client->slett( $cardnumber );
}
# Update the sync data according to the results
if ( $response->{'status'} && $response->{'status'} == 1 ) {
if ( $sync->syncstatus eq 'delete' ) {
# Turn off any further syncing
$sync->update( { 'sync' => 0 } );
}
# Update the syncstatus to 'synced'
$sync->update( { 'syncstatus' => 'synced' } );
# Update the 'synclast' attribute with the "server time" ("server_tid") returned by the method
$sync->update( { 'lastsync' => $response->{'server_tid'} } );
}
return $response;
}
=head2 NLGetChanged
Fetches patrons from NL that have been changed since a given timestamp. This includes
patrons that have been changed by the library that runs the sync, so we have to
check which library was the last one to change a patron, before we update patrons
locally.
This is supposed to be executed once per night.
SOAP call: soekEndret
=cut
sub NLGetChanged {
my ( $from_arg ) = @_;
my $client = SOAP::Lite
->on_action( sub { return '""';})
->uri( $nl_uri )
->proxy( C4::Context->preference("NorwegianPatronDBEndpoint") );
my $from_string;
if ( $from_arg && $from_arg ne '' ) {
$from_string = $from_arg;
} else {
# Calculate 1 second past midnight of the day before
my $dt = DateTime->now( time_zone => 'Europe/Oslo' );
$dt->subtract( days => 1 );
my $from = DateTime->new(
year => $dt->year(),
month => $dt->month(),
day => $dt->day(),
hour => 0,
minute => 0,
second => 1,
time_zone => 'Europe/Oslo',
);
$from_string = $from->ymd . "T" . $from->hms;
}
my $timestamp = SOAP::Data->name( 'tidspunkt' => $from_string );
my $max_results = SOAP::Data->name( 'max_antall' => 0 ); # 0 = no limit
my $start_index = SOAP::Data->name( 'start_indeks' => 0 ); # 1 is the first record
# Call the appropriate method based on syncstatus
my $som = $client->soekEndret( $timestamp, $max_results, $start_index );
# Extract and massage patron data
my $result = $som->result;
foreach my $patron ( @{ $result->{'respons_poster'} } ) {
# Only handle patrons that have lnr (barcode) and fnr_hash (social security number)
# Patrons that lack these two have been deleted from NL
if ( $patron->{'lnr'} && $patron->{'fnr_hash'} ) {
push @{ $result->{'kohapatrons'} }, _soap_to_kohapatron( $patron );
}
}
return $result;
}
=head2 NLMarkForDeletion
Mark a borrower for deletion, but do not do the actual deletion. Deleting the
borrower from NL will be done later by the nl-sync-from-koha.pl script.
=cut
sub NLMarkForDeletion {
my ( $borrowernumber ) = @_;
my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
'synctype' => 'norwegianpatrondb',
'borrowernumber' => $borrowernumber,
});
return $borrowersync->update( { 'syncstatus' => 'delete' } );
}
=head2 NLDecodePin
Takes a string encoded with AES/ECB/PKCS5PADDING and a 128-bits key, and returns
the decoded string as plain text.
The key needs to be stored in koha-conf.xml, like so:
<yazgfs>
...
<config>
...
<nlkey>xyz</nlkey>
</config>
</yazgfs>
=cut
sub NLDecodePin {
my ( $hash ) = @_;
my $key = C4::Context->config( 'nlkey' );
# Convert the hash from Base16
my $cb = Convert::BaseN->new( base => 16 );
my $decoded_hash = $cb->decode( $hash );
# Do the decryption
my $cipher = Crypt::GCrypt->new(
type => 'cipher',
algorithm => 'aes',
mode => 'ecb',
padding => 'standard', # "This is also known as PKCS#5"
);
$cipher->start( 'decrypting' );
$cipher->setkey( $key ); # Must be called after start()
my $plaintext = $cipher->decrypt( $decoded_hash );
$plaintext .= $cipher->finish;
return $plaintext;
}
=head2 NLEncryptPIN
Takes a plain text PIN as argument, returns the encrypted PIN, according to the
NL specs.
my $encrypted_pin = NLEncryptPIN( $plain_text_pin );
=cut
sub NLEncryptPIN {
my ( $pin ) = @_;
return _encrypt_pin( $pin );
}
=head2 NLUpdateHashedPIN
Takes two arguments:
=over 4
=item * Borrowernumber
=item * Clear text PIN code
=back
Hashes the password and saves it in borrower_sync.hashed_pin.
=cut
sub NLUpdateHashedPIN {
my ( $borrowernumber, $pin ) = @_;
my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
'synctype' => 'norwegianpatrondb',
'borrowernumber' => $borrowernumber,
});
return $borrowersync->update({ 'hashed_pin', _encrypt_pin( $pin ) });
}
=head2 _encrypt_pin
Takes a plain text PIN and returns the encrypted version, according to the NL specs.
=cut
sub _encrypt_pin {
my ( $pin ) = @_;
my $key = C4::Context->config( 'nlkey' );
# Do the encryption
my $cipher = Crypt::GCrypt->new(
type => 'cipher',
algorithm => 'aes',
mode => 'ecb',
padding => 'standard', # "This is also known as PKCS#5"
);
$cipher->start( 'encrypting' );
$cipher->setkey( $key ); # Must be called after start()
my $ciphertext = $cipher->encrypt( $pin );
$ciphertext .= $cipher->finish;
# Encode as Bas16
my $cb = Convert::BaseN->new( base => 16 );
my $encoded_ciphertext = $cb->encode( $ciphertext );
return $encoded_ciphertext;
}
=head2 NLGetSyncDataFromBorrowernumber
Takes a borrowernumber as argument, returns a Koha::Schema::Result::BorrowerSync
object.
my $syncdata = NLGetSyncDataFromBorrowernumber( $borrowernumber );
=cut
sub NLGetSyncDataFromBorrowernumber {
my ( $borrowernumber ) = @_;
my $data = Koha::Database->new->schema->resultset('BorrowerSync')->find({
'synctype' => 'norwegianpatrondb',
'borrowernumber' => $borrowernumber,
});
return $data;
}
=head2 NLGetFirstname
Takes a string like "Surname, Firstname" and returns the "Firstname" part.
If there is no comma, the string is returned unaltered.
my $firstname = NLGetFirstname( $name );
=cut
sub NLGetFirstname {
my ( $s ) = @_;
my ( $surname, $firstname ) = _split_name( $s );
if ( $surname eq $s ) {
return $s;
} else {
return $firstname;
}
}
=head2 NLGetSurname
Takes a string like "Surname, Firstname" and returns the "Surname" part.
If there is no comma, the string is returned unaltered.
my $surname = NLGetSurname( $name );
=cut
sub NLGetSurname {
my ( $s ) = @_;
my ( $surname, $firstname ) = _split_name( $s );
return $surname;
}
=head2 _split_name
Takes a string like "Surname, Firstname" and returns a list of surname and firstname.
If there is no comma, the string is returned unaltered.
my ( $surname, $firstname ) = _split_name( $name );
=cut
sub _split_name {
my ( $s ) = @_;
# Return the string if there is no comma
unless ( $s =~ m/,/ ) {
return $s;
}
my ( $surname, $firstname ) = split /, /, $s;
return ( $surname, $firstname );
}
=head2 _format_soap_error
Takes a soap result object as input and returns a formatted string containing SOAP error data.
=cut
sub _format_soap_error {
my ( $result ) = @_;
if ( $result ) {
return join ', ', $result->faultcode, $result->faultstring, $result->faultdetail;
} else {
return 'No result';
}
}
=head2 _soap_to_koha_patron
Convert a SOAP object of type "Laaner" into a hash that can be sent to Koha::Patron
=cut
sub _soap_to_kohapatron {
my ( $soap ) = @_;
return {
'cardnumber' => $soap->{ 'lnr' },
'surname' => NLGetSurname( $soap->{ 'navn' } ),
'firstname' => NLGetFirstname( $soap->{ 'navn' } ),
'sex' => $soap->{ 'kjonn' },
'dateofbirth' => $soap->{ 'fdato' },
'address' => $soap->{ 'p_adresse1' },
'address2' => $soap->{ 'p_adresse2' },
'zipcode' => $soap->{ 'p_postnr' },
'city' => $soap->{ 'p_sted' },
'country' => $soap->{ 'p_land' },
'b_address' => $soap->{ 'm_adresse1' },
'b_address2' => $soap->{ 'm_adresse2' },
'b_zipcode' => $soap->{ 'm_postnr' },
'b_city' => $soap->{ 'm_sted' },
'b_country' => $soap->{ 'm_land' },
'password' => $soap->{ 'pin' },
'dateexpiry' => $soap->{ 'gyldig_til' },
'email' => $soap->{ 'epost' },
'mobile' => $soap->{ 'tlf_mobil' },
'phone' => $soap->{ 'tlf_hjemme' },
'phonepro' => $soap->{ 'tlf_jobb' },
'_extra' => { # Data that should not go in the borrowers table
'socsec' => $soap->{ 'fnr_hash' },
'created' => $soap->{ 'opprettet' },
'created_by' => $soap->{ 'opprettet_av' },
'last_change' => $soap->{ 'sist_endret' },
'last_change_by' => $soap->{ 'sist_endret_av' },
},
};
}
=head2 _koha_patron_to_soap
Convert a patron (in the form of a Koha::Schema::Result::Borrower) into a SOAP
object that can be sent to NL.
=cut
sub _koha_patron_to_soap {
my ( $patron ) = @_;
# Extract attributes
my $patron_attributes = {};
foreach my $attribute ( $patron->borrower_attributes ) {
$patron_attributes->{ $attribute->code->code } = $attribute->attribute;
}
# There should only be one sync, so we use the first one
my @syncs = $patron->borrower_syncs;
my $sync = $syncs[0];
# Create SOAP::Data object
my $soap_patron = SOAP::Data->name(
'post' => \SOAP::Data->value(
SOAP::Data->name( 'lnr' => $patron->cardnumber ),
SOAP::Data->name( 'fnr_hash' => $patron_attributes->{ 'fnr' } )->type( 'string' )->type( 'string' ),
SOAP::Data->name( 'navn' => $patron->surname . ', ' . $patron->firstname )->type( 'string' ),
SOAP::Data->name( 'sist_endret' => $sync->lastsync )->type( 'string' ),
SOAP::Data->name( 'kjonn' => $patron->sex )->type( 'string' ),
SOAP::Data->name( 'fdato' => $patron->dateofbirth )->type( 'string' ),
SOAP::Data->name( 'p_adresse1' => $patron->address )->type( 'string' ),
SOAP::Data->name( 'p_adresse2' => $patron->address2 )->type( 'string' ),
SOAP::Data->name( 'p_postnr' => $patron->zipcode )->type( 'string' ),
SOAP::Data->name( 'p_sted' => $patron->city )->type( 'string' ),
SOAP::Data->name( 'p_land' => $patron->country )->type( 'string' ),
SOAP::Data->name( 'm_adresse1' => $patron->b_address )->type( 'string' ),
SOAP::Data->name( 'm_adresse2' => $patron->b_address2 )->type( 'string' ),
SOAP::Data->name( 'm_postnr' => $patron->b_zipcode )->type( 'string' ),
SOAP::Data->name( 'm_sted' => $patron->b_city )->type( 'string' ),
SOAP::Data->name( 'm_land' => $patron->b_country )->type( 'string' ),
# Do not send the PIN code as it has been hashed by Koha, but use the version hashed according to NL
SOAP::Data->name( 'pin' => $sync->hashed_pin )->type( 'string' ),
SOAP::Data->name( 'gyldig_til' => $patron->dateexpiry )->type( 'string' ),
SOAP::Data->name( 'epost' => $patron->email )->type( 'string' ),
SOAP::Data->name( 'tlf_mobil' => $patron->mobile )->type( 'string' ),
SOAP::Data->name( 'tlf_hjemme' => $patron->phone )->type( 'string' ),
SOAP::Data->name( 'tlf_jobb' => $patron->phonepro )->type( 'string' ),
),
)->type("Laaner");
return $soap_patron;
}
=head1 EXPORT
None by default.
=head1 AUTHOR
Magnus Enger <digitalutvikling@gmail.com>
=cut
1;
__END__

View File

@ -23,7 +23,6 @@ use Modern::Perl;
use Carp;
use List::MoreUtils qw( uniq );
use JSON qw( to_json );
use Module::Load::Conditional qw( can_load );
use Text::Unaccent qw( unac_string );
use C4::Accounts;
@ -45,10 +44,6 @@ use Koha::Club::Enrollments;
use Koha::Account;
use Koha::Subscription::Routinglists;
if ( ! can_load( modules => { 'Koha::NorwegianPatronDB' => undef } ) ) {
warn "Unable to load Koha::NorwegianPatronDB";
}
use base qw(Koha::Object);
our $RESULTSET_PATRON_ID_MAPPING = {
@ -245,24 +240,6 @@ sub store {
$self = $self->SUPER::store;
# If NorwegianPatronDBEnable is enabled, we set syncstatus to something that a
# cronjob will use for syncing with NL
if ( C4::Context->preference('NorwegianPatronDBEnable')
&& C4::Context->preference('NorwegianPatronDBEnable') == 1 )
{
Koha::Database->new->schema->resultset('BorrowerSync')
->create(
{
'borrowernumber' => $self->borrowernumber,
'synctype' => 'norwegianpatrondb',
'sync' => 1,
'syncstatus' => 'new',
'hashed_pin' =>
Koha::NorwegianPatronDB::NLEncryptPIN($self->plain_text_password),
}
);
}
$self->add_enrolment_fee_if_needed;
logaction( "MEMBERS", "CREATE", $self->borrowernumber, "" )
@ -293,28 +270,6 @@ sub store {
$self->add_enrolment_fee_if_needed;
}
# If NorwegianPatronDBEnable is enabled, we set syncstatus to something that a
# cronjob will use for syncing with NL
if ( C4::Context->preference('NorwegianPatronDBEnable')
&& C4::Context->preference('NorwegianPatronDBEnable') == 1 )
{
my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
'synctype' => 'norwegianpatrondb',
'borrowernumber' => $self->borrowernumber,
});
# Do not set to "edited" if syncstatus is "new". We need to sync as new before
# we can sync as changed. And the "new sync" will pick up all changes since
# the patron was created anyway.
if ( $borrowersync->syncstatus ne 'new' && $borrowersync->syncstatus ne 'delete' ) {
$borrowersync->update( { 'syncstatus' => 'edited' } );
}
# Set the value of 'sync'
# FIXME THIS IS BROKEN # $borrowersync->update( { 'sync' => $data{'sync'} } );
# Try to do the live sync
Koha::NorwegianPatronDB::NLSync({ 'borrowernumber' => $self->borrowernumber });
}
my $borrowers_log = C4::Context->preference("BorrowersLog");
my $previous_cardnumber = $self_from_storage->cardnumber;
if ($borrowers_log
@ -685,11 +640,6 @@ sub update_password {
return 0 if $password eq '****' or $password eq '';
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
# Update the hashed PIN in borrower_sync.hashed_pin, before Koha hashes it
Koha::NorwegianPatronDB::NLUpdateHashedPIN( $self->borrowernumber, $password );
}
my $digest = Koha::AuthUtils::hash_password($password);
$self->update(
{

View File

@ -1697,24 +1697,6 @@ CREATE TABLE borrower_debarments ( -- tracks restrictions on the patron's record
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table borrower_sync
--
DROP TABLE IF EXISTS `borrower_sync`;
CREATE TABLE borrower_sync (
borrowersyncid int(11) NOT NULL AUTO_INCREMENT, -- Primary key, unique identifier
borrowernumber int(11) NOT NULL, -- Connects data about synchronisations to a borrower
synctype varchar(32) NOT NULL, -- There could potentially be more than one kind of syncing going on, a text string here can be used to tell them apart. E.g.: The Norwegian national patron database uses 'norwegianpatrondb' in this column
sync tinyint(1) NOT NULL DEFAULT '0', -- A boolean (1/0) for turning syncing off and on for individual borrowers
syncstatus varchar(10) DEFAULT NULL, -- The sync status for any given borrower. Could be text strings like 'new', 'edited', 'synced' etc. The values used here will depend on the actual syncing being done.
lastsync varchar(50) DEFAULT NULL, -- Date of the last successfull sync. The date format might be different depending on the service that is being used, so no special date format is being enforced here.
hashed_pin varchar(64) DEFAULT NULL, -- Perhaps specific to The Norwegian national patron database, this column holds a hashed PIN code
PRIMARY KEY (borrowersyncid),
KEY borrowernumber (borrowernumber),
CONSTRAINT borrower_sync_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table api_keys
--

View File

@ -4,7 +4,6 @@
[% USE Branches %]
[% USE Categories %]
[% USE AuthorisedValues %]
[% SET NorwegianPatronDBEnable = Koha.Preference( 'NorwegianPatronDBEnable' ) %]
<div id="toolbar" class="btn-toolbar">
[% IF CAN_user_borrowers_edit_borrowers %]
[% IF ( guarantor ) %]
@ -72,13 +71,7 @@
[% END %]
[% IF CAN_user_borrowers_edit_borrowers %]
[% IF ( NorwegianPatronDBEnable == 1 ) %]
<li><a id="deletepatronlocal" href="#">Delete local</a></li>
<li><a id="deletepatronremote" href="#">Delete remote</a></li>
<li><a id="deletepatronboth" href="#">Delete local and remote</a></li>
[% ELSE %]
<li><a id="deletepatron" href="#">Delete</a></li>
[% END %]
<li><a id="deletepatron" href="#">Delete</a></li>
[% ELSE %]
<li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to delete patrons" id="deletepatron" href="#">Delete</a></li>
[% END %]

View File

@ -1,9 +0,0 @@
<form method="POST" action="nl-search.pl" autocomplete="off"> <!-- This form will be used for things like social security numbers, so it makes sense not to remember them. -->
<input type="hidden" name="op" value="search" />
<fieldset>
<legend>[% nl_search_form_title | html %]</legend>
<label for="q">Social security or card number: </label>
<input type="text" name="q" value="[% q | html %]">
<input type="submit" value="Search">
</fieldset>
</form>

View File

@ -9,7 +9,6 @@
var CAN_user_borrowers_edit_borrowers = "[% CAN_user_borrowers_edit_borrowers | html %]";
var dateformat = "[% Koha.Preference('dateformat') | html %]";
var NorwegianPatronDBEnable = "[% Koha.Preference('NorwegianPatronDBEnable') | html %]";
var borrowernumber;
var number_of_adult_categories = 0;

View File

@ -49,12 +49,6 @@
</form>
</div>
[% END %]
[% IF ( keeplocal ) %]
<div class="dialog message">
<h3>Remote record deleted, local record kept</h3>
<p>Patron was marked for deletion from Norwegian national patron database, but the local record was kept.</p>
</div>
[% END %]
</div>
</div>

View File

@ -28,11 +28,6 @@
</div>
[% END %]
[% IF Koha.Preference( 'NorwegianPatronDBEnable' ) == 1 %]
[% SET nl_search_form_title='Search the Norwegian national patron database' %]
[% INCLUDE 'nl-search-form.tt' %]
[% END %]
[% INCLUDE 'patron-toolbar.inc' %]
[% INCLUDE 'noadd-warnings.inc' %]

View File

@ -635,18 +635,6 @@
[% IF ( mandatorysort2 ) %]<span class="required">Required</span>[% END %]
</li>
[% END %]
[% IF ( Koha.Preference( 'NorwegianPatronDBEnable' ) == 1 ) %]
<li>
<label for="sort2">Sync with the Norwegian national patron database:</label>
[% IF ( sync == 0 ) %]
<input type="radio" id="sync" name="sync" value="1"> Yes
<input type="radio" id="sync" name="sync" value="0" checked> No
[% ELSE %]
<input type="radio" id="sync" name="sync" value="1" checked> Yes
<input type="radio" id="sync" name="sync" value="0"> No
[% END %]
</li>
[% END %]
[% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
<li><label for="checkprevcheckout">Check for previous checkouts: </label>
<select name="checkprevcheckout" id="checkprevcheckout">

View File

@ -494,32 +494,6 @@
</li>
[% END %]
[% IF Koha.Preference( 'NorwegianPatronDBEnable' ) == 1 %]
[% IF ( sync == 1 ) %]
<li>
<span class="label">Activate sync: </span>
Yes
</li>
[% IF ( syncstatus ) %]
<li>
<span class="label">Sync status: </span>
[% syncstatus | html %]
</li>
[% END %]
[% IF ( lastsync ) %]
<li>
<span class="label">Last sync: </span>
[% lastsync | $KohaDates %]
</li>
[% END %]
[% ELSE %]
<li>
<span class="label">Activate sync: </span>
No
</li>
[% END %]
[% END %]
[% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
<li>
<span class="label">Check previous checkouts: </span>

View File

@ -1,180 +0,0 @@
[% USE raw %]
[% USE Asset %]
[% USE KohaDates %]
[% USE Branches %]
[% SET footerjs = 1 %]
[% INCLUDE 'doc-head-open.inc' %]
<title>Search the Norwegian national patron database</title>
[% INCLUDE 'doc-head-close.inc' %]
</head>
<body id="pat_nl_search" class="pat">
[% INCLUDE 'header.inc' %]
[% INCLUDE 'patron-search.inc' %]
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> &rsaquo; Search the Norwegian national patron database</div>
<div id="doc3" class="yui-t2">
<div id="bd">
<div id="yui-main">
<div class="yui-b">
<h1>Search the Norwegian national patron database</h1>
[% IF (error) %]
<div class="dialog alert">
[% IF ( error.nlenabled == 0 ) %]<p>You need to activate this function with the NorwegianPatronDBEnable system preference in order to use it.</p>[% END %]
[% IF ( error.endpoint == 0 ) %]<p>You need to specify an endpoint with the NorwegianPatronDBEndpoint system preference.</p>[% END %]
[% IF ( error.userpass == 0 ) %]<p>You need to fill in the NorwegianPatronDBUsername and NorwegianPatronDBPassword system preferences in order to use this function.</p>[% END %]
[% IF ( error == 'COULD_NOT_ADD_PATRON' ) %]<p>Could not add a new patron.</p>[% END %]
</div>
[% ELSE %]
[% SET nl_search_form_title='Search' %]
[% INCLUDE 'nl-search-form.tt' %]
[% END %]
[% IF ( local_result ) %]
<h3>Existing patrons</h3>
<ul>
[% FOREACH patron IN local_result %]
<li>[% patron.firstname | html %] [% patron.surname | html %] [% patron.cardnumber | html %] |
<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | html %]">Details</a> |
<a href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% patron.borrowernumber | html %]">Edit</a> |
<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% patron.borrowernumber | html %]">Check out</a>
</li>
[% END %]
</ul>
[% END %]
[% IF ( result ) %]
[% IF result.antall_poster_returnert == 0 %]
<div class="dialog alert">
<p>No results found in the Norwegian national patron database. Message: "[% result.melding | html %]"</p>
</div>
[% ELSE %]
<h3>Results from the Norwegian national patron database</h3>
<div class="yui-g">
<div class="yui-u first">
[% PROCESS patron_detail p=result.respons_poster.0 %]
</div>
[% IF ( result.respons_poster.1 ) %]
<div class="yui-u">
[% PROCESS patron_detail p=result.respons_poster.1 %]
</div>
[% END %]
</div>
[% END %]
[% END %]
</div>
</div>
<div class="yui-b">
[% INCLUDE 'circ-menu.inc' %]
</div>
</div>
[% MACRO jsinclude BLOCK %]
[% INCLUDE 'str/members-menu.inc' %]
[% Asset.js("js/members-menu.js") | $raw %]
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]
[% BLOCK patron_detail %]
<div class="rows">
<h4>[% p.navn | html_entity %]</h4>
<ol>
[% IF ( p.kjonn ) %]<li><span class="label">Gender:</span> [% p.kjonn | html_entity %]</li>[% END %]
[% IF ( p.fdato ) %]<li><span class="label">Date of birth:</span> [% p.fdato | html_entity %]</li>[% END %]
[% IF ( p.lnr ) %]<li><span class="label">Card number:</span> [% p.lnr | html_entity %]</li>[% END %]
[% IF ( p.fnr_hash ) %]<li><span class="label">Social security number hash:</span> [% p.fnr_hash | html_entity %]</li>[% END %]
[% IF ( p.epost ) %]<li><span class="label">Email:</span> [% p.epost | html_entity %]</li>[% END %]
[% IF ( p.epost_sjekk ) %]<li><span class="label">Email check:</span> [% p.epost_sjekk | html_entity %]</li>[% END %]
[% IF ( p.tlf_mobil ) %]<li><span class="label">Phone - mobile:</span> [% p.tlf_mobil | html_entity %]</li>[% END %]
[% IF ( p.tlf_hjemme ) %]<li><span class="label">Phone - home:</span> [% p.tlf_hjemme | html_entity %]</li>[% END %]
[% IF ( p.tlf_jobb ) %]<li><span class="label">Phone - work:</span> [% p.tlf_jobb | html_entity %]</li>[% END %]
[% IF ( p.p_adresse1 ) %]<li><span class="label">Address:</span> [% p.p_adresse1 | html_entity %]</li>[% END %]
[% IF ( p.p_adresse2 ) %]<li><span class="label">Address 2:</span> [% p.p_adresse2 | html_entity %]</li>[% END %]
[% IF ( p.p_postnr ) %]<li><span class="label">Zip/Postal code:</span> [% p.p_postnr | html_entity %]</li>[% END %]
[% IF ( p.p_sted ) %]<li><span class="label">City:</span> [% p.p_sted | html_entity %]</li>[% END %]
[% IF ( p.p_land ) %]<li><span class="label">Country:</span> [% p.p_land | html_entity %]</li>[% END %]
[% IF ( p.p_sjekk ) %]<li><span class="label">Check:</span> [% p.p_sjekk | html_entity %]</li>[% END %]
[% IF ( p.m_adresse1 ) %]<li><span class="label">Address:</span> [% p.m_adresse1 | html_entity %]</li>[% END %]
[% IF ( p.m_adresse2 ) %]<li><span class="label">Address 2:</span> [% p.m_adresse2 | html_entity %]</li>[% END %]
[% IF ( p.m_postnr ) %]<li><span class="label">Zip/Postal code:</span> [% p.m_postnr | html_entity %]</li>[% END %]
[% IF ( p.m_sted ) %]<li><span class="label">City:</span> [% p.m_sted | html_entity %]</li>[% END %]
[% IF ( p.m_land ) %]<li><span class="label">Country:</span> [% p.m_land | html_entity %]</li>[% END %]
[% IF ( p.m_sjek ) %]<li><span class="label">Check:</span> [% p.m_sjekk | html_entity %]</li>[% END %]
[% IF ( p.m_gyldig_til ) %]<li><span class="label">Valid until:</span> [% p.m_gyldig_til | html_entity %]</li>[% END %]
[% IF ( p.pin ) %]<li><span class="label">PIN:</span> [% p.pin | html_entity %]</li>[% END %]
[% IF ( p.passord ) %]<li><span class="label">Password:</span> [% p.passord | html_entity %]</li>[% END %]
[% IF ( p.feide ) %]<li><span class="label">FEIDE:</span> [% p.feide | html_entity %]</li>[% END %]
[% IF ( p.folkeregsjekk_dato ) %]<li><span class="label">Population registry date check:</span> [% p.folkeregsjekk_dato | html_entity %]</li>[% END %]
[% IF ( p.hjemmebibliotek ) %]<li><span class="label">Home library:</span> [% p.hjemmebibliotek | html_entity %]</li>[% END %]
[% IF ( p.opprettet ) %]<li><span class="label">Created:</span> [% p.opprettet | html_entity %]</li>[% END %]
[% IF ( p.opprettet_av ) %]<li><span class="label">Created by:</span> [% p.opprettet_av | html_entity %]</li>[% END %]
[% IF ( p.sist_endret ) %]<li><span class="label">Last changed:</span> [% p.sist_endret | html_entity %]</li>[% END %]
[% IF ( p.sist_endret_av ) %]<li><span class="label">Last changed by:</span> [% p.sist_endret_av | html_entity %]</li>[% END %]
[% IF ( p.gyldig_til ) %]<li><span class="label">Valid until:</span> [% p.gyldig_til | html_entity %]</li>[% END %]
[% IF ( p.prim_kontakt ) %]<li><span class="label">Primary contact:</span> [% p.prim_kontakt | html_entity %]</li>[% END %]
</ol>
<form action="nl-search.pl" method="POST">
<input type="hidden" name="op" value="save" />
<input type="hidden" name="navn" value="[% p.navn | html_entity %]" />
<input type="hidden" name="kjonn" value="[% p.kjonn | html_entity %]" />
<input type="hidden" name="fdato" value="[% p.fdato | html_entity %]" />
<input type="hidden" name="lnr" value="[% p.lnr | html_entity %]" />
<input type="hidden" name="fnr_hash" value="[% p.fnr_hash | html_entity %]" />
<input type="hidden" name="p_adresse1" value="[% p.p_adresse1 | html_entity %]" />
<input type="hidden" name="p_adresse2" value="[% p.p_adresse2 | html_entity %]" />
<input type="hidden" name="p_postnr" value="[% p.p_postnr | html_entity %]" />
<input type="hidden" name="p_sted" value="[% p.p_sted | html_entity %]" />
<input type="hidden" name="p_land" value="[% p.p_land | html_entity %]" />
<input type="hidden" name="p_sjekk" value="[% p.p_sjekk | html_entity %]" />
<input type="hidden" name="m_adresse1" value="[% p.m_adresse1 | html_entity %]" />
<input type="hidden" name="m_adresse2" value="[% p.m_adresse2 | html_entity %]" />
<input type="hidden" name="m_postnr" value="[% p.m_postnr | html_entity %]" />
<input type="hidden" name="m_sted" value="[% p.m_sted | html_entity %]" />
<input type="hidden" name="m_land" value="[% p.m_land | html_entity %]" />
<input type="hidden" name="m_sjekk" value="[% p.m_sjekk | html_entity %]" />
<input type="hidden" name="m_gyldig_til" value="[% p.m_gyldig_til | html_entity %]" />
<input type="hidden" name="pin" value="[% p.pin | html %]" />
<input type="hidden" name="passord" value="[% p.passord | html_entity %]" />
<input type="hidden" name="feide" value="[% p.feide | html_entity %]" />
<input type="hidden" name="folkeregsjekk_dato" value="[% p.folkeregsjekk_dato | html_entity %]" />
<input type="hidden" name="hjemmebibliotek" value="[% p.hjemmebibliotek | html_entity %]" />
<input type="hidden" name="opprettet" value="[% p.opprettet | html_entity %]" />
<input type="hidden" name="opprettet_av" value="[% p.opprettet_av | html_entity %]" />
<input type="hidden" name="sist_endret" value="[% p.sist_endret | html_entity %]" />
<input type="hidden" name="sist_endret_av" value="[% p.sist_endret_av | html_entity %]" />
<input type="hidden" name="gyldig_til" value="[% p.gyldig_til | html_entity %]" />
<input type="hidden" name="epost" value="[% p.epost | html_entity %]" />
<input type="hidden" name="epost_sjekk" value="[% p.epost_sjekk | html_entity %]" />
<input type="hidden" name="tlf_mobil" value="[% p.tlf_mobil | html_entity %]" />
<input type="hidden" name="tlf_hjemme" value="[% p.tlf_hjemme | html_entity %]" />
<input type="hidden" name="tlf_jobb" value="[% p.tlf_jobb | html_entity %]" />
<input type="hidden" name="prim_kontakt" value="[% p.prim_kontakt | html_entity %]" />
<input type="submit" value="Import this patron" />
as
<select name="categorycode">
[% FOREACH c IN categories %]
<option value="[% c.categorycode | html %]">[% c.description | html %]</option>
[% END %]
</select>
</form>
</div>
[% END %]

View File

@ -1,4 +1,4 @@
/* global borrowernumber advsearch dateformat _ CAN_user_borrowers_edit_borrowers NorwegianPatronDBEnable number_of_adult_categories destination */
/* global borrowernumber advsearch dateformat _ CAN_user_borrowers_edit_borrowers number_of_adult_categories destination */
$(document).ready(function(){
$("#filteraction_off, #filteraction_on").on('click', function(e) {
@ -31,27 +31,9 @@ $(document).ready(function(){
});
if( CAN_user_borrowers_edit_borrowers ){
if( NorwegianPatronDBEnable == 1 ){
$("#deletepatronlocal").click(function(){
confirm_local_deletion();
$(".btn-group").removeClass("open");
return false;
});
$("#deletepatronremote").click(function(){
confirm_remote_deletion();
$(".btn-group").removeClass("open");
return false;
});
$("#deletepatronboth").click(function(){
confirm_both_deletion();
$(".btn-group").removeClass("open");
return false;
});
} else {
$("#deletepatron").click(function(){
window.location='/cgi-bin/koha/members/deletemem.pl?member=' + borrowernumber;
});
}
$("#deletepatron").click(function(){
window.location='/cgi-bin/koha/members/deletemem.pl?member=' + borrowernumber;
});
$("#renewpatron").click(function(){
confirm_reregistration();
$(".btn-group").removeClass("open");
@ -101,24 +83,6 @@ $(document).ready(function(){
$("#borrower_message").val( $(this).val() );
});
});
function confirm_local_deletion() {
var is_confirmed = window.confirm(_("Are you sure you want to delete this patron from the local database? This cannot be undone."));
if (is_confirmed) {
window.location='/cgi-bin/koha/members/deletemem.pl?member=' + borrowernumber + '&deletelocal=true&deleteremote=false';
}
}
function confirm_remote_deletion() {
var is_confirmed = window.confirm(_("Are you sure you want to delete this patron from the Norwegian national patron database? This cannot be undone."));
if (is_confirmed) {
window.location='/cgi-bin/koha/members/deletemem.pl?member=' + borrowernumber + '&deletelocal=false&deleteremote=true';
}
}
function confirm_both_deletion() {
var is_confirmed = window.confirm(_("Are you sure you want to delete this patron both from the local database and from the Norwegian national patron database? This cannot be undone."));
if (is_confirmed) {
window.location='/cgi-bin/koha/members/deletemem.pl?member=' + borrowernumber + '&deletelocal=true&deleteremote=true';
}
}
function confirm_updatechild() {
var is_confirmed = window.confirm(_("Are you sure you want to update this child to an Adult category? This cannot be undone."));

View File

@ -28,15 +28,10 @@ use C4::Context;
use C4::Output;
use C4::Auth;
use C4::Members;
use Module::Load;
use Koha::Patrons;
use Koha::Token;
use Koha::Patron::Categories;
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
load Koha::NorwegianPatronDB, qw( NLMarkForDeletion NLSync );
}
my $input = new CGI;
my ($template, $loggedinuser, $cookie)
@ -61,20 +56,6 @@ my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in"
my $patron = Koha::Patrons->find( $member );
output_and_exit_if_error( $input, $cookie, $template, { module => 'members', logged_in_user => $logged_in_user, current_patron => $patron } );
# Handle deletion from the Norwegian national patron database, if it is enabled
# If the "deletelocal" parameter is set to "false", the regular deletion will be
# short circuited, and only a deletion from the national database can be carried
# out. If "deletelocal" is set to "true", or not set to anything normal
# deletion will be done.
my $deletelocal = $input->param('deletelocal') eq 'false' ? 0 : 1; # Deleting locally is the default
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
if ( $input->param('deleteremote') eq 'true' ) {
# Mark for deletion, then try a live sync
NLMarkForDeletion( $member );
NLSync({ 'borrowernumber' => $member });
}
}
my $charges = $patron->account->non_issues_charges;
my $countissues = $patron->checkouts->count;
my $userenv = C4::Context->userenv;
@ -104,7 +85,7 @@ if (C4::Context->preference("IndependentBranches")) {
my $op = $input->param('op') || 'delete_confirm';
my $dbh = C4::Context->dbh;
my $is_guarantor = $dbh->selectrow_array("SELECT COUNT(*) FROM borrowers WHERE guarantorid=?", undef, $member);
if ( $op eq 'delete_confirm' or $countissues > 0 or $charges or $is_guarantor or $deletelocal == 0) {
if ( $op eq 'delete_confirm' or $countissues > 0 or $charges or $is_guarantor ) {
$template->param(
patron => $patron,
@ -118,11 +99,9 @@ if ( $op eq 'delete_confirm' or $countissues > 0 or $charges or $is_guarantor or
if ($is_guarantor) {
$template->param(guarantees => 1);
}
if ($deletelocal == 0) {
$template->param(keeplocal => 1);
}
# This is silly written but reflect the same conditions as above
if ( not $countissues > 0 and not $charges and not $is_guarantor and not $deletelocal == 0 ) {
if ( not $countissues > 0 and not $charges and not $is_guarantor ) {
$template->param(
op => 'delete_confirm',
csrf_token => Koha::Token->new->generate_csrf({ session_id => scalar $input->cookie('CGISESSID') }),

View File

@ -48,10 +48,6 @@ use Koha::Patron::HouseboundRole;
use Koha::Patron::HouseboundRoles;
use Koha::Token;
use Email::Valid;
use Module::Load;
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
load Koha::NorwegianPatronDB, qw( NLGetSyncDataFromBorrowernumber );
}
use Koha::SMS::Providers;
use vars qw($debug);
@ -483,10 +479,6 @@ if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){
if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template, 1, $newdata{'categorycode'});
}
# Try to do the live sync with the Norwegian national patron database, if it is enabled
if ( exists $data{'borrowernumber'} && C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
NLSync({ 'borrowernumber' => $borrowernumber });
}
# Create HouseboundRole if necessary.
# Borrower did not exist, so HouseboundRole *cannot* yet exist.
@ -599,15 +591,6 @@ if ($op eq "modify") {
if ( $step == 4 ) {
$template->param( categorycode => $borrower_data->{'categorycode'} );
}
# Add sync data to the user data
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
my $sync = NLGetSyncDataFromBorrowernumber( $borrowernumber );
if ( $sync ) {
$template->param(
sync => $sync->sync,
);
}
}
}
if ( $op eq "duplicate" ) {
$template->param( updtype => 'I' );

View File

@ -55,10 +55,6 @@ use Koha::AuthorisedValues;
use Koha::CsvProfiles;
use Koha::Patron::Debarments qw(GetDebarments);
use Koha::Patron::Messages;
use Module::Load;
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
load Koha::NorwegianPatronDB, qw( NLGetSyncDataFromBorrowernumber );
}
#use Smart::Comments;
#use Data::Dumper;
use DateTime;
@ -241,16 +237,6 @@ if ($borrowernumber) {
->count( { borrowernumber => $borrowernumber } ) );
}
# Add sync data to the user data
if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
my $sync = NLGetSyncDataFromBorrowernumber( $borrowernumber );
if ( $sync ) {
$data->{'sync'} = $sync->sync;
$data->{'syncstatus'} = $sync->syncstatus;
$data->{'lastsync'} = $sync->lastsync;
}
}
# Generate CSRF token for upload and delete image buttons
$template->param(
csrf_token => Koha::Token->new->generate_csrf({ session_id => $input->cookie('CGISESSID'),}),

View File

@ -1,167 +0,0 @@
#!/usr/bin/perl
# Copyright 2013 Oslo Public Library
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
=head1 NAME
nl-search.pl - Script for searching the Norwegian national patron database
=head1 DESCRIPTION
This script will search the Norwegian national patron database, and let staff
import patrons from the natial database into the local database.
In order to use this, a username/password from the Norwegian national database
of libraries ("Base Bibliotek") is needed. A special key is also needed, in
order to decrypt and encrypt PIN-codes/passwords.
See http://www.lanekortet.no/ for more information (in Norwegian).
=cut
use Modern::Perl;
use CGI;
use C4::Auth;
use C4::Context;
use C4::Output;
use C4::Members::Attributes qw( SetBorrowerAttributes );
use C4::Utils::DataTables::Members;
use Koha::NorwegianPatronDB qw( NLCheckSysprefs NLSearch NLDecodePin NLGetFirstname NLGetSurname NLSync );
use Koha::Database;
use Koha::DateUtils;
use Koha::Patrons;
use Koha::Patron::Categories;
my $cgi = CGI->new;
my $dbh = C4::Context->dbh;
my $op = $cgi->param('op');
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
template_name => "members/nl-search.tt",
query => $cgi,
type => "intranet",
authnotrequired => 0,
flagsrequired => { borrowers => 'edit_borrowers' },
debug => 1,
}
);
my $userenv = C4::Context->userenv;
# Check sysprefs
my $check_result = NLCheckSysprefs();
if ( $check_result->{'error'} == 1 ) {
$template->param( 'error' => $check_result );
output_html_with_http_headers $cgi, $cookie, $template->output;
exit 0;
}
if ( $op && $op eq 'search' ) {
# Get the string we are searching for
my $identifier = $cgi->param('q');
if ( $identifier ) {
# Local search
my $local_results = C4::Utils::DataTables::Members::search(
{
searchmember => $identifier,
dt_params => { iDisplayLength => -1 },
}
)->{patrons};
$template->param( 'local_result' => $local_results );
# Search NL, unless we got at least one hit and further searching is
# disabled
if ( scalar @{ $local_results } == 0 || C4::Context->preference("NorwegianPatronDBSearchNLAfterLocalHit") == 1 ) {
# TODO Check the format of the identifier before searching NL
my $result = NLSearch( $identifier );
unless ($result->fault) {
my $r = $result->result();
my $categories = Koha::Patron::Categories->search_limited;
$template->param(
'result' => $r,
'categories' => $categories,
);
} else {
$template->param( 'error' => join ', ', $result->faultcode, $result->faultstring, $result->faultdetail );
}
}
$template->param( 'q' => $identifier );
}
} elsif ( $op && $op eq 'save' ) {
# This is where we map from fields in NL to fields in Koha
my %borrower = (
'surname' => NLGetSurname( $cgi->param('navn') ),
'firstname' => NLGetFirstname( $cgi->param('navn') ),
'sex' => scalar $cgi->param('kjonn'),
'dateofbirth' => scalar $cgi->param('fdato'),
'cardnumber' => scalar $cgi->param('lnr'),
'userid' => scalar $cgi->param('lnr'),
'address' => scalar $cgi->param('p_adresse1'),
'address2' => scalar $cgi->param('p_adresse2'),
'zipcode' => scalar $cgi->param('p_postnr'),
'city' => scalar $cgi->param('p_sted'),
'country' => scalar $cgi->param('p_land'),
'B_address' => scalar $cgi->param('m_adresse1'),
'B_address2' => scalar $cgi->param('m_adresse2'),
'B_zipcode' => scalar $cgi->param('m_postnr'),
'B_city' => scalar $cgi->param('m_sted'),
'B_country' => scalar $cgi->param('m_land'),
'password' => NLDecodePin( $cgi->param('pin') ),
'dateexpiry' => scalar $cgi->param('gyldig_til'),
'email' => scalar $cgi->param('epost'),
'mobile' => scalar $cgi->param('tlf_mobil'),
'phone' => scalar $cgi->param('tlf_hjemme'),
'phonepro' => scalar $cgi->param('tlf_jobb'),
'branchcode' => $userenv->{'branch'},
'categorycode' => scalar $cgi->param('categorycode'),
);
# Add the new patron
my $patron = eval { Koha::Patron->new(\%borrower)->store; };
unless ( $@) {
my $borrowernumber = $patron->borrowernumber;
# Add extended patron attributes
SetBorrowerAttributes($borrowernumber, [
{ code => 'fnr', value => scalar $cgi->param('fnr_hash') },
], 'no_branch_limit' );
# Override the default sync data created by Koha::Patron->store
my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
'synctype' => 'norwegianpatrondb',
'borrowernumber' => $borrowernumber,
});
$borrowersync->update({ 'syncstatus', 'synced' });
$borrowersync->update({ 'lastsync', $cgi->param('sist_endret') });
$borrowersync->update({ 'hashed_pin', $cgi->param('pin') });
# Try to sync in real time. If this fails it will be picked up by the cronjob
NLSync({ 'borrowernumber' => $borrowernumber });
# Redirect to the edit screen
print $cgi->redirect( "/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=$borrowernumber" );
} else {
$template->param( 'error' => 'COULD_NOT_ADD_PATRON' );
}
}
output_html_with_http_headers $cgi, $cookie, $template->output;
=head1 AUTHOR
Magnus Enger <digitalutvikling@gmail.com>
=cut

View File

@ -1,202 +0,0 @@
#!/usr/bin/perl
# Copyright 2014 Oslo Public Library
=head1 NAME
nl-sync-from-koha.pl - Sync patrons from Koha to the Norwegian national patron database (NL).
=head1 SYNOPSIS
perl nl-sync-from-koha.pl -v --run
=cut
use Koha::NorwegianPatronDB qw( NLCheckSysprefs NLSync );
use Koha::Database;
use Getopt::Long;
use Pod::Usage;
use Modern::Perl;
# Get options
my ( $run, $verbose, $debug ) = get_options();
=head1 ACTIONS
=head2
Find local patrons that have been changed and need to be sent upstream to NL.
These patrons will be distinguished by two borrower attributes:
=over 4
=item * The "nlstatus" attribute will have a value of "needsync". (Which means
that the patron has been changed in Koha, but not yet successfully synced
upstream.)
=item * The "nlsync" attribute will have a value of 1. (Which means that this
patron has accepted to be synced with NL, as opposed to a value of 0 which
would indicate that the patron has asked not to be synced with NL.)
=back
=head1 STEPS
This script performs the following steps:
=head2 Check sysprefs
Check that the necessary sysprefs are set before proceeding.
=cut
my $check_result = NLCheckSysprefs();
if ( $check_result->{'error'} == 1 ) {
if ( $check_result->{'nlenabled'} == 0 ) { say "* Please activate this function with the NorwegianPatronDBEnable system preference." };
if ( $check_result->{'endpoint'} == 0 ) { say "* Please specify an endpoint with the NorwegianPatronDBEndpoint system preference." };
if ( $check_result->{'userpass'} == 0 ) { say "* Please fill in the NorwegianPatronDBUsername and NorwegianPatronDBPassword system preferences." };
exit 0;
}
unless ( $run ) {
say "* You have not specified --run, no real syncing will be done.";
}
=head2 Find patrons that need to be synced
Patrons with either of these statuses:
=over 4
=item * edited
=item * new
=item * deleted
=back
=cut
my @needs_sync = Koha::Database->new->schema->resultset('BorrowerSync')->search({
-and => [
sync => 1,
synctype => 'norwegianpatrondb',
-or => [
syncstatus => 'edited',
syncstatus => 'new',
syncstatus => 'delete',
],
],
});
=head2 Do the actual sync
Data is synced to NL with NLSync.
=cut
my $sync_success = 0;
my $sync_failed = 0;
foreach my $borrower ( @needs_sync ) {
my $cardnumber = $borrower->borrowernumber->cardnumber;
my $firstname = $borrower->borrowernumber->firstname;
my $surname = $borrower->borrowernumber->surname;
my $syncstatus = $borrower->syncstatus;
say "*** Syncing patron: $cardnumber - $firstname $surname ($syncstatus)" if $verbose;
if ( $run ) {
my $response = NLSync({ 'patron' => $borrower->borrowernumber });
if ( $response ) {
my $result = $response->result;
if ( $result->{'status'} && $result->{'status'} == 1 ) {
$sync_success++;
} else {
$sync_failed++;
}
if ( $result->{'melding'} && $verbose ) {
say $result->{'melding'};
}
}
}
}
=head2 Summarize if verbose mode is enabled
Specify -v on the command line to get a summary of the syncing operations.
=cut
if ( $verbose ) {
say "-----------------------------";
say "Sync succeeded: $sync_success";
say "Sync failed : $sync_failed";
}
=head1 OPTIONS
=over 4
=item B<-r, --run>
Actually carry out syncing operations. Without this option, the script will
only report what it would have done, but not change any data, locally or
remotely.
=item B<-v --verbose>
Report on the progress of the script.
=item B<-d --debug>
Even more output.
=item B<-h, -?, --help>
Prints this help message and exits.
=back
=cut
sub get_options {
# Options
my $run = '',
my $verbose = '';
my $debug = '';
my $help = '';
GetOptions (
'r|run' => \$run,
'v|verbose' => \$verbose,
'd|debug' => \$debug,
'h|?|help' => \$help
);
pod2usage( -exitval => 0 ) if $help;
return ( $run, $verbose, $debug );
}
=head1 AUTHOR
Magnus Enger <digitalutvikling@gmail.com>
=head1 COPYRIGHT
Copyright 2014 Oslo Public Library
=head1 LICENSE
This file is part of Koha.
Koha is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation;
either version 3 of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public License along with
Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
Fifth Floor, Boston, MA 02110-1301 USA.
=cut

View File

@ -1,186 +0,0 @@
#!/usr/bin/perl
# Copyright 2014 Oslo Public Library
=head1 NAME
nl-sync-to-koha.pl - Sync patrons from the Norwegian national patron database (NL) to Koha.
=head1 SYNOPSIS
perl nl-sync-to-koha.pl -v --run
=cut
use C4::Members::Attributes qw( UpdateBorrowerAttribute );
use Koha::NorwegianPatronDB qw( NLCheckSysprefs NLGetChanged );
use Koha::Patrons;
use Koha::Database;
use Getopt::Long;
use Pod::Usage;
use Modern::Perl;
# Get options
my ( $run, $from, $verbose, $debug ) = get_options();
my $check_result = NLCheckSysprefs();
if ( $check_result->{'error'} == 1 ) {
if ( $check_result->{'nlenabled'} == 0 ) { say "* Please activate this function with the NorwegianPatronDBEnable system preference." };
if ( $check_result->{'endpoint'} == 0 ) { say "* Please specify an endpoint with the NorwegianPatronDBEndpoint system preference." };
if ( $check_result->{'userpass'} == 0 ) { say "* Please fill in the NorwegianPatronDBUsername and NorwegianPatronDBPassword system preferences." };
exit 0;
}
unless ( $run ) {
say "* You have not specified --run, no real syncing will be done.";
}
# Do the sync
my $sync_success = 0;
my $sync_failed = 0;
my $skipped_local_change = 0;
# Get the borrowers that have been changed
my $result = NLGetChanged( $from );
if ( $verbose ) {
say 'Number of records: ' . $result->{'antall_poster_returnert'};
say 'Number of hits: ' . $result->{'antall_treff'};
say 'Message: ' . $result->{'melding'};
say 'Status: ' . $result->{'status'};
say 'Server time: ' . $result->{'server_tid'};
say "-----------------------------";
}
# Loop through the patrons
foreach my $patron ( @{ $result->{'kohapatrons'} } ) {
if ( $verbose ) {
if ( $patron->{'surname'} ) {
say "*** Name: " . $patron->{'surname'};
} else {
say "*** No name";
}
say 'Created by: ' . $patron->{'_extra'}->{'created_by'};
say 'Last change by: ' . $patron->{'_extra'}->{'last_change_by'};
}
# Only sync in changes made by other libraries
if ( C4::Context->preference("NorwegianPatronDBUsername") ne $patron->{'_extra'}->{'last_change_by'} ) {
# Make a copy of the data in the hashref and store it as a hash
my %clean_patron = %$patron;
# Delete the extra data from the copy of the hashref
delete $clean_patron{'_extra'};
# Find the borrowernumber based on cardnumber
my $stored_patron = Koha::Patrons->find({ cardnumber => $patron->{cardnumber} });
my $borrowernumber = $stored_patron->borrowernumber;
if ( $run ) {
# FIXME Exceptions must be caught here
if ( $stored_patron->set(\%clean_patron)->store ) {
# Get the sync object
my $sync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
'synctype' => 'norwegianpatrondb',
'borrowernumber' => $borrowernumber,
});
# Update the syncstatus to 'synced'
$sync->update( { 'syncstatus' => 'synced' } );
# Update the 'synclast' attribute with the "server time" ("server_tid") returned by the method
$sync->update( { 'lastsync' => $result->{'result'}->{'server_tid'} } );
# Save social security number as attribute
UpdateBorrowerAttribute(
$borrowernumber,
{ code => 'fnr', attribute => $patron->{'_extra'}->{'socsec'} },
);
$sync_success++;
} else {
$sync_failed++;
}
}
} else {
say "Skipped, local change" if $verbose;
$skipped_local_change++;
}
}
if ( $verbose ) {
say "-----------------------------";
say "Sync succeeded: $sync_success";
say "Sync failed : $sync_failed";
say "Skipped local change: $skipped_local_change";
}
=head1 OPTIONS
=over 4
=item B<-r, --run>
Actually carry out syncing operations. Without this option, the script will
only report what it would have done, but not change any data, locally or
remotely.
=item B<-v --verbose>
Report on the progress of the script.
=item B<-f --from>
Date and time to sync from, if this should be different from "1 second past
midnight of the day before". The date should be in this format:
2014-06-03T00:00:01
=item B<-d --debug>
Even more output.
=item B<-h, -?, --help>
Prints this help message and exits.
=back
=cut
sub get_options {
# Options
my $run = '',
my $from = '',
my $verbose = '';
my $debug = '';
my $help = '';
GetOptions (
'r|run' => \$run,
'f|from=s' => \$from,
'v|verbose' => \$verbose,
'd|debug' => \$debug,
'h|?|help' => \$help
);
pod2usage( -exitval => 0 ) if $help;
return ( $run, $from, $verbose, $debug );
}
=head1 AUTHOR
Magnus Enger <digitalutvikling@gmail.com>
=head1 COPYRIGHT
Copyright 2014 Oslo Public Library
=head1 LICENSE
This file is part of Koha.
Koha is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation;
either version 3 of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public License along with
Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
Fifth Floor, Boston, MA 02110-1301 USA.
=cut

View File

@ -75,11 +75,7 @@ sub is_testable {
my ($module_name) = @_;
my @needed_module_names;
my $return_value = 1;
if ( $module_name =~ /Koha::NorwegianPatronDB/xsm ) {
@needed_module_names =
( 'SOAP::Lite', 'Crypt::GCrypt', 'Digest::SHA', 'Convert::BaseN' );
}
elsif ( $module_name =~ /Koha::SearchEngine::Elasticsearch::Indexer/xsm ) {
if ( $module_name =~ /Koha::SearchEngine::Elasticsearch::Indexer/xsm ) {
@needed_module_names =
( 'Catmandu::Importer::MARC', 'Catmandu::Store::ElasticSearch' );
}

View File

@ -1,599 +0,0 @@
#!/usr/bin/perl
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use Test::More;
use Test::MockModule;
use t::lib::Mocks;
use Data::Dumper;
# Check that all the modules we need are installed, or bail out
BEGIN {
my $missing_lib;
eval {
require Test::DBIx::Class;
1;
} or do {
$missing_lib = "Test::DBIx::Class";
};
eval {
require SOAP::Lite;
1;
} or do {
$missing_lib = "SOAP::Lite";
};
eval {
require Crypt::GCrypt;
1;
} or do {
$missing_lib = "Crypt::GCrypt";
};
eval {
require Convert::BaseN;
1;
} or do {
$missing_lib = "Convert::BaseN";
};
if ( $missing_lib ) {
plan skip_all => $missing_lib . " is not available.";
} else {
# Everything good
plan tests => 73;
}
}
use Test::DBIx::Class {}, 'Borrower', 'BorrowerSync'; #Also loads those modules.
# Make the code in the module use our mocked Koha::Schema/Koha::Database
my $db = Test::MockModule->new('Koha::Database');
$db->mock(
# Schema() gives us the DB connection set up by Test::DBIx::Class
_new_schema => sub { return Schema(); }
);
fixtures_ok [
'Borrower' => [
[qw/firstname surname borrowernumber address city/],
['Test', 'Borrower', 1, 'Test road', 'Test city'],
['Test', 'Borrower', 2, 'Test road', 'Test city'],
['Test', 'Borrower', 3, 'Test road', 'Test city'],
['Test', 'Borrower', 4, 'Test road', 'Test city'],
],
'BorrowerSync' => [
[qw/borrowernumber sync syncstatus lastsync hashed_pin synctype/],
[1, 1, 'new', '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
[2, 1, 'edited', '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
[3, 1, 'new', '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
[4, 1, 'new', '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
],
], 'installed some fixtures';
=head1 LOADING THE MODULE
=cut
BEGIN { use_ok( 'Koha::NorwegianPatronDB', ':all' ) }
=head1 UTILITY SUBROUTINES
=head2 NLCheckSysprefs
Relevant sysprefs:
=over 4
=item * NorwegianPatronDBEnable
=item * NorwegianPatronDBEndpoint
=item * NorwegianPatronDBUsername
=item * NorwegianPatronDBPassword
=back
=cut
BEGIN {
t::lib::Mocks::mock_config('nlkey', 'key');
t::lib::Mocks::mock_config('nlvendoruser', 'user');
t::lib::Mocks::mock_config('nlvendorpass', 'pass');
}
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable', 0);
t::lib::Mocks::mock_preference('NorwegianPatronDBEndpoint', '');
t::lib::Mocks::mock_preference('NorwegianPatronDBUsername', '');
t::lib::Mocks::mock_preference('NorwegianPatronDBPassword', '');
ok( my $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
is( $result->{ 'error' }, 1, 'error detected' );
is( $result->{ 'nlenabled' }, 0, 'NL is not enabled' );
is( $result->{ 'endpoint' }, 0, 'an endpoint is not specified' );
is( $result->{ 'userpass' }, 0, 'username and/or password is missing' );
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable', 1);
ok( $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
is( $result->{ 'error' }, 1, 'error detected' );
is( $result->{ 'nlenabled' }, 1, 'NL is enabled' );
is( $result->{ 'endpoint' }, 0, 'an endpoint is not specified' );
is( $result->{ 'userpass' }, 0, 'username and/or password is missing' );
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable', 0);
t::lib::Mocks::mock_preference('NorwegianPatronDBUsername', 'user');
t::lib::Mocks::mock_preference('NorwegianPatronDBPassword', 'pass');
ok( $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
is( $result->{ 'error' }, 1, 'error detected' );
is( $result->{ 'nlenabled' }, 0, 'NL is not enabled' );
is( $result->{ 'endpoint' }, 0, 'an endpoint is not specified' );
is( $result->{ 'userpass' }, 1, 'username and/or password is present' );
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable', 1);
t::lib::Mocks::mock_preference('NorwegianPatronDBEndpoint', 'http://example.com/');
ok( $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
is( $result->{ 'error' }, 0, 'no error detected' );
is( $result->{ 'nlenabled' }, 1, 'NL is enabled' );
is( $result->{ 'endpoint' }, 1, 'an endpoint is specified' );
is( $result->{ 'userpass' }, 1, 'username and/or password is present' );
=head2 NLGetFirstname and NLGetSurname
=cut
my $firstname = 'Firstname';
my $surname = 'Surname';
my $fullname = "$surname, $firstname";
my $wrongname = "$surname $firstname";
is( NLGetFirstname( $fullname ), $firstname, 'can get firstname from name' );
is( NLGetSurname( $fullname ), $surname, 'can get surname from name' );
is( NLGetFirstname( $wrongname ), $wrongname, 'returns full string when name misses comma' );
is( NLGetSurname( $wrongname ), $wrongname, 'returns full string when name misses comma' );
=head2 NLDecodePin and NLEncryptPIN
=cut
my $pin = '1234';
my $hash = NLEncryptPIN( $pin );
is( NLEncryptPIN( $pin ), $hash, 'NLEncryptPIN works' );
is( NLDecodePin( $hash ), $pin, 'NLDecodePin works' );
=head2 NLUpdateHashedPIN
=cut
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('hashed_pin'), 'abc', 'hashed_pin is "abc"' );
# Set a new pin
my $new_pin = 'bcd';
ok( NLUpdateHashedPIN( 1, $new_pin ), 'NLUpdateHashedPIN runs ok' );
# Hash the new pin and compare it to the one stored in the database
my $hashed_pin = Koha::NorwegianPatronDB::_encrypt_pin( $new_pin );
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('hashed_pin'), $hashed_pin, 'hashed_pin was updated' );
=head2 NLMarkForDeletion
=cut
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('syncstatus'), 'new', 'syncstatus is "new"' );
ok( NLMarkForDeletion( 3 ), 'NLMarkForDeletion runs ok' );
# Check that the syncstatus was updated. Note: We will use this status later, to check syncing of deleted borrowers
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('syncstatus'), 'delete', 'syncstatus is "delete"' );
=head2 NLGetSyncDataFromBorrowernumber
=cut
ok( my $sync_data = NLGetSyncDataFromBorrowernumber( 1 ), 'NLGetSyncDataFromBorrowernumber runs ok' );
isa_ok( $sync_data, 'Koha::Schema::Result::BorrowerSync' );
is( $sync_data->sync, 1, 'the sync is on' );
is( $sync_data->syncstatus, 'new', 'syncstatus is "new"' );
is( $sync_data->lastsync, '2014-03-31T12:35:14', 'lastsync is ok' );
is( $sync_data->hashed_pin, $hashed_pin, 'hashed_pin is ok' );
=head1 SUBROUTINES THAT TALK TO SOAP
=head2 NLSearch
=cut
my $lite = Test::MockModule->new('SOAP::Lite');
# Mock a successfull call to the "hent" method
$lite->mock(
hent => sub { return SOAP::Deserializer->deserialize( hent_success() )->result; }
);
ok( my $res = NLSearch( '12345678910' ), 'successfull call to NLSearch' );
is( $res->{'antall_poster_returnert'}, 1, 'got 1 record' );
isa_ok( $res, "Resultat" );
isa_ok( $res->{'respons_poster'}, "LaanerListe" );
isa_ok( $res->{'respons_poster'}[0], "Laaner" );
# Mock an unsuccessfull call to the "hent" method
$lite->mock(
hent => sub { return SOAP::Deserializer->deserialize( hent_failure() )->result; }
);
ok( $res = NLSearch( '12345678910' ), 'call to NLSearch with an illegal argument' );
is( $res->{'antall_poster_returnert'}, 0, 'got 0 records' );
isa_ok( $res, "Resultat" );
like( $res->{'melding'}, qr/Ulovlig argument: hverken LNR eller FNR_HASH/, "got expected error message for an illegal identifier" );
=head2 NLSync
=head3 New patron
=cut
my $borrower = Borrower->find({ 'borrowernumber' => 1 });
$lite->mock(
nyPost => sub { return SOAP::Deserializer->deserialize( nyPost_success() )->result; }
);
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('syncstatus'), 'new', 'patron is new' );
ok ( $result = NLSync({ 'patron' => $borrower }), 'successfull call to NLSync via patron ("nyPost")' );
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('syncstatus'), 'synced', 'patron is synced' );
# Now do the same test, but pass in a borrowernumber, not a Koha::Schema::Result::Borrower
is ( BorrowerSync->find({ 'borrowernumber' => 4 })->get_column('syncstatus'), 'new', 'patron is new' );
ok ( $result = NLSync({ 'borrowernumber' => 4 }), 'successfull call to NLSync via borrowernumber ("nyPost")' );
is ( BorrowerSync->find({ 'borrowernumber' => 4 })->get_column('syncstatus'), 'synced', 'patron is synced' );
=head3 Edited patron
=cut
ok ( $borrower = Borrower->find({ 'borrowernumber' => 2 }), 'find our "edited" mock patron' );
$lite->mock(
endre => sub { return SOAP::Deserializer->deserialize( endre_success() )->result; }
);
is ( BorrowerSync->find({ 'borrowernumber' => 2 })->get_column('syncstatus'), 'edited', 'patron is edited' );
ok ( $result = NLSync({ 'patron' => $borrower }), 'successfull call to NLSync ("endre")' );
is ( BorrowerSync->find({ 'borrowernumber' => 2 })->get_column('syncstatus'), 'synced', 'patron is synced' );
=head3 Deleted patron
=cut
ok ( $borrower = Borrower->find({ 'borrowernumber' => 3 }), 'find our "deleted" mock patron' );
$lite->mock(
slett => sub { return SOAP::Deserializer->deserialize( endre_success() )->result; }
);
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('syncstatus'), 'delete', 'patron is marked for deletion' );
ok ( $result = NLSync({ 'patron' => $borrower }), 'successfull call to NLSync ("slett")' );
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('sync'), 0, 'sync is now disabled' );
=head2 NLGetChanged
=cut
# Mock a successfull call to the "soekEndret" method
$lite->mock(
soekEndret => sub { return SOAP::Deserializer->deserialize( soekEndret_success() ); }
);
ok( $res = NLGetChanged(), 'successfull call to NLGetChanged - 2 results' );
is( $res->{'melding'}, 'OK', 'got "OK"' );
is( $res->{'antall_poster_returnert'}, 2, 'got 2 records' );
isa_ok( $res, "Resultat" );
isa_ok( $res->{'respons_poster'}, "LaanerListe" );
isa_ok( $res->{'respons_poster'}[0], "Laaner" );
# Mock a successfull call to the "soekEndret" method, but with zero new records
$lite->mock(
soekEndret => sub { return SOAP::Deserializer->deserialize( soekEndret_zero_new() ); }
);
ok( $res = NLGetChanged(), 'successfull call to NLGetChanged - 0 results' );
is( $res->{'melding'}, 'ingen treff', 'got "ingen treff"' );
is( $res->{'antall_poster_returnert'}, 0, 'got 0 records' );
is( $res->{'antall_treff'}, 0, 'got 0 records' );
=head1 SAMPLE SOAP XML RESPONSES
These responses can be gathered by setting "outputxml()" to true on the SOAP
client:
my $client = SOAP::Lite
->on_action( sub { return '""';})
->uri('http://lanekortet.no')
->proxy('https://fl.lanekortet.no/laanekort/fl_test.php')
->outputxml(1);
my $response = $client->slett( $x );
say $response;
Pretty formatting can be achieved by piping the output from a test script
through xmllint:
perl my_test_script.pl > xmllint --format -
=cut
sub slett_success {
return <<'ENDRESPONSE';
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://lanekortet.no" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:slettResponse>
<return xsi:type="ns1:Svar">
<status xsi:type="xsd:boolean">true</status>
<melding xsi:type="xsd:string">Test Testersen (1973-08-11) er slettet fra registeret</melding>
<lnr xsi:type="xsd:string">N000106188</lnr>
<server_tid xsi:type="xsd:string">2014-06-02T16:51:58</server_tid>
</return>
</ns1:slettResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
ENDRESPONSE
}
sub endre_success {
return <<'ENDRESPONSE';
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://lanekortet.no" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:endreResponse>
<return xsi:type="ns1:Svar">
<status xsi:type="xsd:boolean">true</status>
<melding xsi:type="xsd:string">Oppdaterte felt: navn, p_adresse1, p_postnr, p_sted, p_land, fdato, fnr_hash, kjonn, pin, sist_endret, sist_endret_av</melding>
<lnr xsi:type="xsd:string">N000106188</lnr>
<server_tid xsi:type="xsd:string">2014-06-02T16:42:32</server_tid>
</return>
</ns1:endreResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
ENDRESPONSE
}
sub nyPost_success {
return <<'ENDRESPONSE';
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://lanekortet.no" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:nyPostResponse>
<return xsi:type="ns1:Svar">
<status xsi:type="xsd:boolean">true</status>
<melding xsi:type="xsd:string">Ny post er opprettet</melding>
<lnr xsi:type="xsd:string">N000106188</lnr>
<server_tid xsi:type="xsd:string">2014-06-02T14:10:09</server_tid>
</return>
</ns1:nyPostResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
ENDRESPONSE
}
sub soekEndret_success {
return <<'ENDRESPONSE';
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://lanekortet.no"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:soekEndretResponse>
<return xsi:type="ns1:Resultat">
<status xsi:type="xsd:boolean">true</status>
<melding xsi:type="xsd:string">OK</melding>
<antall_treff xsi:type="xsd:int">2</antall_treff>
<antall_poster_returnert xsi:type="xsd:int">2</antall_poster_returnert>
<neste_indeks xsi:type="xsd:int">0</neste_indeks>
<respons_poster SOAP-ENC:arrayType="ns1:Laaner[2]" xsi:type="ns1:LaanerListe">
<item xsi:type="ns1:Laaner">
<lnr xsi:type="xsd:string">N000106186</lnr>
<navn xsi:type="xsd:string">Hansen, Hanne</navn>
<p_adresse1 xsi:type="xsd:string"/>
<p_adresse2 xsi:type="xsd:string"/>
<p_postnr xsi:type="xsd:string"/>
<p_sted xsi:type="xsd:string">BØDØ</p_sted>
<p_land xsi:type="xsd:string">no</p_land>
<p_sjekk xsi:type="xsd:string">0</p_sjekk>
<m_adresse1 xsi:type="xsd:string"/>
<m_adresse2 xsi:type="xsd:string"/>
<m_postnr xsi:type="xsd:string"/>
<m_sted xsi:type="xsd:string"/>
<m_land xsi:type="xsd:string"/>
<m_sjekk xsi:type="xsd:string">0</m_sjekk>
<m_gyldig_til xsi:type="xsd:string">0000-00-00</m_gyldig_til>
<tlf_hjemme xsi:type="xsd:string"/>
<tlf_jobb xsi:type="xsd:string"/>
<tlf_mobil xsi:type="xsd:string"/>
<epost xsi:type="xsd:string"/>
<epost_sjekk xsi:type="xsd:string"/>
<prim_kontakt xsi:type="xsd:string"/>
<hjemmebibliotek xsi:type="xsd:string">5180401</hjemmebibliotek>
<fdato xsi:type="xsd:string">1994-04-08</fdato>
<fnr_hash xsi:type="xsd:string">11087395628</fnr_hash>
<kjonn xsi:type="xsd:string">F</kjonn>
<pin xsi:type="xsd:string">89308dfc85ee7a5826ae14e2d8efad1e</pin>
<passord xsi:type="xsd:string"/>
<feide xsi:type="xsd:string">0</feide>
<opprettet xsi:type="xsd:string">2014-04-28T15:20:38</opprettet>
<opprettet_av xsi:type="xsd:string">5180401</opprettet_av>
<sist_endret xsi:type="xsd:string">2014-04-28T15:20:38</sist_endret>
<sist_endret_av xsi:type="xsd:string">5180401</sist_endret_av>
<folkeregsjekk_dato xsi:type="xsd:string">0000-00-00</folkeregsjekk_dato>
</item>
<item xsi:type="ns1:Laaner">
<lnr xsi:type="xsd:string">N000106184</lnr>
<navn xsi:type="xsd:string">Enger, Magnus</navn>
<p_adresse1 xsi:type="xsd:string">Svarthammarveien 633333</p_adresse1>
<p_adresse2 xsi:type="xsd:string"/>
<p_postnr xsi:type="xsd:string">8015</p_postnr>
<p_sted xsi:type="xsd:string">Bodø</p_sted>
<p_land xsi:type="xsd:string">no</p_land>
<p_sjekk xsi:type="xsd:string">0</p_sjekk>
<m_adresse1 xsi:type="xsd:string"/>
<m_adresse2 xsi:type="xsd:string"/>
<m_postnr xsi:type="xsd:string"/>
<m_sted xsi:type="xsd:string"/>
<m_land xsi:type="xsd:string">no</m_land>
<m_sjekk xsi:type="xsd:string">0</m_sjekk>
<m_gyldig_til xsi:type="xsd:string">0000-00-00</m_gyldig_til>
<tlf_hjemme xsi:type="xsd:string">95158548</tlf_hjemme>
<tlf_jobb xsi:type="xsd:string"/>
<tlf_mobil xsi:type="xsd:string"/>
<epost xsi:type="xsd:string">magnus@enger.priv.no</epost>
<epost_sjekk xsi:type="xsd:string"/>
<prim_kontakt xsi:type="xsd:string"/>
<hjemmebibliotek xsi:type="xsd:string">5180401</hjemmebibliotek>
<fdato xsi:type="xsd:string">1973-08-11</fdato>
<fnr_hash xsi:type="xsd:string">11087345795</fnr_hash>
<kjonn xsi:type="xsd:string">M</kjonn>
<pin xsi:type="xsd:string">a632c504b8c4fba3149115cb07e0796c</pin>
<passord xsi:type="xsd:string"/>
<feide xsi:type="xsd:string">0</feide>
<opprettet xsi:type="xsd:string">2014-04-28T14:52:02</opprettet>
<opprettet_av xsi:type="xsd:string">5180401</opprettet_av>
<sist_endret xsi:type="xsd:string">2014-05-13T11:01:33</sist_endret>
<sist_endret_av xsi:type="xsd:string">5180401</sist_endret_av>
<folkeregsjekk_dato xsi:type="xsd:string">0000-00-00</folkeregsjekk_dato>
</item>
</respons_poster>
<server_tid xsi:type="xsd:string">2014-05-16T14:44:44</server_tid>
</return>
</ns1:soekEndretResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
ENDRESPONSE
}
sub soekEndret_zero_new {
return <<'ENDRESPONSE';
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://lanekortet.no" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:soekEndretResponse>
<return xsi:type="ns1:Resultat">
<status xsi:type="xsd:boolean">false</status>
<melding xsi:type="xsd:string">ingen treff</melding>
<antall_treff xsi:type="xsd:int">0</antall_treff>
<antall_poster_returnert xsi:type="xsd:int">0</antall_poster_returnert>
<neste_indeks xsi:type="xsd:int">0</neste_indeks>
<respons_poster SOAP-ENC:arrayType="ns1:Laaner[0]" xsi:type="ns1:LaanerListe"/>
<server_tid xsi:type="xsd:string">2014-05-20T13:02:02</server_tid>
</return>
</ns1:soekEndretResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
ENDRESPONSE
}
sub hent_failure {
return <<'ENDRESPONSE';
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://lanekortet.no"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:hentResponse>
<return xsi:type="ns1:Resultat">
<status xsi:type="xsd:boolean">false</status>
<melding xsi:type="xsd:string">hent: Ulovlig argument: hverken LNR eller FNR_HASH</melding>
<antall_treff xsi:type="xsd:int">0</antall_treff>
<antall_poster_returnert xsi:type="xsd:int">0</antall_poster_returnert>
<neste_indeks xsi:type="xsd:int">0</neste_indeks>
<respons_poster SOAP-ENC:arrayType="ns1:Laaner[0]" xsi:type="ns1:LaanerListe"/>
<server_tid xsi:type="xsd:string">2014-05-15T10:56:24</server_tid>
</return>
</ns1:hentResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
ENDRESPONSE
}
sub hent_success {
return <<'ENDRESPONSE';
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://lanekortet.no"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:hentResponse>
<return xsi:type="ns1:Resultat">
<status xsi:type="xsd:boolean">true</status>
<melding xsi:type="xsd:string">OK</melding>
<antall_treff xsi:type="xsd:int">1</antall_treff>
<antall_poster_returnert xsi:type="xsd:int">1</antall_poster_returnert>
<neste_indeks xsi:type="xsd:int">0</neste_indeks>
<respons_poster SOAP-ENC:arrayType="ns1:Laaner[1]" xsi:type="ns1:LaanerListe">
<item xsi:type="ns1:Laaner">
<lnr xsi:type="xsd:string">N000123456</lnr>
<navn xsi:type="xsd:string">Test, Testersen</navn>
<p_adresse1 xsi:type="xsd:string">Bibliotekveien 6</p_adresse1>
<p_adresse2 xsi:type="xsd:string"/>
<p_postnr xsi:type="xsd:string">1234</p_postnr>
<p_sted xsi:type="xsd:string">Lillevik</p_sted>
<p_land xsi:type="xsd:string">no</p_land>
<p_sjekk xsi:type="xsd:string">0</p_sjekk>
<m_adresse1 xsi:type="xsd:string"/>
<m_adresse2 xsi:type="xsd:string"/>
<m_postnr xsi:type="xsd:string"/>
<m_sted xsi:type="xsd:string"/>
<m_land xsi:type="xsd:string">no</m_land>
<m_sjekk xsi:type="xsd:string">0</m_sjekk>
<m_gyldig_til xsi:type="xsd:string">0000-00-00</m_gyldig_til>
<tlf_hjemme xsi:type="xsd:string"/>
<tlf_jobb xsi:type="xsd:string"/>
<tlf_mobil xsi:type="xsd:string">12345678</tlf_mobil>
<epost xsi:type="xsd:string">test@example.com</epost>
<epost_sjekk xsi:type="xsd:string">0</epost_sjekk>
<prim_kontakt xsi:type="xsd:string"/>
<hjemmebibliotek xsi:type="xsd:string">2060000</hjemmebibliotek>
<fdato xsi:type="xsd:string">1964-05-22</fdato>
<fnr_hash xsi:type="xsd:string">22056412345</fnr_hash>
<kjonn xsi:type="xsd:string">F</kjonn>
<pin xsi:type="xsd:string">g345abc123dab567abc78900abc123ab</pin>
<passord xsi:type="xsd:string"/>
<feide xsi:type="xsd:string"/>
<opprettet xsi:type="xsd:string">2005-10-20</opprettet>
<opprettet_av xsi:type="xsd:string">2060000</opprettet_av>
<sist_endret xsi:type="xsd:string">2013-05-13T13:51:24</sist_endret>
<sist_endret_av xsi:type="xsd:string">2060000</sist_endret_av>
<gyldig_til xsi:type="xsd:string"/>
<folkeregsjekk_dato xsi:type="xsd:string">0000-00-00</folkeregsjekk_dato>
</item>
</respons_poster>
<server_tid xsi:type="xsd:string">2014-01-07T14:43:18</server_tid>
</return>
</ns1:hentResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
ENDRESPONSE
}