View | Details | Raw Unified | Return to bug 11401
Collapse All | Expand All

(-)a/C4/Installer/PerlDependencies.pm (+19 lines)
Lines 741-746 our $PERL_DEPS = { Link Here
741
        'usage'    => 'OverDrive integration',
741
        'usage'    => 'OverDrive integration',
742
        'required' => '0',
742
        'required' => '0',
743
        'min_ver'  => '5.836',
743
        'min_ver'  => '5.836',
744
    'SOAP::Lite' => {
745
        'usage'    => 'Norwegian national library card',
746
        'required' => '0',
747
        'min_ver'  => '0.712',
748
    },
749
    'Crypt::GCrypt' => {
750
        'usage'    => 'Norwegian national library card',
751
        'required' => '0',
752
        'min_ver'  => '1.24',
753
    },
754
    'Convert::BaseN' => {
755
        'usage'    => 'Norwegian national library card',
756
        'required' => '0',
757
        'min_ver'  => '0.01',
758
    },
759
    'Test::DBIx::Class' => {
760
        'usage'    => 'Testing suite',
761
        'required' => '0',
762
        'min_ver'  => '0.41',
744
    },
763
    },
745
};
764
};
746
765
(-)a/C4/Members.pm (-1 / +40 lines)
Lines 33-47 use C4::Accounts; Link Here
33
use C4::Biblio;
33
use C4::Biblio;
34
use C4::Letters;
34
use C4::Letters;
35
use C4::SQLHelper qw(InsertInTable UpdateInTable SearchInTable);
35
use C4::SQLHelper qw(InsertInTable UpdateInTable SearchInTable);
36
use C4::Members::Attributes qw(SearchIdMatchingAttribute);
36
use C4::Members::Attributes qw(SearchIdMatchingAttribute UpdateBorrowerAttribute);
37
use C4::NewsChannels; #get slip news
37
use C4::NewsChannels; #get slip news
38
use DateTime;
38
use DateTime;
39
use DateTime::Format::DateParse;
39
use DateTime::Format::DateParse;
40
use Koha::Database;
40
use Koha::DateUtils;
41
use Koha::DateUtils;
41
use Koha::Borrower::Debarments qw(IsDebarred);
42
use Koha::Borrower::Debarments qw(IsDebarred);
42
use Text::Unaccent qw( unac_string );
43
use Text::Unaccent qw( unac_string );
43
use Koha::AuthUtils qw(hash_password);
44
use Koha::AuthUtils qw(hash_password);
44
use Koha::Database;
45
use Koha::Database;
46
use Koha::NorwegianPatronDB qw( NLUpdateHashedPIN NLEncryptPIN NLSync );
45
47
46
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
48
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
47
49
Lines 783-788 sub ModMember { Link Here
783
        if ($data{password} eq '****' or $data{password} eq '') {
785
        if ($data{password} eq '****' or $data{password} eq '') {
784
            delete $data{password};
786
            delete $data{password};
785
        } else {
787
        } else {
788
            if ( C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
789
                # Update the hashed PIN in borrower_sync.hashed_pin, before Koha hashes it
790
                NLUpdateHashedPIN( $data{'borrowernumber'}, $data{password} );
791
            }
786
            $data{password} = hash_password($data{password});
792
            $data{password} = hash_password($data{password});
787
        }
793
        }
788
    }
794
    }
Lines 803-808 sub ModMember { Link Here
803
            AddEnrolmentFeeIfNeeded( $data{categorycode}, $data{borrowernumber} );
809
            AddEnrolmentFeeIfNeeded( $data{categorycode}, $data{borrowernumber} );
804
        }
810
        }
805
811
812
        # If NorwegianPatronDBEnable is enabled, we set syncstatus to something that a
813
        # cronjob will use for syncing with NL
814
        if ( C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
815
            my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
816
                'synctype'       => 'norwegianpatrondb',
817
                'borrowernumber' => $data{'borrowernumber'}
818
            });
819
            # Do not set to "edited" if syncstatus is "new". We need to sync as new before
820
            # we can sync as changed. And the "new sync" will pick up all changes since
821
            # the patron was created anyway.
822
            if ( $borrowersync->syncstatus ne 'new' && $borrowersync->syncstatus ne 'delete' ) {
823
                $borrowersync->update( { 'syncstatus' => 'edited' } );
824
            }
825
            # Set the value of 'sync'
826
            $borrowersync->update( { 'sync' => $data{'sync'} } );
827
            # Try to do the live sync
828
            NLSync({ 'borrowernumber' => $data{'borrowernumber'} });
829
        }
830
806
        logaction("MEMBERS", "MODIFY", $data{'borrowernumber'}, "UPDATE (executed w/ arg: $data{'borrowernumber'})") if C4::Context->preference("BorrowersLog");
831
        logaction("MEMBERS", "MODIFY", $data{'borrowernumber'}, "UPDATE (executed w/ arg: $data{'borrowernumber'})") if C4::Context->preference("BorrowersLog");
807
    }
832
    }
808
    return $execute_success;
833
    return $execute_success;
Lines 845-855 sub AddMember { Link Here
845
      : $patron_category->default_privacy() eq 'never'   ? 2
870
      : $patron_category->default_privacy() eq 'never'   ? 2
846
      : $patron_category->default_privacy() eq 'forever' ? 0
871
      : $patron_category->default_privacy() eq 'forever' ? 0
847
      :                                                    undef;
872
      :                                                    undef;
873
    # Make a copy of the plain text password for later use
874
    my $plain_text_password = $data{'password'};
848
875
849
    # create a disabled account if no password provided
876
    # create a disabled account if no password provided
850
    $data{'password'} = ($data{'password'})? hash_password($data{'password'}) : '!';
877
    $data{'password'} = ($data{'password'})? hash_password($data{'password'}) : '!';
851
    $data{'borrowernumber'}=InsertInTable("borrowers",\%data);
878
    $data{'borrowernumber'}=InsertInTable("borrowers",\%data);
852
879
880
    # If NorwegianPatronDBEnable is enabled, we set syncstatus to something that a
881
    # cronjob will use for syncing with NL
882
    if ( exists $data{'borrowernumber'} && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
883
        Koha::Database->new->schema->resultset('BorrowerSync')->create({
884
            'borrowernumber' => $data{'borrowernumber'},
885
            'synctype'       => 'norwegianpatrondb',
886
            'sync'           => 1,
887
            'syncstatus'     => 'new',
888
            'hashed_pin'     => NLEncryptPIN( $plain_text_password ),
889
        });
890
    }
891
853
    # mysql_insertid is probably bad.  not necessarily accurate and mysql-specific at best.
892
    # mysql_insertid is probably bad.  not necessarily accurate and mysql-specific at best.
854
    logaction("MEMBERS", "CREATE", $data{'borrowernumber'}, "") if C4::Context->preference("BorrowersLog");
893
    logaction("MEMBERS", "CREATE", $data{'borrowernumber'}, "") if C4::Context->preference("BorrowersLog");
855
894
(-)a/Koha/NorwegianPatronDB.pm (+647 lines)
Line 0 Link Here
1
package Koha::NorwegianPatronDB;
2
3
# Copyright 2014 Oslo Public Library
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
Koha::NorwegianPatronDB
23
24
=head1 SYNOPSIS
25
26
  use Koha::NorwegianPatronDB;
27
28
=head1 FUNCTIONS
29
30
=cut
31
32
use Modern::Perl;
33
use C4::Context;
34
use C4::Members::Attributes qw( UpdateBorrowerAttribute );
35
use SOAP::Lite;
36
use Crypt::GCrypt;
37
use Convert::BaseN;
38
use DateTime;
39
40
use base 'Exporter';
41
use version; our $VERSION = qv('1.0.0');
42
43
our %EXPORT_TAGS = ( all => [qw(
44
        NLCheckSysprefs
45
        NLSearch
46
        NLSync
47
        NLGetChanged
48
        NLMarkForDeletion
49
        NLDecodePin
50
        NLEncryptPIN
51
        NLUpdateHashedPIN
52
        NLGetFirstname
53
        NLGetSurname
54
        NLGetSyncDataFromBorrowernumber
55
)] );
56
Exporter::export_ok_tags('all');
57
58
my $nl_uri   = 'http://lanekortet.no';
59
my $nl_proxy =  C4::Context->preference("NorwegianPatronDBEndpoint");
60
61
=head2 SOAP::Transport::HTTP::Client::get_basic_credentials
62
63
This is included to set the username and password used by SOAP::Lite.
64
65
=cut
66
67
sub SOAP::Transport::HTTP::Client::get_basic_credentials {
68
    # Username and password from Base Bibliotek
69
    return C4::Context->preference("NorwegianPatronDBUsername") => C4::Context->preference("NorwegianPatronDBPassword");
70
}
71
72
=head2 NLCheckSysprefs
73
74
Check that sysprefs relevant to NL are set.
75
76
=cut
77
78
sub NLCheckSysprefs {
79
80
    my $response = {
81
        'error'     => 0,
82
        'nlenabled' => 0,
83
        'endpoint'  => 0,
84
        'userpass'  => 0,
85
    };
86
87
    # Check that the Norwegian national paron database is enabled
88
    if ( C4::Context->preference("NorwegianPatronDBEnable") == 1 ) {
89
        $response->{ 'nlenabled' } = 1;
90
    } else {
91
        $response->{ 'error' } = 1;
92
    }
93
94
    # Check that an endpoint is specified
95
    if ( C4::Context->preference("NorwegianPatronDBEndpoint") ne '' ) {
96
        $response->{ 'endpoint' } = 1;
97
    } else {
98
        $response->{ 'error' } = 1;
99
    }
100
101
    # Check that the username and password for the patron database is set
102
    if ( C4::Context->preference("NorwegianPatronDBUsername") ne '' && C4::Context->preference("NorwegianPatronDBPassword") ne '' ) {
103
        $response->{ 'userpass' } = 1;
104
    } else {
105
        $response->{ 'error' } = 1;
106
    }
107
108
    return $response;
109
110
}
111
112
=head2 NLSearch
113
114
Search the NL patron database.
115
116
SOAP call: "hent" (fetch)
117
118
=cut
119
120
sub NLSearch {
121
122
    my ( $identifier ) = @_;
123
124
    my $client = SOAP::Lite
125
        ->on_action( sub { return '""';})
126
        ->uri( $nl_uri )
127
        ->proxy( $nl_proxy );
128
129
    my $id = SOAP::Data->type('string');
130
    $id->name('identifikator');
131
    $id->value( $identifier );
132
    my $som = $client->hent( $id );
133
134
    return $som;
135
136
}
137
138
=head2 NLSync
139
140
Sync a patron that has been changed or created in Koha "upstream" to NL.
141
142
Input is a hashref with one of two possible elements, either a patron retrieved
143
from the database:
144
145
    my $result = NLSync({ 'patron' => $borrower_from_dbic });
146
147
or a plain old borrowernumber:
148
149
    my $result = NLSync({ 'borrowernumber' => $borrowernumber });
150
151
In the latter case, this function will retrieve the patron record from the
152
database using DBIC.
153
154
Which part of the API is called depends on the value of the "syncstatus" column:
155
156
=over 4
157
158
=item * B<new> = The I<nyPost> ("new record") method is called.
159
160
=item * B<edited> = The I<endre> ("change/update") method is called.
161
162
=item * B<delete> = The I<slett> ("delete") method is called.
163
164
=back
165
166
Required values for B<new> and B<edited>:
167
168
=over 4
169
170
=item * sist_endret (last updated)
171
172
=item * adresse, postnr eller sted (address, zip or city)
173
174
=item * fdato (birthdate)
175
176
=item * fnr_hash (social security number, but not hashed...)
177
178
=item * kjonn (gender, M/F)
179
180
=back
181
182
=cut
183
184
sub NLSync {
185
186
    my ( $input ) = @_;
187
188
    my $patron;
189
    if ( defined $input->{'borrowernumber'} ) {
190
        $patron = Koha::Database->new->schema->resultset('Borrower')->find( $input->{'borrowernumber'} );
191
    } elsif ( defined $input->{'patron'} ) {
192
        $patron = $input->{'patron'};
193
    }
194
195
    # There should only be one sync, so we use the first one
196
    my @syncs = $patron->borrower_syncs;
197
    my $sync;
198
    foreach my $this_sync ( @syncs ) {
199
        if ( $this_sync->synctype eq 'norwegianpatrondb' ) {
200
            $sync = $this_sync;
201
        }
202
    }
203
204
    my $client = SOAP::Lite
205
        ->on_action( sub { return '""';})
206
        ->uri( $nl_uri )
207
        ->proxy( $nl_proxy );
208
209
    my $cardnumber = SOAP::Data->name( 'lnr' => $patron->cardnumber );
210
211
    # Call the appropriate method based on syncstatus
212
    my $response;
213
    if ( $sync->syncstatus eq 'edited' || $sync->syncstatus eq 'new' ) {
214
        my $soap_patron = _koha_patron_to_soap( $patron );
215
        if ( $sync->syncstatus eq 'edited' ) {
216
            $response = $client->endre( $cardnumber, $soap_patron );
217
        } elsif ( $sync->syncstatus eq 'new' ) {
218
            $response = $client->nyPost( $soap_patron );
219
        }
220
    }
221
    if ( $sync->syncstatus eq 'delete' ) {
222
        $response = $client->slett( $cardnumber );
223
    }
224
225
    # Update the sync data according to the results
226
    if ( $response->{'status'} && $response->{'status'} == 1 ) {
227
        if ( $sync->syncstatus eq 'delete' ) {
228
            # Turn off any further syncing
229
            $sync->update( { 'sync' => 0 } );
230
        }
231
        # Update the syncstatus to 'synced'
232
        $sync->update( { 'syncstatus' => 'synced' } );
233
        # Update the 'synclast' attribute with the "server time" ("server_tid") returned by the method
234
        $sync->update( { 'lastsync' => $response->{'server_tid'} } );
235
    }
236
    return $response;
237
238
}
239
240
=head2 NLGetChanged
241
242
Fetches patrons from NL that have been changed since a given timestamp. This includes
243
patrons that have been changed by the library that runs the sync, so we have to
244
check which library was the last one to change a patron, before we update patrons
245
locally.
246
247
This is supposed to be executed once per night.
248
249
SOAP call: soekEndret
250
251
=cut
252
253
sub NLGetChanged {
254
255
    my ( $from_arg ) = @_;
256
257
    my $client = SOAP::Lite
258
        ->on_action( sub { return '""';})
259
        ->uri( $nl_uri )
260
        ->proxy( $nl_proxy );
261
262
    my $from_string;
263
    if ( $from_arg && $from_arg ne '' ) {
264
        $from_string = $from_arg;
265
    } else {
266
        # Calculate 1 second past midnight of the day before
267
        my $dt = DateTime->now( time_zone => 'Europe/Oslo' );
268
        $dt->subtract( days => 1 );
269
        my $from = DateTime->new(
270
            year       => $dt->year(),
271
            month      => $dt->month(),
272
            day        => $dt->day(),
273
            hour       => 00,
274
            minute     => 00,
275
            second     => 01,
276
            time_zone  => 'Europe/Oslo',
277
        );
278
        $from_string = $from->ymd . "T" . $from->hms;
279
    }
280
281
    my $timestamp   = SOAP::Data->name( 'tidspunkt'    => $from_string );
282
    my $max_results = SOAP::Data->name( 'max_antall'   => 0 ); # 0 = no limit
283
    my $start_index = SOAP::Data->name( 'start_indeks' => 0 ); # 1 is the first record
284
285
    # Call the appropriate method based on syncstatus
286
    my $som = $client->soekEndret( $timestamp, $max_results, $start_index );
287
288
    # Extract and massage patron data
289
    my $result = $som->result;
290
    foreach my $patron ( @{ $result->{'respons_poster'} } ) {
291
        # Only handle patrons that have lnr (barcode) and fnr_hash (social security number)
292
        # Patrons that lack these two have been deleted from NL
293
        if ( $patron->{'lnr'} && $patron->{'fnr_hash'} ) {
294
            push @{ $result->{'kohapatrons'} }, _soap_to_kohapatron( $patron );
295
        }
296
    }
297
    return $result;
298
299
}
300
301
=head2 NLMarkForDeletion
302
303
Mark a borrower for deletion, but do not do the actual deletion. Deleting the
304
borrower from NL will be done later by the nl-sync-from-koha.pl script.
305
306
=cut
307
308
sub NLMarkForDeletion {
309
310
    my ( $borrowernumber ) = @_;
311
312
    my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
313
        'synctype'       => 'norwegianpatrondb',
314
        'borrowernumber' => $borrowernumber,
315
    });
316
    return $borrowersync->update( { 'syncstatus' => 'delete' } );
317
318
}
319
320
=head2 NLDecodePin
321
322
Takes a string encoded with AES/ECB/PKCS5PADDING and a 128-bits key, and returns
323
the decoded string as plain text.
324
325
The key needs to be stored in koha-conf.xml, like so:
326
327
<yazgfs>
328
  ...
329
  <config>
330
    ...
331
    <nlkey>xyz</nlkey>
332
  </config>
333
</yazgfs>
334
335
=cut
336
337
sub NLDecodePin {
338
339
    my ( $hash ) = @_;
340
    my $key = C4::Context->config( 'nlkey' );
341
342
    # Convert the hash from Base16
343
    my $cb = Convert::BaseN->new( base => 16 );
344
    my $decoded_hash = $cb->decode( $hash );
345
346
    # Do the decryption
347
    my $cipher = Crypt::GCrypt->new(
348
        type      => 'cipher',
349
        algorithm => 'aes',
350
        mode      => 'ecb',
351
        padding   => 'standard', # "This is also known as PKCS#5"
352
    );
353
    $cipher->start( 'decrypting' );
354
    $cipher->setkey( $key ); # Must be called after start()
355
    my $plaintext  = $cipher->decrypt( $decoded_hash );
356
    $plaintext .= $cipher->finish;
357
358
    return $plaintext;
359
360
}
361
362
=head2 NLEncryptPIN
363
364
Takes a plain text PIN as argument, returns the encrypted PIN, according to the
365
NL specs.
366
367
    my $encrypted_pin = NLEncryptPIN( $plain_text_pin );
368
369
=cut
370
371
sub NLEncryptPIN {
372
373
    my ( $pin ) = @_;
374
    return _encrypt_pin( $pin );
375
376
}
377
378
=head2 NLUpdateHashedPIN
379
380
Takes two arguments:
381
382
=over 4
383
384
=item * Borrowernumber
385
386
=item * Clear text PIN code
387
388
=back
389
390
Hashes the password and saves it in borrower_sync.hashed_pin.
391
392
=cut
393
394
sub NLUpdateHashedPIN {
395
396
    my ( $borrowernumber, $pin ) = @_;
397
    my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
398
        'synctype'       => 'norwegianpatrondb',
399
        'borrowernumber' => $borrowernumber,
400
        });
401
    return $borrowersync->update({ 'hashed_pin', _encrypt_pin( $pin ) });
402
403
}
404
405
=head2 _encrypt_pin
406
407
Takes a plain text PIN and returns the encrypted version, according to the NL specs.
408
409
=cut
410
411
sub _encrypt_pin {
412
413
    my ( $pin ) = @_;
414
    my $key = C4::Context->config( 'nlkey' );
415
416
    # Do the encryption
417
    my $cipher = Crypt::GCrypt->new(
418
        type      => 'cipher',
419
        algorithm => 'aes',
420
        mode      => 'ecb',
421
        padding   => 'standard', # "This is also known as PKCS#5"
422
    );
423
    $cipher->start( 'encrypting' );
424
    $cipher->setkey( $key ); # Must be called after start()
425
    my $ciphertext  = $cipher->encrypt( $pin );
426
    $ciphertext .= $cipher->finish;
427
428
    # Encode as Bas16
429
    my $cb = Convert::BaseN->new( base => 16 );
430
    my $encoded_ciphertext = $cb->encode( $ciphertext );
431
432
    return $encoded_ciphertext;
433
434
}
435
436
=head2 NLGetSyncDataFromBorrowernumber
437
438
Takes a borrowernumber as argument, returns a Koha::Schema::Result::BorrowerSync
439
object.
440
441
    my $syncdata = NLGetSyncDataFromBorrowernumber( $borrowernumber );
442
443
=cut
444
445
sub NLGetSyncDataFromBorrowernumber {
446
447
    my ( $borrowernumber ) = @_;
448
    my $data = Koha::Database->new->schema->resultset('BorrowerSync')->find({
449
        'synctype'       => 'norwegianpatrondb',
450
        'borrowernumber' => $borrowernumber,
451
    });
452
    return $data;
453
454
}
455
456
=head2 NLGetFirstname
457
458
Takes a string like "Surname, Firstname" and returns the "Firstname" part.
459
460
If there is no comma, the string is returned unaltered.
461
462
    my $firstname = NLGetFirstname( $name );
463
464
=cut
465
466
sub NLGetFirstname {
467
468
    my ( $s ) = @_;
469
    my ( $surname, $firstname ) = _split_name( $s );
470
    if ( $surname eq $s ) {
471
        return $s;
472
    } else {
473
        return $firstname;
474
    }
475
476
}
477
478
=head2 NLGetSurname
479
480
Takes a string like "Surname, Firstname" and returns the "Surname" part.
481
482
If there is no comma, the string is returned unaltered.
483
484
    my $surname = NLGetSurname( $name );
485
486
=cut
487
488
sub NLGetSurname {
489
490
    my ( $s ) = @_;
491
    my ( $surname, $firstname ) = _split_name( $s );
492
    return $surname;
493
494
}
495
496
=head2 _split_name
497
498
Takes a string like "Surname, Firstname" and returns a list of surname and firstname.
499
500
If there is no comma, the string is returned unaltered.
501
502
    my ( $surname, $firstname ) = _split_name( $name );
503
504
=cut
505
506
sub _split_name {
507
508
    my ( $s ) = @_;
509
510
    # Return the string if there is no comma
511
    unless ( $s =~ m/,/ ) {
512
        return $s;
513
    }
514
515
    my ( $surname, $firstname ) = split /, /, $s;
516
517
    return ( $surname, $firstname );
518
519
}
520
521
=head2 _format_soap_error
522
523
Takes a soap result object as input and returns a formatted string containing SOAP error data.
524
525
=cut
526
527
sub _format_soap_error {
528
529
    my ( $result ) = @_;
530
    if ( $result ) {
531
        return join ', ', $result->faultcode, $result->faultstring, $result->faultdetail;
532
    } else {
533
        return 'No result';
534
    }
535
536
}
537
538
=head2 _soap_to_koha_patron
539
540
Convert a SOAP object of type "Laaner" into a hash that can be sent to AddMember or ModMember.
541
542
=cut
543
544
sub _soap_to_kohapatron {
545
546
    my ( $soap ) = @_;
547
548
    return {
549
        'cardnumber'      => $soap->{ 'lnr' },
550
        'surname'         => NLGetSurname(   $soap->{ 'navn' } ),
551
        'firstname'       => NLGetFirstname( $soap->{ 'navn' } ),
552
        'sex'             => $soap->{ 'kjonn' },
553
        'dateofbirth'     => $soap->{ 'fdato' },
554
        'address'         => $soap->{ 'p_adresse1' },
555
        'address2'        => $soap->{ 'p_adresse2' },
556
        'zipcode'         => $soap->{ 'p_postnr' },
557
        'city'            => $soap->{ 'p_sted' },
558
        'country'         => $soap->{ 'p_land' },
559
        'b_address'       => $soap->{ 'm_adresse1' },
560
        'b_address2'      => $soap->{ 'm_adresse2' },
561
        'b_zipcode'       => $soap->{ 'm_postnr' },
562
        'b_city'          => $soap->{ 'm_sted' },
563
        'b_country'       => $soap->{ 'm_land' },
564
        'password'        => $soap->{ 'pin' },
565
        'dateexpiry'      => $soap->{ 'gyldig_til' },
566
        'email'           => $soap->{ 'epost' },
567
        'mobile'          => $soap->{ 'tlf_mobil' },
568
        'phone'           => $soap->{ 'tlf_hjemme' },
569
        'phonepro'        => $soap->{ 'tlf_jobb' },
570
        '_extra'          => { # Data that should not go in the borrowers table
571
            'socsec'         => $soap->{ 'fnr_hash' },
572
            'created'        => $soap->{ 'opprettet' },
573
            'created_by'     => $soap->{ 'opprettet_av' },
574
            'last_change'    => $soap->{ 'sist_endret' },
575
            'last_change_by' => $soap->{ 'sist_endret_av' },
576
        },
577
    };
578
579
}
580
581
=head2 _koha_patron_to_soap
582
583
Convert a patron (in the form of a Koha::Schema::Result::Borrower) into a SOAP
584
object that can be sent to NL.
585
586
=cut
587
588
sub _koha_patron_to_soap {
589
590
    my ( $patron ) = @_;
591
592
    # Extract attributes
593
    my $patron_attributes = {};
594
    foreach my $attribute ( $patron->borrower_attributes ) {
595
        $patron_attributes->{ $attribute->code->code } = $attribute->attribute;
596
    }
597
598
    # There should only be one sync, so we use the first one
599
    my @syncs = $patron->borrower_syncs;
600
    my $sync = $syncs[0];
601
602
    # Create SOAP::Data object
603
    my $soap_patron = SOAP::Data->name(
604
        'post' => \SOAP::Data->value(
605
            SOAP::Data->name( 'lnr'         => $patron->cardnumber ),
606
            SOAP::Data->name( 'fnr_hash'    => $patron_attributes->{ 'fnr' } )->type( 'string' )->type( 'string' ),
607
            SOAP::Data->name( 'navn'        => $patron->surname . ', ' . $patron->firstname    )->type( 'string' ),
608
            SOAP::Data->name( 'sist_endret' => $sync->lastsync      )->type( 'string' ),
609
            SOAP::Data->name( 'kjonn'       => $patron->sex         )->type( 'string' ),
610
            SOAP::Data->name( 'fdato'       => $patron->dateofbirth )->type( 'string' ),
611
            SOAP::Data->name( 'p_adresse1'  => $patron->address     )->type( 'string' ),
612
            SOAP::Data->name( 'p_adresse2'  => $patron->address2    )->type( 'string' ),
613
            SOAP::Data->name( 'p_postnr'    => $patron->zipcode     )->type( 'string' ),
614
            SOAP::Data->name( 'p_sted'      => $patron->city        )->type( 'string' ),
615
            SOAP::Data->name( 'p_land'      => $patron->country     )->type( 'string' ),
616
            SOAP::Data->name( 'm_adresse1'  => $patron->b_address   )->type( 'string' ),
617
            SOAP::Data->name( 'm_adresse2'  => $patron->b_address2  )->type( 'string' ),
618
            SOAP::Data->name( 'm_postnr'    => $patron->b_zipcode   )->type( 'string' ),
619
            SOAP::Data->name( 'm_sted'      => $patron->b_city      )->type( 'string' ),
620
            SOAP::Data->name( 'm_land'      => $patron->b_country   )->type( 'string' ),
621
            # Do not send the PIN code as it has been hashed by Koha, but use the version hashed according to NL
622
            SOAP::Data->name( 'pin'         => $sync->hashed_pin    )->type( 'string' ),
623
            SOAP::Data->name( 'gyldig_til'  => $patron->dateexpiry  )->type( 'string' ),
624
            SOAP::Data->name( 'epost'       => $patron->email       )->type( 'string' ),
625
            SOAP::Data->name( 'tlf_mobil'   => $patron->mobile      )->type( 'string' ),
626
            SOAP::Data->name( 'tlf_hjemme'  => $patron->phone       )->type( 'string' ),
627
            SOAP::Data->name( 'tlf_jobb'    => $patron->phonepro    )->type( 'string' ),
628
        ),
629
    )->type("Laaner");
630
631
    return $soap_patron;
632
633
}
634
635
=head1 EXPORT
636
637
None by default.
638
639
=head1 AUTHOR
640
641
Magnus Enger <digitalutvikling@gmail.com>
642
643
=cut
644
645
1;
646
647
__END__
(-)a/Koha/Schema/Result/Borrower.pm (-2 / +17 lines)
Lines 696-701 __PACKAGE__->has_many( Link Here
696
  { cascade_copy => 0, cascade_delete => 0 },
696
  { cascade_copy => 0, cascade_delete => 0 },
697
);
697
);
698
698
699
=head2 borrower_syncs
700
701
Type: has_many
702
703
Related object: L<Koha::Schema::Result::BorrowerSync>
704
705
=cut
706
707
__PACKAGE__->has_many(
708
  "borrower_syncs",
709
  "Koha::Schema::Result::BorrowerSync",
710
  { "foreign.borrowernumber" => "self.borrowernumber" },
711
  { cascade_copy => 0, cascade_delete => 0 },
712
);
713
699
=head2 branchcode
714
=head2 branchcode
700
715
701
Type: belongs_to
716
Type: belongs_to
Lines 1072-1079 Composing rels: L</course_instructors> -> course Link Here
1072
__PACKAGE__->many_to_many("courses", "course_instructors", "course");
1087
__PACKAGE__->many_to_many("courses", "course_instructors", "course");
1073
1088
1074
1089
1075
# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-07-11 09:26:55
1090
# Created by DBIx::Class::Schema::Loader v0.07025 @ 2014-01-24 09:22:05
1076
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:5cfpOojccKCoVRMj+0mWHg
1091
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:JYbNZNTvSlG20bvsbUEhQg
1077
1092
1078
1093
1079
# You can replace this text with custom content, and it will be preserved on regeneration
1094
# You can replace this text with custom content, and it will be preserved on regeneration
(-)a/Koha/Schema/Result/BorrowerSync.pm (+122 lines)
Line 0 Link Here
1
use utf8;
2
package Koha::Schema::Result::BorrowerSync;
3
4
# Created by DBIx::Class::Schema::Loader
5
# DO NOT MODIFY THE FIRST PART OF THIS FILE
6
7
=head1 NAME
8
9
Koha::Schema::Result::BorrowerSync
10
11
=cut
12
13
use strict;
14
use warnings;
15
16
use base 'DBIx::Class::Core';
17
18
=head1 TABLE: C<borrower_sync>
19
20
=cut
21
22
__PACKAGE__->table("borrower_sync");
23
24
=head1 ACCESSORS
25
26
=head2 borrowersyncid
27
28
  data_type: 'integer'
29
  is_auto_increment: 1
30
  is_nullable: 0
31
32
=head2 borrowernumber
33
34
  data_type: 'integer'
35
  is_foreign_key: 1
36
  is_nullable: 0
37
38
=head2 synctype
39
40
  data_type: 'varchar'
41
  is_nullable: 0
42
  size: 32
43
44
=head2 sync
45
46
  data_type: 'tinyint'
47
  default_value: 0
48
  is_nullable: 0
49
50
=head2 syncstatus
51
52
  data_type: 'varchar'
53
  is_nullable: 1
54
  size: 10
55
56
=head2 lastsync
57
58
  data_type: 'varchar'
59
  is_nullable: 1
60
  size: 50
61
62
=head2 hashed_pin
63
64
  data_type: 'varchar'
65
  is_nullable: 1
66
  size: 64
67
68
=cut
69
70
__PACKAGE__->add_columns(
71
  "borrowersyncid",
72
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
73
  "borrowernumber",
74
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
75
  "synctype",
76
  { data_type => "varchar", is_nullable => 0, size => 32 },
77
  "sync",
78
  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
79
  "syncstatus",
80
  { data_type => "varchar", is_nullable => 1, size => 10 },
81
  "lastsync",
82
  { data_type => "varchar", is_nullable => 1, size => 50 },
83
  "hashed_pin",
84
  { data_type => "varchar", is_nullable => 1, size => 64 },
85
);
86
87
=head1 PRIMARY KEY
88
89
=over 4
90
91
=item * L</borrowersyncid>
92
93
=back
94
95
=cut
96
97
__PACKAGE__->set_primary_key("borrowersyncid");
98
99
=head1 RELATIONS
100
101
=head2 borrowernumber
102
103
Type: belongs_to
104
105
Related object: L<Koha::Schema::Result::Borrower>
106
107
=cut
108
109
__PACKAGE__->belongs_to(
110
  "borrowernumber",
111
  "Koha::Schema::Result::Borrower",
112
  { borrowernumber => "borrowernumber" },
113
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
114
);
115
116
117
# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-06-04 14:43:23
118
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:7kXC+RmwDYY6S/uVpIfiJg
119
120
121
# You can replace this text with custom code or comments, and it will be preserved on regeneration
122
1;
(-)a/installer/data/mysql/kohastructure.sql (+18 lines)
Lines 357-362 CREATE TABLE `branch_item_rules` ( -- information entered in the circulation and Link Here
357
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
357
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
358
358
359
--
359
--
360
-- Table structure for table borrower_sync
361
--
362
363
CREATE TABLE borrower_sync (
364
  borrowersyncid int(11) NOT NULL AUTO_INCREMENT, -- Primary key, unique identifier
365
  borrowernumber int(11) NOT NULL, -- Connects data about synchronisations to a borrower
366
  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
367
  sync tinyint(1) NOT NULL DEFAULT '0', -- A boolean (1/0) for turning syncing off and on for individual borrowers
368
  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.
369
  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.
370
  hashed_pin varchar(64) DEFAULT NULL, -- Perhaps specific to The Norwegian national patron database, this column holds a hashed PIN code
371
  PRIMARY KEY (borrowersyncid),
372
  KEY borrowernumber (borrowernumber),
373
  CONSTRAINT borrower_sync_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE
374
) ENGINE=InnoDB DEFAULT CHARSET=utf8
375
376
377
--
360
-- Table structure for table `branchcategories`
378
-- Table structure for table `branchcategories`
361
--
379
--
362
380
(-)a/installer/data/mysql/sysprefs.sql (+5 lines)
Lines 195-200 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
195
('noissuescharge','5','','Define maximum amount withstanding before check outs are blocked','Integer'),
195
('noissuescharge','5','','Define maximum amount withstanding before check outs are blocked','Integer'),
196
('noItemTypeImages','0',NULL,'If ON, disables item-type images','YesNo'),
196
('noItemTypeImages','0',NULL,'If ON, disables item-type images','YesNo'),
197
('NoLoginInstructions', '', '60|10', 'Instructions to display on the OPAC login form when a patron is not logged in', 'Textarea'),
197
('NoLoginInstructions', '', '60|10', 'Instructions to display on the OPAC login form when a patron is not logged in', 'Textarea'),
198
('NorwegianPatronDBEnable','0',NULL,'Enable communication with the Norwegian national patron database.', 'YesNo'),
199
('NorwegianPatronDBEndpoint','',NULL,'Which NL endpoint to use.', 'Free'),
200
('NorwegianPatronDBUsername','',NULL,'Username for communication with the Norwegian national patron database.','Free'),
201
('NorwegianPatronDBPassword','',NULL,'Password for communication with the Norwegian national patron database.','Free'),
202
('NorwegianPatronDBSearchNLAfterLocalHit','0',NULL,'Search NL if a search has already given one or more local hits?.','YesNo'),
198
('NotesBlacklist','',NULL,'List of notes fields that should not appear in the title notes/description separator of details','free'),
203
('NotesBlacklist','',NULL,'List of notes fields that should not appear in the title notes/description separator of details','free'),
199
('NoticeCSS','',NULL,'Notices CSS url.','free'),
204
('NoticeCSS','',NULL,'Notices CSS url.','free'),
200
('NotifyBorrowerDeparture','30',NULL,'Define number of days before expiry where circulation is warned about patron account expiry','Integer'),
205
('NotifyBorrowerDeparture','30',NULL,'Define number of days before expiry where circulation is warned about patron account expiry','Integer'),
(-)a/installer/data/mysql/updatedatabase.pl (+23 lines)
Lines 8600-8605 $DBversion = "3.17.00.013"; Link Here
8600
if ( CheckVersion($DBversion) ) {
8600
if ( CheckVersion($DBversion) ) {
8601
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('maxreserves',50,'System-wide maximum number of holds a patron can place','','Integer')");
8601
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('maxreserves',50,'System-wide maximum number of holds a patron can place','','Integer')");
8602
    print "Upgrade to $DBversion done (Re-add system preference maxreserves)\n";
8602
    print "Upgrade to $DBversion done (Re-add system preference maxreserves)\n";
8603
8604
$DBversion = "3.17.00.XXX";
8605
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
8606
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('NorwegianPatronDBEnable', '0', NULL, 'Enable communication with the Norwegian national patron database.', 'YesNo')");
8607
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('NorwegianPatronDBEndpoint', '', NULL, 'Which NL endpoint to use.', 'Free')");
8608
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('NorwegianPatronDBUsername', '', NULL, 'Username for communication with the Norwegian national patron database.', 'Free')");
8609
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('NorwegianPatronDBPassword', '', NULL, 'Password for communication with the Norwegian national patron database.', 'Free')");
8610
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('NorwegianPatronDBSearchNLAfterLocalHit','0',NULL,'Search NL if a search has already given one or more local hits?.','YesNo')");
8611
    $dbh->do("
8612
CREATE TABLE borrower_sync (
8613
    borrowersyncid int(11) NOT NULL AUTO_INCREMENT,
8614
    borrowernumber int(11) NOT NULL,
8615
    synctype varchar(32) NOT NULL,
8616
    sync tinyint(1) NOT NULL DEFAULT '0',
8617
    syncstatus varchar(10) DEFAULT NULL,
8618
    lastsync varchar(50) DEFAULT NULL,
8619
    hashed_pin varchar(64) DEFAULT NULL,
8620
    PRIMARY KEY (borrowersyncid),
8621
    KEY borrowernumber (borrowernumber),
8622
    CONSTRAINT borrower_sync_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE
8623
) ENGINE=InnoDB DEFAULT CHARSET=utf8"
8624
);
8625
    print "Upgrade to $DBversion done (Bug 11401 - Add support for Norwegian national library card)\n";
8603
    SetVersion($DBversion);
8626
    SetVersion($DBversion);
8604
}
8627
}
8605
8628
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc (-2 / +46 lines)
Lines 1-12 Link Here
1
[% USE Koha %]
2
[% SET NorwegianPatronDBEnable = Koha.Preference( 'NorwegianPatronDBEnable' ) %]
1
<script type="text/javascript">
3
<script type="text/javascript">
2
//<![CDATA[
4
//<![CDATA[
3
$(document).ready(function(){
5
$(document).ready(function(){
4
    [% IF ( CAN_user_borrowers ) %]
6
    [% IF ( CAN_user_borrowers ) %]
5
        $("#deletepatron").click(function(){
7
        [% IF ( NorwegianPatronDBEnable == 1 ) %]
8
            $("#deletepatronlocal").click(function(){
9
                confirm_local_deletion();
10
                $(".btn-group").removeClass("open");
11
                return false;
12
            });
13
            $("#deletepatronremote").click(function(){
14
                confirm_remote_deletion();
15
                $(".btn-group").removeClass("open");
16
                return false;
17
            });
18
            $("#deletepatronboth").click(function(){
19
                confirm_both_deletion();
20
                $(".btn-group").removeClass("open");
21
                return false;
22
            });
23
        [% ELSE %]
24
            $("#deletepatron").click(function(){
6
                confirm_deletion();
25
                confirm_deletion();
7
                $(".btn-group").removeClass("open");
26
                $(".btn-group").removeClass("open");
8
                return false;
27
                return false;
9
            });
28
            });
29
        [% END %]
10
        $("#renewpatron").click(function(){
30
        $("#renewpatron").click(function(){
11
            confirm_reregistration();
31
            confirm_reregistration();
12
            $(".btn-group").removeClass("open");
32
            $(".btn-group").removeClass("open");
Lines 49-54 function confirm_deletion() { Link Here
49
        window.location='/cgi-bin/koha/members/deletemem.pl?member=[% borrowernumber %]';
69
        window.location='/cgi-bin/koha/members/deletemem.pl?member=[% borrowernumber %]';
50
    }
70
    }
51
}
71
}
72
function confirm_local_deletion() {
73
    var is_confirmed = window.confirm(_("Are you sure you want to delete this patron from the local database? This cannot be undone."));
74
    if (is_confirmed) {
75
        window.location='/cgi-bin/koha/members/deletemem.pl?member=[% borrowernumber %]&deletelocal=true&deleteremote=false';
76
    }
77
}
78
function confirm_remote_deletion() {
79
    var is_confirmed = window.confirm(_("Are you sure you want to delete this patron from the Norwegian national patron database? This cannot be undone."));
80
    if (is_confirmed) {
81
        window.location='/cgi-bin/koha/members/deletemem.pl?member=[% borrowernumber %]&deletelocal=false&deleteremote=true';
82
    }
83
}
84
function confirm_both_deletion() {
85
    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."));
86
    if (is_confirmed) {
87
        window.location='/cgi-bin/koha/members/deletemem.pl?member=[% borrowernumber %]&deletelocal=true&deleteremote=true';
88
    }
89
}
52
90
53
[% IF ( is_child ) %]function confirm_updatechild() {
91
[% IF ( is_child ) %]function confirm_updatechild() {
54
    var is_confirmed = window.confirm(_("Are you sure you want to update this child to an Adult category?  This cannot be undone."));
92
    var is_confirmed = window.confirm(_("Are you sure you want to update this child to an Adult category?  This cannot be undone."));
Lines 141-147 function searchToHold(){ Link Here
141
                    <li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to set permissions" id="patronflags" href="#">Set permissions</a></li>
179
                    <li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to set permissions" id="patronflags" href="#">Set permissions</a></li>
142
                [% END %]
180
                [% END %]
143
                [% IF ( CAN_user_borrowers ) %]
181
                [% IF ( CAN_user_borrowers ) %]
144
                    <li><a id="deletepatron" href="#">Delete</a></li>
182
                    [% IF ( NorwegianPatronDBEnable == 1 ) %]
183
                        <li><a id="deletepatronlocal" href="#">Delete local</a></li>
184
                        <li><a id="deletepatronremote" href="#">Delete remote</a></li>
185
                        <li><a id="deletepatronboth" href="#">Delete local and remote</a></li>
186
                    [% ELSE %]
187
                        <li><a id="deletepatron" href="#">Delete</a></li>
188
                    [% END %]
145
                [% ELSE %]
189
                [% ELSE %]
146
                    <li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to delete patrons" id="deletepatron" href="#">Delete</a></li>
190
                    <li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to delete patrons" id="deletepatron" href="#">Delete</a></li>
147
                [% END %]
191
                [% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/nl-search-form.tt (+9 lines)
Line 0 Link Here
1
<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. -->
2
<input type="hidden" name="op" value="search" />
3
    <fieldset>
4
        <legend>[% nl_search_form_title %]</legend>
5
        <label for="q">Social security or card number: </label>
6
        <input type="text" name="q" value="[% q %]">
7
        <input type="submit" value="Search">
8
    </fieldset>
9
</form>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (+22 lines)
Lines 1-4 Link Here
1
Patrons:
1
Patrons:
2
    General:
2
     -
3
     -
3
         - List
4
         - List
4
         - pref: AddPatronLists
5
         - pref: AddPatronLists
Lines 138-140 Patrons: Link Here
138
         - pref: CardnumberLength
139
         - pref: CardnumberLength
139
         - "characters long. The length can be a single number to specify an exact length, a range separated by a comma (i.e., 'Min,Max'), or a maximum with no minimum (i.e., ',Max')."
140
         - "characters long. The length can be a single number to specify an exact length, a range separated by a comma (i.e., 'Min,Max'), or a maximum with no minimum (i.e., ',Max')."
140
         - "If 'cardnumber' is included in the BorrowerMandatoryField list, the minimum length, if not specified here, defaults to one."
141
         - "If 'cardnumber' is included in the BorrowerMandatoryField list, the minimum length, if not specified here, defaults to one."
142
    Norwegian patron database:
143
    -
144
         - pref: NorwegianPatronDBEnable
145
           choices:
146
               yes: Enable
147
               no: Disable
148
         - the ability to communicate with the Norwegian national patron database via the
149
         - pref: NorwegianPatronDBEndpoint
150
         - endpoint.
151
    -
152
         - Communicate with the Norwegian national patron database using the username
153
         - pref: NorwegianPatronDBPassword
154
         - and the password
155
         - pref: NorwegianPatronDBUsername
156
         - . You can get these from "Base Bibliotek", which is maintained by the Norwegian National Library.
157
    -
158
         - pref: NorwegianPatronDBSearchNLAfterLocalHit
159
           choices:
160
               yes: Do
161
               no: "Don't"
162
         - search the Norwegian national patron database after a local search result was found.
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/deletemem.tt (-12 / +22 lines)
Lines 13-30 Link Here
13
	<div id="yui-main">
13
	<div id="yui-main">
14
	<div class="yui-b">
14
	<div class="yui-b">
15
	[% INCLUDE 'members-toolbar.inc' %]
15
	[% INCLUDE 'members-toolbar.inc' %]
16
	<div class="dialog alert">
16
	[% IF ( ItemsOnIssues || charges || guarantees ) %]
17
    <h3>Cannot delete patron</h3>
17
        <div class="dialog alert">
18
		<ul>[% IF ( ItemsOnIssues ) %]
18
        <h3>Cannot delete patron</h3>
19
			<li>Patron has [% ItemsOnIssues %] item(s) checked out.</li>
19
		    <ul>
20
		[% END %]
20
		    [% IF ( ItemsOnIssues ) %]
21
		[% IF ( charges ) %]
21
			    <li>Patron has [% ItemsOnIssues %] item(s) checked out.</li>
22
			<li>Patron has [% charges %] in fines.</li>
22
		    [% END %]
23
		[% END %]
23
		    [% IF ( charges ) %]
24
		[% IF ( guarantees ) %]
24
			    <li>Patron has [% charges %] in fines.</li>
25
			<li>Patron's record has guaranteed accounts attached.</li>
25
		    [% END %]
26
		[% END %]</ul>
26
		    [% IF ( guarantees ) %]
27
			    <li>Patron's record has guaranteed accounts attached.</li>
28
		    [% END %]
29
		    </ul>
27
	</div>
30
	</div>
31
    [% END %]
32
    [% IF ( keeplocal ) %]
33
        <div class="dialog message">
34
        <h3>Remote record deleted, local record kept</h3>
35
        <p>Patron was marked for deletion from Norwegian national patron database, but the local record was kept.</p>
36
        </div>
37
    [% END %]
28
</div>
38
</div>
29
</div>
39
</div>
30
40
Lines 32-35 Link Here
32
[% INCLUDE 'circ-menu.inc' %]
42
[% INCLUDE 'circ-menu.inc' %]
33
</div>
43
</div>
34
</div>
44
</div>
35
[% INCLUDE 'intranet-bottom.inc' %]
45
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt (+149 lines)
Lines 1-3 Link Here
1
[% USE Koha %]
1
[% INCLUDE 'doc-head-open.inc' %]
2
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Patrons [% IF ( searching ) %]&rsaquo; Search results[% END %]</title>
3
<title>Koha &rsaquo; Patrons [% IF ( searching ) %]&rsaquo; Search results[% END %]</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
[% INCLUDE 'doc-head-close.inc' %]
Lines 353-358 function filterByFirstLetterSurname(letter) { Link Here
353
                  </div>
354
                  </div>
354
              </div>
355
              </div>
355
            [% END %]
356
            [% END %]
357
				[% INCLUDE 'patron-toolbar.inc' %]
358
359
	[% IF ( no_add ) %]<div class="dialog alert"><h3>Cannot add patron</h3>
360
		[% IF ( no_branches ) %]<p>There are <strong>no libraries defined</strong>. [% IF ( CAN_user_parameters ) %]Please <a href="/cgi-bin/koha/admin/branches.pl">add a library</a>.[% ELSE %]An administrator must define at least one library.[% END %]</p>[% END %]
361
		[% IF ( no_categories ) %]<p>There are <strong>no patron categories defined</strong>. [% IF ( CAN_user_parameters ) %]Please <a href="/cgi-bin/koha/admin/categorie.pl">add a patron category</a>.[% ELSE %]An administrator must define at least one patron category.[% END %]</p>[% END %]</div>
362
	[% END %]
363
364
						<div class="browse">
365
							Browse by last name:
366
                            [% FOREACH letter IN alphabet.split(' ') %]
367
                                <a href="/cgi-bin/koha/members/member.pl?quicksearch=1&amp;surname=[% letter %]">[% letter %]</a>
368
							[% END %]
369
						</div>
370
371
                    [% IF Koha.Preference( 'NorwegianPatronDBEnable' ) == 1 %]
372
                        [% SET nl_search_form_title='Search the Norwegian national patron database' %]
373
                        [% INCLUDE 'nl-search-form.tt' %]
374
                    [% END %]
375
376
                    [% IF ( CAN_user_borrowers && pending_borrower_modifications ) %]
377
                        <div class="pending-info" id="patron_updates_pending">
378
                            <a href="/cgi-bin/koha/members/members-update.pl">Patrons requesting modifications</a>:
379
                            <span class="holdcount"><a href="/cgi-bin/koha/members/members-update.pl">[% pending_borrower_modifications %]</a></span>
380
                        </div>
381
                    [% END %]
382
383
                    [% IF ( resultsloop ) %]
384
                    [% IF (CAN_user_tools_manage_patron_lists) %]
385
                    <form id="add-patrons-to-list-form" method="post" action="member.pl" onsubmit="return CheckForm()">
386
                    [% END %]
387
                        <div id="searchheader">
388
                            <h3>Results [% from %] to [% to %] of [% numresults %] found for [% IF ( member ) %]'<span class="ex">[% member %]</span>'[% END %][% IF ( surname ) %]'<span class="ex">[% surname %]</span>'[% END %]</h3>
389
390
                            [% IF (CAN_user_tools_manage_patron_lists) %]
391
                            <div>
392
                                <a href="javascript:void(0)" onclick="$('.selection').prop('checked', true)">Select all</a>
393
                                |
394
                                <a href="javascript:void(0)" onclick="$('.selection').prop('checked', false)">Clear all</a>
395
                                |
396
                                <span>
397
                                    <label for="add_to_patron_list_which">Add:</label>
398
                                    <select id="add_to_patron_list_which" name="add_to_patron_list_which">
399
                                        <option value="selected">Selected patrons</option>
400
                                        <option value="all">All resultant patrons</option>
401
                                    </select>
402
403
                                    <label for="add_to_patron_list">to:</label>
404
                                    <select id="add_to_patron_list" name="add_to_patron_list">
405
                                        <option value=""></option>
406
                                        [% IF patron_lists %]
407
                                            <optgroup label="Patron lists:">
408
                                                [% FOREACH pl IN patron_lists %]
409
                                                    <option value="[% pl.patron_list_id %]">[% pl.name %]</option>
410
                                                [% END %]
411
                                            </optgroup>
412
                                        [% END %]
413
414
                                        <option value="new">[ New list ]</option>
415
                                    </select>
416
417
                                    <input type="text" id="new_patron_list" name="new_patron_list" id="new_patron_list" />
418
419
                                    [% FOREACH key IN search_parameters.keys %]
420
                                        <input type="hidden" name="[% key %]" value="[% search_parameters.$key %]" />
421
                                    [% END %]
422
423
                                    <input id="add_to_patron_list_submit" type="submit" class="submit" value="Save">
424
                                </span>
425
                            </div>
426
                            [% END %]
427
                        </div>
428
						<div class="searchresults">
429
430
							<table id="memberresultst">
431
							<thead>
432
							<tr>
433
                            [% IF (CAN_user_tools_manage_patron_lists) %]
434
                            <th>&nbsp</th>
435
                            [% END %]
436
							<th>Card</th>
437
							<th>Name</th>
438
							<th>Cat</th>
439
							<th>Library</th>
440
							<th>Expires on</th>
441
							<th>OD/Checkouts</th>
442
							<th>Fines</th>
443
							<th>Circ note</th>
444
							<th>&nbsp;</th>
445
							</tr>
446
							</thead>
447
							<tbody>
448
							[% FOREACH resultsloo IN resultsloop %]
449
							[% IF ( resultsloo.overdue ) %]
450
							<tr class="problem">
451
							[% ELSE %]
452
							[% UNLESS ( loop.odd ) %]
453
							<tr class="highlight">
454
							[% ELSE %]
455
							<tr>
456
							[% END %]
457
							[% END %]
458
                            [% IF (CAN_user_tools_manage_patron_lists) %]
459
                            <td><input type="checkbox" class="selection" name="borrowernumber" value="[% resultsloo.borrowernumber %]" /></td>
460
                            [% END %]
461
							<td>[% resultsloo.cardnumber %]</td>
462
                            <td style="white-space: nowrap;">
463
                            <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% resultsloo.borrowernumber %]">
464
                            [% INCLUDE 'patron-title.inc' borrowernumber = resultsloo.borrowernumber category_type = resultsloo.category_type firstname = resultsloo.firstname surname = resultsloo.surname othernames = resultsloo.othernames cardnumber = resultsloo.cardnumber invert_name = 1%]
465
                            </a> <br />
466
                            [% IF ( resultsloo.streetnumber ) %][% resultsloo.streetnumber %] [% END %][% resultsloo.address %][% IF ( resultsloo.address2 ) %]<br />[% resultsloo.address2 %][% END %][% IF ( resultsloo.city ) %]<br />[% resultsloo.city %][% IF ( resultsloo.state ) %],[% END %][% END %][% IF ( resultsloo.state ) %] [% resultsloo.state %][% END %] [% IF ( resultsloo.zipcode ) %]  [% resultsloo.zipcode %][% END %][% IF ( resultsloo.country ) %], [% resultsloo.country %][% END %]
467
                            [% IF (resultsloo.email ) %]<br/>Email: <a href="mailto:[% resultsloo.email %]">[% resultsloo.email %]</a>[% END %]
468
                            </td>
469
							<td>[% resultsloo.category_description %] ([% resultsloo.category_type %])</td>
470
							<td>[% resultsloo.branchname %]</td>
471
							<td>[% resultsloo.dateexpiry %]</td>
472
							<td>[% IF ( resultsloo.overdues ) %]<span class="overdue"><strong>[% resultsloo.overdues %]</strong></span>[% ELSE %][% resultsloo.overdues %][% END %]/[% resultsloo.issues %]</td>
473
							<td>[% IF ( resultsloo.fines < 0 ) %]<span class="credit">[% resultsloo.fines %]</span> [% ELSIF resultsloo.fines > 0 %] <span class="debit"><strong>[% resultsloo.fines %]</strong></span> [% ELSE %] [% resultsloo.fines %] [% END %]</td>
474
							<td>[% resultsloo.borrowernotes %]</td>
475
							<td>[% IF ( resultsloo.category_type ) %]
476
									<a href="/cgi-bin/koha/members/memberentry.pl?op=modify&amp;destination=circ&amp;borrowernumber=[% resultsloo.borrowernumber %]&amp;category_type=[% resultsloo.category_type %]">Edit</a>
477
						[% ELSE %] <!-- try with categorycode if no category_type -->
478
							[% IF ( resultsloo.categorycode ) %]
479
									<a href="/cgi-bin/koha/members/memberentry.pl?op=modify&amp;destination=circ&amp;borrowernumber=[% resultsloo.borrowernumber %]&amp;categorycode=[% resultsloo.categorycode %]">Edit</a>
480
							[% ELSE %] <!-- if no categorycode, set category_type to A by default -->
481
									<a href="/cgi-bin/koha/members/memberentry.pl?op=modify&amp;destination=circ&amp;borrowernumber=[% resultsloo.borrowernumber %]&amp;category_type=A">Edit</a>
482
							[% END %]
483
						[% END %]</td>
484
							</tr>
485
							[% END %]
486
							</tbody>
487
							</table>
488
							<div class="pages">[% IF ( multipage ) %][% paginationbar %][% END %]</div>
489
						</div>
490
                    [% IF (CAN_user_tools_manage_patron_lists) %]
491
                    </form>
492
                    [% END %]
493
                    [% ELSE %]
494
                        [% IF ( searching ) %]
495
                            <div class="dialog alert">No results found</div>
496
                        [% END %]
497
                    [% END %]
498
499
					</div>
500
				</div>
501
502
				<div class="yui-g">
503
				[% INCLUDE 'members-menu.inc' %]
504
			</div>
356
505
357
            <table id="memberresultst">
506
            <table id="memberresultst">
358
              <thead>
507
              <thead>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt (+13 lines)
Lines 1-4 Link Here
1
[% IF ( opduplicate ) %][% SET focusAction = "clearDupe" %][% END %]
1
[% IF ( opduplicate ) %][% SET focusAction = "clearDupe" %][% END %]
2
[% USE Koha %]
2
[% USE KohaDates %]
3
[% USE KohaDates %]
3
[% INCLUDE 'doc-head-open.inc' %]
4
[% INCLUDE 'doc-head-open.inc' %]
4
<title>Koha &rsaquo; Patrons &rsaquo; 
5
<title>Koha &rsaquo; Patrons &rsaquo; 
Lines 973-978 Link Here
973
    [% IF ( mandatorysort2 ) %]<span class="required">Required</span>[% END %]
974
    [% IF ( mandatorysort2 ) %]<span class="required">Required</span>[% END %]
974
    </li>
975
    </li>
975
        [% END %]
976
        [% END %]
977
    [% IF ( Koha.Preference( 'NorwegianPatronDBEnable' ) == 1 ) %]
978
        <li>
979
            <label for="sort2">Sync with the Norwegian national patron database:</label>
980
            [% IF ( sync == 0 ) %]
981
                <input type="radio" id="sync" name="sync" value="1"> Yes
982
                <input type="radio" id="sync" name="sync" value="0" checked> No
983
            [% ELSE %]
984
                <input type="radio" id="sync" name="sync" value="1" checked> Yes
985
                <input type="radio" id="sync" name="sync" value="0"> No
986
            [% END %]
987
        </li>
988
    [% END %]
976
	</ol>
989
	</ol>
977
  </fieldset>
990
  </fieldset>
978
    [% UNLESS nodateenrolled &&  noopacnote && noborrowernotes %]
991
    [% UNLESS nodateenrolled &&  noopacnote && noborrowernotes %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (+10 lines)
Lines 1-3 Link Here
1
[% USE Koha %]
1
[% USE KohaDates %]
2
[% USE KohaDates %]
2
[% INCLUDE 'doc-head-open.inc' %]
3
[% INCLUDE 'doc-head-open.inc' %]
3
<title>Koha &rsaquo; Patrons &rsaquo;
4
<title>Koha &rsaquo; Patrons &rsaquo;
Lines 350-355 function validate1(date) { Link Here
350
    </li>
351
    </li>
351
    [% IF ( borrowernotes ) %]<li><span class="label">Circulation note: </span>[% borrowernotes %]</li>[% END %]
352
    [% IF ( borrowernotes ) %]<li><span class="label">Circulation note: </span>[% borrowernotes %]</li>[% END %]
352
    [% IF ( opacnote ) %]<li><span class="label">OPAC note:</span>[% opacnote %]</li>[% END %]
353
    [% IF ( opacnote ) %]<li><span class="label">OPAC note:</span>[% opacnote %]</li>[% END %]
354
    [% IF Koha.Preference( 'NorwegianPatronDBEnable' ) == 1 %]
355
        [% IF ( sync == 1 ) %]
356
            <li><span class="label">Activate sync: </span>Yes</li>
357
            [% IF ( syncstatus ) %]<li><span class="label">Sync status: </span>[% syncstatus %]</li>[% END %]
358
            [% IF ( lastsync ) %]<li><span class="label">Last sync: </span>[% lastsync | $KohaDates %]</li>[% END %]
359
        [% ELSE %]
360
            <li><span class="label">Activate sync: </span>No</li>
361
        [% END %]
362
    [% END %]
353
	</ol>
363
	</ol>
354
	</div>
364
	</div>
355
 </div>
365
 </div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/nl-search.tt (+176 lines)
Line 0 Link Here
1
[% USE KohaDates %]
2
[% INCLUDE 'doc-head-open.inc' %]
3
<title>Search the Norwegian national patron database</title>
4
[% INCLUDE 'doc-head-close.inc' %]
5
</head>
6
<body>
7
[% INCLUDE 'header.inc' %]
8
[% INCLUDE 'patron-search.inc' %]
9
10
<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>
11
12
<div id="doc3" class="yui-t2">
13
    <div id="bd">
14
        <div id="yui-main">
15
            <div class="yui-b">
16
17
                <h1>Search the Norwegian national patron database</h1>
18
19
                [% IF (error) %]
20
                    <div class="dialog alert">
21
                    [% IF ( error.nlenabled == 0 ) %]<p>You need to activate this function with the NorwegianPatronDBEnable system preference in order to use it.</p>[% END %]
22
                    [% IF ( error.endpoint  == 0 ) %]<p>You need to specify an endpoint with the NorwegianPatronDBEndpoint system preference.</p>[% END %]
23
                    [% IF ( error.userpass  == 0 ) %]<p>You need to fill in the NorwegianPatronDBUsername and NorwegianPatronDBPassword system preferences in order to use this function.</p>[% END %]
24
                    [% IF ( error == 'COULD_NOT_ADD_PATRON' ) %]<p>Could not add a new patron.</p>[% END %]
25
                    </div>
26
                [% ELSE %]
27
                    [% SET nl_search_form_title='Search' %]
28
                    [% INCLUDE 'nl-search-form.tt' %]
29
                [% END %]
30
31
                [% IF ( local_result ) %]
32
                    <h3>Existing patrons</h3>
33
                    <ul>
34
                        [% FOREACH patron IN local_result %]
35
                            [%# Find the category_type %]
36
                            [% FOREACH category IN categories %]
37
                                [% IF category.categorycode == patron.categorycode %]
38
                                    [% patron.category_type = category.category_type %]
39
                                [% END %]
40
                            [% END %]
41
                            <li>[% patron.firstname %] [% patron.surname %] [% patron.cardnumber %] |
42
                                <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber %]">Details</a> |
43
                                <a href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% patron.borrowernumber %]&category_type=[% patron.category_type %]">Edit</a> |
44
                                <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% patron.borrowernumber %]">Check out</a>
45
                            </li>
46
                        [% END %]
47
                    </ul>
48
                [% END %]
49
50
                [% IF ( result ) %]
51
52
                    [% IF result.antall_poster_returnert == 0 %]
53
54
                        <div class="dialog alert">
55
                            <p>No results found in the Norwegian national patron database. Message: "[% result.melding %]"</p>
56
                        </div>
57
58
                    [% ELSE %]
59
60
                        <h3>Results from the Norwegian national patron database</h3>
61
                        <div class="yui-g">
62
                        <div class="yui-u first">
63
                        [% PROCESS patron_detail p=result.respons_poster.0 %]
64
                        </div>
65
                        [% IF ( result.respons_poster.1 ) %]
66
                            <div class="yui-u">
67
                            [% PROCESS patron_detail p=result.respons_poster.1 %]
68
                            </div>
69
                        [% END %]
70
                        </div>
71
72
                    [% END %]
73
74
                [% END %]
75
76
            </div>
77
        </div>
78
79
        <div class="yui-b">
80
            [% INCLUDE 'circ-menu.inc' %]
81
        </div>
82
    </div>
83
[% INCLUDE 'intranet-bottom.inc' %]
84
85
[% BLOCK patron_detail %]
86
<div class="rows">
87
<h4>[% p.navn | html_entity %]</h4>
88
<ol>
89
[% IF ( p.kjonn ) %]<li><span class="label">kjonn: </span>[% p.kjonn | html_entity %]</li>[% END %]
90
[% IF ( p.fdato ) %]<li><span class="label">fdato: </span>[% p.fdato | html_entity %]</li>[% END %]
91
[% IF ( p.lnr ) %]<li><span class="label">lnr: </span>[% p.lnr | html_entity %]</li>[% END %]
92
[% IF ( p.fnr_hash ) %]<li><span class="label">fnr_hash: </span>[% p.fnr_hash | html_entity %]</li>[% END %]
93
94
[% IF ( p.epost ) %]<li><span class="label">epost: </span>[% p.epost | html_entity %]</li>[% END %]
95
[% IF ( p.epost_sjekk ) %]<li><span class="label">epost_sjekk: </span>[% p.epost_sjekk | html_entity %]</li>[% END %]
96
97
[% IF ( p.tlf_mobil ) %]<li><span class="label">tlf_mobil: </span>[% p.tlf_mobil | html_entity %]</li>[% END %]
98
[% IF ( p.tlf_hjemme ) %]<li><span class="label">tlf_hjemme: </span>[% p.tlf_hjemme | html_entity %]</li>[% END %]
99
[% IF ( p.tlf_jobb ) %]<li><span class="label">tlf_jobb: </span>[% p.tlf_jobb | html_entity %]</li>[% END %]
100
101
[% IF ( p.p_adresse1 ) %]<li><span class="label">p_adresse1: </span>[% p.p_adresse1 | html_entity %]</li>[% END %]
102
[% IF ( p.p_adresse2 ) %]<li><span class="label">p_adresse2: </span>[% p.p_adresse2 | html_entity %]</li>[% END %]
103
[% IF ( p.p_postnr ) %]<li><span class="label">p_postnr: </span>[% p.p_postnr | html_entity %]</li>[% END %]
104
[% IF ( p.p_sted ) %]<li><span class="label">p_sted: </span>[% p.p_sted | html_entity %]</li>[% END %]
105
[% IF ( p.p_land ) %]<li><span class="label">p_land: </span>[% p.p_land | html_entity %]</li>[% END %]
106
[% IF ( p.p_sjekk ) %]<li><span class="label">p_sjekk: </span>[% p.p_sjekk | html_entity %]</li>[% END %]
107
108
[% IF ( p.m_adresse1 ) %]<li><span class="label">m_adresse1: </span>[% p.m_adresse1 | html_entity %]</li>[% END %]
109
[% IF ( p.m_adresse2 ) %]<li><span class="label">m_adresse2: </span>[% p.m_adresse2 | html_entity %]</li>[% END %]
110
[% IF ( p.m_postnr ) %]<li><span class="label">m_postnr: </span>[% p.m_postnr | html_entity %]</li>[% END %]
111
[% IF ( p.m_sted ) %]<li><span class="label">m_sted: </span>[% p.m_sted | html_entity %]</li>[% END %]
112
[% IF ( p.m_land ) %]<li><span class="label">m_land: </span>[% p.m_land | html_entity %]</li>[% END %]
113
[% IF ( p.m_sjek ) %]<li><span class="label">m_sjekk: </span>[% p.m_sjekk | html_entity %]</li>[% END %]
114
[% IF ( p.m_gyldig_til ) %]<li><span class="label">m_gyldig_til: </span>[% p.m_gyldig_til | html_entity %]</li>[% END %]
115
116
[% IF ( p.pin ) %]<li><span class="label">pin: </span>[% p.pin | html_entity %]</li>[% END %]
117
[% IF ( p.passord ) %]<li><span class="label">passsord: </span>[% p.passord | html_entity %]</li>[% END %]
118
[% IF ( p.feide ) %]<li><span class="label">feide: </span>[% p.feide | html_entity %]</li>[% END %]
119
[% IF ( p.folkeregsjekk_dato ) %]<li><span class="label">folkeregsjekk_dato: </span>[% p.folkeregsjekk_dato | html_entity %]</li>[% END %]
120
121
[% IF ( p.hjemmebibliotek ) %]<li><span class="label">hjemmebibliotek: </span>[% p.hjemmebibliotek | html_entity %]</li>[% END %]
122
[% IF ( p.opprettet ) %]<li><span class="label">opprettet: </span>[% p.opprettet | html_entity %]</li>[% END %]
123
[% IF ( p.opprettet_av ) %]<li><span class="label">opprettet_av: </span>[% p.opprettet_av | html_entity %]</li>[% END %]
124
[% IF ( p.sist_endret ) %]<li><span class="label">sist_endret: </span>[% p.sist_endret | html_entity %]</li>[% END %]
125
[% IF ( p.sist_endret_av ) %]<li><span class="label">sist_endret_av: </span>[% p.sist_endret_av | html_entity %]</li>[% END %]
126
[% IF ( p.gyldig_til ) %]<li><span class="label">gyldig_til: </span>[% p.gyldig_til | html_entity %]</li>[% END %]
127
128
[% IF ( p.prim_kontakt ) %]<li><span class="label">prim_kontakt: </span>[% p.prim_kontakt | html_entity %]</li>[% END %]
129
</ol>
130
131
<form action="nl-search.pl" method="POST">
132
<input type="hidden" name="op" value="save" />
133
<input type="hidden" name="navn" value="[% p.navn | html_entity %]" />
134
<input type="hidden" name="kjonn" value="[% p.kjonn | html_entity %]" />
135
<input type="hidden" name="fdato" value="[% p.fdato | html_entity %]" />
136
<input type="hidden" name="lnr" value="[% p.lnr | html_entity %]" />
137
<input type="hidden" name="fnr_hash" value="[% p.fnr_hash | html_entity %]" />
138
<input type="hidden" name="p_adresse1" value="[% p.p_adresse1 | html_entity %]" />
139
<input type="hidden" name="p_adresse2" value="[% p.p_adresse2 | html_entity %]" />
140
<input type="hidden" name="p_postnr" value="[% p.p_postnr | html_entity %]" />
141
<input type="hidden" name="p_sted" value="[% p.p_sted | html_entity %]" />
142
<input type="hidden" name="p_land" value="[% p.p_land | html_entity %]" />
143
<input type="hidden" name="p_sjekk" value="[% p.p_sjekk | html_entity %]" />
144
<input type="hidden" name="m_adresse1" value="[% p.m_adresse1 | html_entity %]" />
145
<input type="hidden" name="m_adresse2" value="[% p.m_adresse2 | html_entity %]" />
146
<input type="hidden" name="m_postnr" value="[% p.m_postnr | html_entity %]" />
147
<input type="hidden" name="m_sted" value="[% p.m_sted | html_entity %]" />
148
<input type="hidden" name="m_land" value="[% p.m_land | html_entity %]" />
149
<input type="hidden" name="m_sjekk" value="[% p.m_sjekk | html_entity %]" />
150
<input type="hidden" name="m_gyldig_til" value="[% p.m_gyldig_til | html_entity %]" />
151
<input type="hidden" name="pin" value="[% p.pin %]" />
152
<input type="hidden" name="passord" value="[% p.passord | html_entity %]" />
153
<input type="hidden" name="feide" value="[% p.feide | html_entity %]" />
154
<input type="hidden" name="folkeregsjekk_dato" value="[% p.folkeregsjekk_dato | html_entity %]" />
155
<input type="hidden" name="hjemmebibliotek" value="[% p.hjemmebibliotek | html_entity %]" />
156
<input type="hidden" name="opprettet" value="[% p.opprettet | html_entity %]" />
157
<input type="hidden" name="opprettet_av" value="[% p.opprettet_av | html_entity %]" />
158
<input type="hidden" name="sist_endret" value="[% p.sist_endret | html_entity %]" />
159
<input type="hidden" name="sist_endret_av" value="[% p.sist_endret_av | html_entity %]" />
160
<input type="hidden" name="gyldig_til" value="[% p.gyldig_til | html_entity %]" />
161
<input type="hidden" name="epost" value="[% p.epost | html_entity %]" />
162
<input type="hidden" name="epost_sjekk" value="[% p.epost_sjekk | html_entity %]" />
163
<input type="hidden" name="tlf_mobil" value="[% p.tlf_mobil | html_entity %]" />
164
<input type="hidden" name="tlf_hjemme" value="[% p.tlf_hjemme | html_entity %]" />
165
<input type="hidden" name="tlf_jobb" value="[% p.tlf_jobb | html_entity %]" />
166
<input type="hidden" name="prim_kontakt" value="[% p.prim_kontakt | html_entity %]" />
167
<input type="submit" value="Import this patron" />
168
as
169
<select name="categorycode">
170
[% FOREACH c IN categories %]
171
    <option value="[% c.categorycode %]">[% c.description %]</option>
172
[% END %]
173
</select>
174
</form>
175
</div>
176
[% END %]
(-)a/members/deletemem.pl (-3 / +22 lines)
Lines 31-36 use C4::Auth; Link Here
31
use C4::Members;
31
use C4::Members;
32
use C4::Branch; # GetBranches
32
use C4::Branch; # GetBranches
33
use C4::VirtualShelves (); #no import
33
use C4::VirtualShelves (); #no import
34
use Koha::NorwegianPatronDB qw( NLMarkForDeletion NLSync );
34
35
35
my $input = new CGI;
36
my $input = new CGI;
36
37
Lines 44-50 my ($template, $borrowernumber, $cookie) Link Here
44
                                        });
45
                                        });
45
46
46
#print $input->header;
47
#print $input->header;
47
my $member=$input->param('member');
48
my $member       = $input->param('member');
49
50
# Handle deletion from the Norwegian national patron database, if it is enabled
51
# If the "deletelocal" parameter is set to "false", the regular deletion will be
52
# short circuited, and only a deletion from the national database can be carried
53
# out. If "deletelocal" is set to "true", or not set to anything normal
54
# deletion will be done.
55
my $deletelocal  = $input->param('deletelocal')  eq 'false' ? 0 : 1; # Deleting locally is the default
56
if ( C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
57
    if ( $input->param('deleteremote') eq 'true' ) {
58
        # Mark for deletion, then try a live sync
59
        NLMarkForDeletion( $member );
60
        NLSync({ 'borrowernumber' => $member });
61
    }
62
}
63
48
my $issues = GetPendingIssues($member);     # FIXME: wasteful call when really, we only want the count
64
my $issues = GetPendingIssues($member);     # FIXME: wasteful call when really, we only want the count
49
my $countissues = scalar(@$issues);
65
my $countissues = scalar(@$issues);
50
66
Lines 80-86 my $dbh = C4::Context->dbh; Link Here
80
my $sth=$dbh->prepare("Select * from borrowers where guarantorid=?");
96
my $sth=$dbh->prepare("Select * from borrowers where guarantorid=?");
81
$sth->execute($member);
97
$sth->execute($member);
82
my $data=$sth->fetchrow_hashref;
98
my $data=$sth->fetchrow_hashref;
83
if ($countissues > 0 or $flags->{'CHARGES'}  or $data->{'borrowernumber'}){
99
if ($countissues > 0 or $flags->{'CHARGES'}  or $data->{'borrowernumber'} or $deletelocal == 0){
84
    #   print $input->header;
100
    #   print $input->header;
85
101
86
    my ($picture, $dberror) = GetPatronImage($bor->{'borrowernumber'});
102
    my ($picture, $dberror) = GetPatronImage($bor->{'borrowernumber'});
Lines 112-120 if ($countissues > 0 or $flags->{'CHARGES'} or $data->{'borrowernumber'}){ Link Here
112
    if ($flags->{'CHARGES'} ne '') {
128
    if ($flags->{'CHARGES'} ne '') {
113
        $template->param(charges => $flags->{'CHARGES'}->{'amount'});
129
        $template->param(charges => $flags->{'CHARGES'}->{'amount'});
114
    }
130
    }
115
    if ($data) {
131
    if ($data->{'borrowernumber'}) {
116
        $template->param(guarantees => 1);
132
        $template->param(guarantees => 1);
117
    }
133
    }
134
    if ($deletelocal == 0) {
135
        $template->param(keeplocal => 1);
136
    }
118
output_html_with_http_headers $input, $cookie, $template->output;
137
output_html_with_http_headers $input, $cookie, $template->output;
119
138
120
} else {
139
} else {
(-)a/members/memberentry.pl (-1 / +15 lines)
Lines 43-48 use C4::Branch; # GetBranches Link Here
43
use C4::Form::MessagingPreferences;
43
use C4::Form::MessagingPreferences;
44
use Koha::Borrower::Debarments;
44
use Koha::Borrower::Debarments;
45
use Koha::DateUtils;
45
use Koha::DateUtils;
46
use Koha::NorwegianPatronDB qw(NLGetSyncDataFromBorrowernumber);
46
47
47
use vars qw($debug);
48
use vars qw($debug);
48
49
Lines 416-427 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
416
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
417
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
417
            C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template, 1, $newdata{'categorycode'});
418
            C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template, 1, $newdata{'categorycode'});
418
        }
419
        }
420
        # Try to do the live sync with the Norwegian national patron database, if it is enabled
421
        if ( exists $data{'borrowernumber'} && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
422
            NLSync({ 'borrowernumber' => $borrowernumber });
423
        }
419
	} elsif ($op eq 'save'){ 
424
	} elsif ($op eq 'save'){ 
420
		if ($NoUpdateLogin) {
425
		if ($NoUpdateLogin) {
421
			delete $newdata{'password'};
426
			delete $newdata{'password'};
422
			delete $newdata{'userid'};
427
			delete $newdata{'userid'};
423
		}
428
		}
424
		&ModMember(%newdata) unless scalar(keys %newdata) <= 1; # bug 4508 - avoid crash if we're not
429
        &ModMember(%newdata) unless scalar(keys %newdata) <= 1; # bug 4508 - avoid crash if we're not
425
                                                                # updating any columns in the borrowers table,
430
                                                                # updating any columns in the borrowers table,
426
                                                                # which can happen if we're only editing the
431
                                                                # which can happen if we're only editing the
427
                                                                # patron attributes or messaging preferences sections
432
                                                                # patron attributes or messaging preferences sections
Lines 470-475 if ($op eq "modify") { Link Here
470
    if ( $step == 4 ) {
475
    if ( $step == 4 ) {
471
        $template->param( categorycode => $borrower_data->{'categorycode'} );
476
        $template->param( categorycode => $borrower_data->{'categorycode'} );
472
    }
477
    }
478
    # Add sync data to the user data
479
    if ( C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
480
        my $sync = NLGetSyncDataFromBorrowernumber( $borrowernumber );
481
        if ( $sync ) {
482
            $template->param(
483
                sync => $sync->sync,
484
            );
485
        }
486
    }
473
}
487
}
474
if ( $op eq "duplicate" ) {
488
if ( $op eq "duplicate" ) {
475
    $template->param( updtype => 'I' );
489
    $template->param( updtype => 'I' );
(-)a/members/moremember.pl (+11 lines)
Lines 53-58 use C4::Form::MessagingPreferences; Link Here
53
use List::MoreUtils qw/uniq/;
53
use List::MoreUtils qw/uniq/;
54
use C4::Members::Attributes qw(GetBorrowerAttributes);
54
use C4::Members::Attributes qw(GetBorrowerAttributes);
55
use Koha::Borrower::Debarments qw(GetDebarments IsDebarred);
55
use Koha::Borrower::Debarments qw(GetDebarments IsDebarred);
56
use Koha::NorwegianPatronDB qw(NLGetSyncDataFromBorrowernumber);
56
#use Smart::Comments;
57
#use Smart::Comments;
57
#use Data::Dumper;
58
#use Data::Dumper;
58
use DateTime;
59
use DateTime;
Lines 290-295 else { Link Here
290
    }
291
    }
291
}
292
}
292
293
294
# Add sync data to the user data
295
if ( C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
296
    my $sync = NLGetSyncDataFromBorrowernumber( $borrowernumber );
297
    if ( $sync ) {
298
        $data->{'sync'}       = $sync->sync;
299
        $data->{'syncstatus'} = $sync->syncstatus;
300
        $data->{'lastsync'}   = $sync->lastsync;
301
    }
302
}
303
293
# check to see if patron's image exists in the database
304
# check to see if patron's image exists in the database
294
# basically this gives us a template var to condition the display of
305
# basically this gives us a template var to condition the display of
295
# patronimage related interface on
306
# patronimage related interface on
(-)a/members/nl-search.pl (+161 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2013 Oslo Public Library
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
=head1 NAME
21
22
nl-search.pl - Script for searching the Norwegian national patron database
23
24
=head1 DESCRIPTION
25
26
This script will search the Norwegian national patron database, and let staff
27
import patrons from the natial database into the local database.
28
29
In order to use this, a username/password from the Norwegian national database
30
of libraries ("Base Bibliotek") is needed. A special key is also needed, in
31
order to decrypt and encrypt PIN-codes/passwords.
32
33
See http://www.lanekortet.no/ for more information (in Norwegian).
34
35
=cut
36
37
use Modern::Perl;
38
use CGI;
39
use C4::Auth;
40
use C4::Category;
41
use C4::Context;
42
use C4::Output;
43
use C4::Members;
44
use C4::Members::Attributes qw( SetBorrowerAttributes );
45
use Koha::NorwegianPatronDB qw( NLCheckSysprefs NLSearch NLDecodePin NLGetFirstname NLGetSurname NLSync );
46
use Koha::Database;
47
use Koha::DateUtils;
48
49
my $cgi = CGI->new;
50
my $dbh = C4::Context->dbh;
51
my $op  = $cgi->param('op');
52
53
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
54
    {
55
        template_name   => "members/nl-search.tt",
56
        query           => $cgi,
57
        type            => "intranet",
58
        authnotrequired => 0,
59
        flagsrequired   => { borrowers => 1 },
60
        debug           => 1,
61
    }
62
);
63
64
my $userenv = C4::Context->userenv;
65
66
# Check sysprefs
67
my $check_result = NLCheckSysprefs();
68
if ( $check_result->{'error'} == 1 ) {
69
    $template->param( 'error' => $check_result );
70
    output_html_with_http_headers $cgi, $cookie, $template->output;
71
    exit 0;
72
}
73
74
if ( $op && $op eq 'search' ) {
75
76
    # Get the string we are searching for
77
    my $identifier = $cgi->param('q');
78
    if ( $identifier ) {
79
        # Local search
80
        my @local_results = Search( $identifier );
81
        $template->param( 'local_result' => @local_results );
82
        # Search NL, unless we got at least one hit and further searching is
83
        # disabled
84
        if ( scalar @local_results == 0 || C4::Context->preference("NorwegianPatronDBSearchNLAfterLocalHit") == 1 ) {
85
            # TODO Check the format of the identifier before searching NL
86
            my $result = NLSearch( $identifier );
87
            unless ($result->fault) {
88
                my $r = $result->result();
89
                # Send the data to the template
90
                my @categories = C4::Category->all;
91
                $template->param(
92
                    'result'     => $r,
93
                    'categories' => \@categories,
94
                );
95
            } else {
96
                $template->param( 'error' => join ', ', $result->faultcode, $result->faultstring, $result->faultdetail );
97
            }
98
        }
99
        $template->param( 'q' => $identifier );
100
    }
101
102
} elsif ( $op && $op eq 'save' ) {
103
104
    # This is where we map from fields in NL to fields in Koha
105
    my %borrower = (
106
        'surname'      => NLGetSurname( $cgi->param('navn') ),
107
        'firstname'    => NLGetFirstname( $cgi->param('navn') ),
108
        'sex'          => $cgi->param('kjonn'),
109
        'dateofbirth'  => $cgi->param('fdato'),
110
        'cardnumber'   => $cgi->param('lnr'),
111
        'userid'       => $cgi->param('lnr'),
112
        'address'      => $cgi->param('p_adresse1'),
113
        'address2'     => $cgi->param('p_adresse2'),
114
        'zipcode'      => $cgi->param('p_postnr'),
115
        'city'         => $cgi->param('p_sted'),
116
        'country'      => $cgi->param('p_land'),
117
        'B_address'    => $cgi->param('m_adresse1'),
118
        'B_address2'   => $cgi->param('m_adresse2'),
119
        'B_zipcode'    => $cgi->param('m_postnr'),
120
        'B_city'       => $cgi->param('m_sted'),
121
        'B_country'    => $cgi->param('m_land'),
122
        'password'     => NLDecodePin( $cgi->param('pin') ),
123
        'dateexpiry'   => $cgi->param('gyldig_til'),
124
        'email'        => $cgi->param('epost'),
125
        'mobile'       => $cgi->param('tlf_mobil'),
126
        'phone'        => $cgi->param('tlf_hjemme'),
127
        'phonepro'     => $cgi->param('tlf_jobb'),
128
        'branchcode'   => $userenv->{'branch'},
129
        'categorycode' => $cgi->param('categorycode'),
130
    );
131
    # Add the new patron
132
    my $borrowernumber = &AddMember(%borrower);
133
    if ( $borrowernumber ) {
134
        # Add extended patron attributes
135
        SetBorrowerAttributes($borrowernumber, [
136
            { code => 'fnr', value => $cgi->param('fnr_hash') },
137
        ] );
138
        # Override the default sync data created by AddMember
139
        my $borrowersync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
140
            'synctype'       => 'norwegianpatrondb',
141
            'borrowernumber' => $borrowernumber,
142
        });
143
        $borrowersync->update({ 'syncstatus', 'synced' });
144
        $borrowersync->update({ 'lastsync',   $cgi->param('sist_endret') });
145
        $borrowersync->update({ 'hashed_pin', $cgi->param('pin') });
146
        # Try to sync in real time. If this fails it will be picked up by the cronjob
147
        NLSync({ 'borrowernumber' => $borrowernumber });
148
        # Redirect to the edit screen
149
        print $cgi->redirect( "/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=$borrowernumber" );
150
    } else {
151
        $template->param( 'error' => 'COULD_NOT_ADD_PATRON' );
152
    }
153
}
154
155
output_html_with_http_headers $cgi, $cookie, $template->output;
156
157
=head1 AUTHOR
158
159
Magnus Enger <digitalutvikling@gmail.com>
160
161
=cut
(-)a/misc/cronjobs/nl-sync-from-koha.pl (+184 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2014 Oslo Public Library
4
5
=head1 NAME
6
7
nl-sync-from-koha.pl - Sync patrons from Koha to the Norwegian national patron database (NL).
8
9
=head1 SYNOPSIS
10
11
 perl nl-sync-from-koha.pl -v --run
12
13
=cut
14
15
use Koha::NorwegianPatronDB qw( NLCheckSysprefs NLSync );
16
use Koha::Database;
17
use Getopt::Long;
18
use Pod::Usage;
19
use Modern::Perl;
20
21
# Get options
22
my ( $run, $verbose, $debug ) = get_options();
23
24
=head1 ACTIONS
25
26
=head2
27
28
Find local patrons that have been changed and need to be sent upstream to NL.
29
These patrons will be distinguished by two borrower attributes:
30
31
=over 4
32
33
=item * The "nlstatus" attribute will have a value of "needsync". (Which means
34
that the patron has been changed in Koha, but not yet successfully synced
35
upstream.)
36
37
=item * The "nlsync" attribute will have a value of 1. (Which means that this
38
patron has accepted to be synced with NL, as opposed to a value of 0 which
39
would indicate that the patron has asked not to be synced with NL.)
40
41
=back
42
43
=head1 STEPS
44
45
This script performs the following steps:
46
47
=head2 Check sysprefs
48
49
=cut
50
51
my $check_result = NLCheckSysprefs();
52
if ( $check_result->{'error'} == 1 ) {
53
    if ( $check_result->{'nlenabled'} == 0 ) { say "* Please activate this function with the NorwegianPatronDBEnable system preference." };
54
    if ( $check_result->{'endpoint'}  == 0 ) { say "* Please specify an endpoint with the NorwegianPatronDBEndpoint system preference." };
55
    if ( $check_result->{'userpass'}  == 0 ) { say "* Please fill in the NorwegianPatronDBUsername and NorwegianPatronDBPassword system preferences." };
56
    exit 0;
57
}
58
59
unless ( $run ) {
60
    say "* You have not specified --run, no real syncing will be done.";
61
}
62
63
=head2 Find patrons that need to be synced
64
65
=cut
66
67
my @needs_sync = Koha::Database->new->schema->resultset('BorrowerSync')->search({
68
    -and => [
69
      sync     => 1,
70
      synctype => 'norwegianpatrondb',
71
      -or => [
72
        syncstatus => 'edited',
73
        syncstatus => 'new',
74
        syncstatus => 'delete',
75
      ],
76
    ],
77
});
78
79
=head2 Do the actual sync
80
81
=cut
82
83
my $sync_success = 0;
84
my $sync_failed  = 0;
85
foreach my $borrower ( @needs_sync ) {
86
    my $cardnumber = $borrower->borrowernumber->cardnumber;
87
    my $firstname  = $borrower->borrowernumber->firstname;
88
    my $surname    = $borrower->borrowernumber->surname;
89
    my $syncstatus = $borrower->syncstatus;
90
    say "*** Syncing patron: $cardnumber - $firstname $surname ($syncstatus)" if $verbose;
91
    if ( $run ) {
92
        my $response = NLSync({ 'patron' => $borrower->borrowernumber });
93
        if ( $response ) {
94
            my $result = $response->result;
95
            if ( $result->{'status'} && $result->{'status'} == 1 ) {
96
                $sync_success++;
97
            } else {
98
                $sync_failed++;
99
            }
100
            if ( $result->{'melding'} && $verbose ) {
101
                say $result->{'melding'};
102
            }
103
        }
104
    }
105
}
106
107
=head2 Summarize if verbose mode is enabled
108
109
=cut
110
111
if ( $verbose ) {
112
    say "-----------------------------";
113
    say "Sync succeeded: $sync_success";
114
    say "Sync failed   : $sync_failed";
115
}
116
117
=head1 OPTIONS
118
119
=over 4
120
121
=item B<-r, --run>
122
123
Actually carry out syncing operations. Without this option, the script will
124
only report what it would have done, but not change any data, locally or
125
remotely.
126
127
=item B<-v --verbose>
128
129
Report on the progress of the script.
130
131
=item B<-d --debug>
132
133
Even more output.
134
135
=item B<-h, -?, --help>
136
137
Prints this help message and exits.
138
139
=back
140
141
=cut
142
143
sub get_options {
144
145
  # Options
146
  my $run     = '',
147
  my $verbose = '';
148
  my $debug   = '';
149
  my $help    = '';
150
151
  GetOptions (
152
    'r|run'     => \$run,
153
    'v|verbose' => \$verbose,
154
    'd|debug'   => \$debug,
155
    'h|?|help'  => \$help
156
  );
157
158
  pod2usage( -exitval => 0 ) if $help;
159
160
  return ( $run, $verbose, $debug );
161
162
}
163
164
=head1 AUTHOR
165
166
Magnus Enger <digitalutvikling@gmail.com>
167
168
=head1 COPYRIGHT
169
170
Copyright 2014 Oslo Public Library
171
172
=head1 LICENSE
173
174
This file is part of Koha.
175
176
Koha is free software; you can redistribute it and/or modify it under the terms
177
of the GNU General Public License as published by the Free Software Foundation;
178
either version 3 of the License, or (at your option) any later version.
179
180
You should have received a copy of the GNU General Public License along with
181
Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
182
Fifth Floor, Boston, MA 02110-1301 USA.
183
184
=cut
(-)a/misc/cronjobs/nl-sync-to-koha.pl (+192 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2014 Oslo Public Library
4
5
=head1 NAME
6
7
nl-sync-to-koha.pl - Sync patrons from the Norwegian national patron database (NL) to Koha.
8
9
=head1 SYNOPSIS
10
11
 perl nl-sync-to-koha.pl -v --run
12
13
=cut
14
15
use C4::Members;
16
use C4::Members::Attributes qw( UpdateBorrowerAttribute );
17
use Koha::NorwegianPatronDB qw( NLCheckSysprefs NLGetChanged );
18
use Koha::Database;
19
use Getopt::Long;
20
use Pod::Usage;
21
use Modern::Perl;
22
23
# Get options
24
my ( $run, $from, $verbose, $debug ) = get_options();
25
26
my $check_result = NLCheckSysprefs();
27
if ( $check_result->{'error'} == 1 ) {
28
    if ( $check_result->{'nlenabled'} == 0 ) { say "* Please activate this function with the NorwegianPatronDBEnable system preference." };
29
    if ( $check_result->{'endpoint'}  == 0 ) { say "* Please specify an endpoint with the NorwegianPatronDBEndpoint system preference." };
30
    if ( $check_result->{'userpass'}  == 0 ) { say "* Please fill in the NorwegianPatronDBUsername and NorwegianPatronDBPassword system preferences." };
31
    exit 0;
32
}
33
34
unless ( $run ) {
35
    say "* You have not specified --run, no real syncing will be done.";
36
}
37
38
# Do the sync
39
my $sync_success         = 0;
40
my $sync_failed          = 0;
41
my $skipped_local_change = 0;
42
43
# Get the borrowers that have been changed
44
my $result = NLGetChanged( $from );
45
46
if ( $verbose ) {
47
    say 'Number of records: ' . $result->{'antall_poster_returnert'};
48
    say 'Number of hits:    ' . $result->{'antall_treff'};
49
    say 'Message:           ' . $result->{'melding'};
50
    say 'Status:            ' . $result->{'status'};
51
    say 'Server time:       ' . $result->{'server_tid'};
52
    say "-----------------------------";
53
}
54
55
# Loop through the patrons
56
foreach my $patron ( @{ $result->{'kohapatrons'} } ) {
57
    if ( $verbose ) {
58
        if ( $patron->{'surname'} ) {
59
            say "*** Name: " . $patron->{'surname'};
60
        } else {
61
            say "*** No name";
62
        }
63
        say 'Created by:     ' . $patron->{'_extra'}->{'created_by'};
64
        say 'Last change by: ' . $patron->{'_extra'}->{'last_change_by'};
65
    }
66
    # Only sync in changes made by other libraries
67
    if ( C4::Context->preference("NorwegianPatronDBUsername") ne $patron->{'_extra'}->{'last_change_by'} ) {
68
        # Make a copy of the data in the hashref and store it as a hash
69
        my %clean_patron = %$patron;
70
        # Delete the extra data from the copy of the hashref
71
        delete $clean_patron{'_extra'};
72
        # Find the borrowernumber based on cardnumber
73
        my $stored_patron = Koha::Database->new->schema->resultset('Borrower')->find({
74
            'cardnumber' => $patron->{'cardnumber'}
75
        });
76
        my $borrowernumber = $stored_patron->borrowernumber;
77
        if ( $run ) {
78
            # Call ModMember
79
            my $success = ModMember(
80
                'borrowernumber' => $borrowernumber,
81
                %clean_patron,
82
            );
83
            if ( $success ) {
84
                # Get the sync object
85
                my $sync = Koha::Database->new->schema->resultset('BorrowerSync')->find({
86
                    'synctype'       => 'norwegianpatrondb',
87
                    'borrowernumber' => $borrowernumber,
88
                });
89
                # Update the syncstatus to 'synced'
90
                $sync->update( { 'syncstatus' => 'synced' } );
91
                # Update the 'synclast' attribute with the "server time" ("server_tid") returned by the method
92
                $sync->update( { 'lastsync' => $result->{'result'}->{'server_tid'} } );
93
                # Save social security number as attribute
94
                UpdateBorrowerAttribute(
95
                    $borrowernumber,
96
                    { code => 'fnr', attribute => $patron->{'_extra'}->{'socsec'} },
97
                );
98
                $sync_success++;
99
            } else {
100
                $sync_failed++;
101
            }
102
        }
103
    } else {
104
        say "Skipped, local change" if $verbose;
105
        $skipped_local_change++;
106
    }
107
}
108
109
if ( $verbose ) {
110
    say "-----------------------------";
111
    say "Sync succeeded:       $sync_success";
112
    say "Sync failed   :       $sync_failed";
113
    say "Skipped local change: $skipped_local_change";
114
}
115
116
=head1 OPTIONS
117
118
=over 4
119
120
=item B<-r, --run>
121
122
Actually carry out syncing operations. Without this option, the script will
123
only report what it would have done, but not change any data, locally or
124
remotely.
125
126
=item B<-v --verbose>
127
128
Report on the progress of the script.
129
130
=item B<-f --from>
131
132
Date and time to sync from, if this should be different from "1 second past
133
midnight of the day before". The date should be in this format:
134
135
    2014-06-03T00:00:01
136
137
=item B<-d --debug>
138
139
Even more output.
140
141
=item B<-h, -?, --help>
142
143
Prints this help message and exits.
144
145
=back
146
147
=cut
148
149
sub get_options {
150
151
  # Options
152
  my $run     = '',
153
  my $from    = '',
154
  my $verbose = '';
155
  my $debug   = '';
156
  my $help    = '';
157
158
  GetOptions (
159
    'r|run'     => \$run,
160
    'f|from=s'  => \$from,
161
    'v|verbose' => \$verbose,
162
    'd|debug'   => \$debug,
163
    'h|?|help'  => \$help
164
  );
165
166
  pod2usage( -exitval => 0 ) if $help;
167
168
  return ( $run, $from, $verbose, $debug );
169
170
}
171
172
=head1 AUTHOR
173
174
Magnus Enger <digitalutvikling@gmail.com>
175
176
=head1 COPYRIGHT
177
178
Copyright 2014 Oslo Public Library
179
180
=head1 LICENSE
181
182
This file is part of Koha.
183
184
Koha is free software; you can redistribute it and/or modify it under the terms
185
of the GNU General Public License as published by the Free Software Foundation;
186
either version 3 of the License, or (at your option) any later version.
187
188
You should have received a copy of the GNU General Public License along with
189
Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
190
Fifth Floor, Boston, MA 02110-1301 USA.
191
192
=cut
(-)a/t/NorwegianPatronDB.t (-1 / +583 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
use Modern::Perl;
4
use Test::More;
5
use Test::MockModule;
6
use t::lib::Mocks;
7
use Data::Dumper;
8
use SOAP::Lite;
9
10
# Check that all the modules we need are installed, or bail out
11
BEGIN {
12
    eval {
13
        require Test::DBIx::Class;
14
        1;
15
    } or do {
16
        plan skip_all => "Test::DBIx::Class is not available";
17
    };
18
}
19
BEGIN {
20
    eval {
21
        require SOAP::Lite;
22
        1;
23
    } or do {
24
        plan skip_all => "SOAP::Lite is not available";
25
    };
26
}
27
BEGIN {
28
    eval {
29
        require Crypt::GCrypt;
30
        1;
31
    } or do {
32
        plan skip_all => "Crypt::GCrypt is not available";
33
    };
34
}
35
BEGIN {
36
    eval {
37
        require Convert::BaseN;
38
        1;
39
    } or do {
40
        plan skip_all => "Convert::BaseN is not available";
41
    };
42
}
43
44
use Test::DBIx::Class {
45
    schema_class => 'Koha::Schema',
46
    connect_info => ['dbi:SQLite:dbname=:memory:','',''],
47
    connect_opts => { name_sep => '.', quote_char => '`', },
48
    fixture_class => '::Populate',
49
}, 'Borrower', 'BorrowerSync';
50
51
# Make the code in the module use our mocked Koha::Schema/Koha::Database
52
my $db = Test::MockModule->new('Koha::Database');
53
$db->mock(
54
    # Schema() gives us the DB connection set up by Test::DBIx::Class
55
    _new_schema => sub { return Schema(); }
56
);
57
58
fixtures_ok [
59
    'Borrower' => [
60
        [qw/firstname surname borrowernumber address city/],
61
        ['Test', 'Borrower', 1, 'Test road', 'Test city'],
62
        ['Test', 'Borrower', 2, 'Test road', 'Test city'],
63
        ['Test', 'Borrower', 3, 'Test road', 'Test city'],
64
        ['Test', 'Borrower', 4, 'Test road', 'Test city'],
65
    ],
66
    'BorrowerSync' => [
67
        [qw/borrowernumber sync syncstatus lastsync hashed_pin synctype/],
68
        [1, 1, 'new',    '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
69
        [2, 1, 'edited', '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
70
        [3, 1, 'new',    '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
71
        [4, 1, 'new',    '2014-03-31T12:35:14', 'abc', 'norwegianpatrondb' ],
72
    ],
73
], 'installed some fixtures';
74
75
=head1 LOADING THE MODULE
76
77
=cut
78
79
BEGIN { use_ok( 'Koha::NorwegianPatronDB', ':all' ) }
80
81
82
=head1 UTILITY SUBROUTINES
83
84
=head2 NLCheckSysprefs
85
86
Relevant sysprefs:
87
88
=over 4
89
90
=item * NorwegianPatronDBEnable
91
92
=item * NorwegianPatronDBEndpoint
93
94
=item * NorwegianPatronDBUsername
95
96
=item * NorwegianPatronDBPassword
97
98
=back
99
100
=cut
101
102
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable',   0);
103
t::lib::Mocks::mock_preference('NorwegianPatronDBEndpoint', '');
104
t::lib::Mocks::mock_preference('NorwegianPatronDBUsername', '');
105
t::lib::Mocks::mock_preference('NorwegianPatronDBPassword', '');
106
ok( my $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
107
is( $result->{ 'error' },     1, 'error detected' );
108
is( $result->{ 'nlenabled' }, 0, 'NL is not enabled' );
109
is( $result->{ 'endpoint' },  0, 'an endpoint is not specified' );
110
is( $result->{ 'userpass' },  0, 'username and/or password is missing' );
111
112
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable',   1);
113
ok( $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
114
is( $result->{ 'error' },     1, 'error detected' );
115
is( $result->{ 'nlenabled' }, 1, 'NL is enabled' );
116
is( $result->{ 'endpoint' },  0, 'an endpoint is not specified' );
117
is( $result->{ 'userpass' },  0, 'username and/or password is missing' );
118
119
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable',   0);
120
t::lib::Mocks::mock_preference('NorwegianPatronDBUsername', 'user');
121
t::lib::Mocks::mock_preference('NorwegianPatronDBPassword', 'pass');
122
ok( $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
123
is( $result->{ 'error' },     1, 'error detected' );
124
is( $result->{ 'nlenabled' }, 0, 'NL is not enabled' );
125
is( $result->{ 'endpoint' },  0, 'an endpoint is not specified' );
126
is( $result->{ 'userpass' },  1, 'username and/or password is present' );
127
128
t::lib::Mocks::mock_preference('NorwegianPatronDBEnable',   1);
129
t::lib::Mocks::mock_preference('NorwegianPatronDBEndpoint', 'http://example.com/');
130
ok( $result = NLCheckSysprefs(), 'call NLCheckSysprefs() ok' );
131
is( $result->{ 'error' },     0, 'no error detected' );
132
is( $result->{ 'nlenabled' }, 1, 'NL is enabled' );
133
is( $result->{ 'endpoint' },  1, 'an endpoint is specified' );
134
is( $result->{ 'userpass' },  1, 'username and/or password is present' );
135
136
=head2 NLGetFirstname and NLGetSurname
137
138
=cut
139
140
my $firstname = 'Firstname';
141
my $surname   = 'Surname';
142
my $fullname  = "$surname, $firstname";
143
my $wrongname = "$surname $firstname";
144
145
is( NLGetFirstname( $fullname  ), $firstname, 'can get firstname from name' );
146
is( NLGetSurname(   $fullname  ), $surname,   'can get surname from name' );
147
is( NLGetFirstname( $wrongname ), $wrongname, 'returns full string when name misses comma' );
148
is( NLGetSurname(   $wrongname ), $wrongname, 'returns full string when name misses comma' );
149
150
=head2 NLDecodePin and NLEncryptPIN
151
152
=cut
153
154
my $pin  = '1234';
155
my $hash = NLEncryptPIN( $pin );
156
157
is( NLEncryptPIN( $pin ), $hash, 'NLEncryptPIN works' );
158
is( NLDecodePin( $hash ), $pin, 'NLDecodePin works' );
159
160
=head2 NLUpdateHashedPIN
161
162
TODO
163
164
=cut
165
166
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('hashed_pin'), 'abc', 'hashed_pin is "abc"' );
167
# Set a new pin
168
my $new_pin = 'bcd';
169
ok( NLUpdateHashedPIN( 1, $new_pin ), 'NLUpdateHashedPIN runs ok' );
170
# Hash the new pin and compare it to the one stored in the database
171
my $hashed_pin = Koha::NorwegianPatronDB::_encrypt_pin( $new_pin );
172
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('hashed_pin'), $hashed_pin, 'hashed_pin was updated' );
173
174
=head2 NLMarkForDeletion
175
176
=cut
177
178
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('syncstatus'), 'new', 'syncstatus is "new"' );
179
ok( NLMarkForDeletion( 3 ), 'NLMarkForDeletion runs ok' );
180
# Check that the syncstatus was updated. Note: We will use this status later, to check syncing of deleted borrowers
181
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('syncstatus'), 'delete', 'syncstatus is "delete"' );
182
183
=head2 NLGetSyncDataFromBorrowernumber
184
185
=cut
186
187
ok( my $sync_data = NLGetSyncDataFromBorrowernumber( 1 ), 'NLGetSyncDataFromBorrowernumber runs ok' );
188
isa_ok( $sync_data, 'Koha::Schema::Result::BorrowerSync' );
189
is( $sync_data->sync, 1, 'the sync is on' );
190
is( $sync_data->syncstatus, 'new', 'syncstatus is "new"' );
191
is( $sync_data->lastsync, '2014-03-31T12:35:14', 'lastsync is ok' );
192
is( $sync_data->hashed_pin, $hashed_pin, 'hashed_pin is ok' );
193
194
=head1 SUBROUTINES THAT TALK TO SOAP
195
196
=head2 NLSearch
197
198
=cut
199
200
my $lite = Test::MockModule->new('SOAP::Lite');
201
202
# Mock a successfull call to the "hent" method
203
$lite->mock(
204
    hent => sub { return SOAP::Deserializer->deserialize( hent_success() )->result; }
205
);
206
ok( my $res = NLSearch( '12345678910' ), 'successfull call to NLSearch' );
207
is( $res->{'antall_poster_returnert'}, 1, 'got 1 record' );
208
isa_ok( $res, "Resultat" );
209
isa_ok( $res->{'respons_poster'}, "LaanerListe" );
210
isa_ok( $res->{'respons_poster'}[0], "Laaner" );
211
212
# Mock an unsuccessfull call to the "hent" method
213
$lite->mock(
214
    hent => sub { return SOAP::Deserializer->deserialize( hent_failure() )->result; }
215
);
216
ok( $res = NLSearch( '12345678910' ), 'call to NLSearch with an illegal argument' );
217
is( $res->{'antall_poster_returnert'}, 0, 'got 0 records' );
218
isa_ok( $res, "Resultat" );
219
like( $res->{'melding'}, qr/Ulovlig argument: hverken LNR eller FNR_HASH/, "got expected error message for an illegal identifier" );
220
221
=head2 NLSync
222
223
=head3 New patron
224
225
=cut
226
227
my $borrower = Borrower->find({ 'borrowernumber' => 1 });
228
$lite->mock(
229
    nyPost => sub { return SOAP::Deserializer->deserialize( nyPost_success() )->result; }
230
);
231
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('syncstatus'), 'new', 'patron is new' );
232
ok ( $result = NLSync({ 'patron' => $borrower }), 'successfull call to NLSync via patron ("nyPost")' );
233
is ( BorrowerSync->find({ 'borrowernumber' => 1 })->get_column('syncstatus'), 'synced', 'patron is synced' );
234
235
# Now do the same test, but pass in a borrowernumber, not a Koha::Schema::Result::Borrower
236
is ( BorrowerSync->find({ 'borrowernumber' => 4 })->get_column('syncstatus'), 'new', 'patron is new' );
237
ok ( $result = NLSync({ 'borrowernumber' => 4 }), 'successfull call to NLSync via borrowernumber ("nyPost")' );
238
is ( BorrowerSync->find({ 'borrowernumber' => 4 })->get_column('syncstatus'), 'synced', 'patron is synced' );
239
240
=head3 Edited patron
241
242
=cut
243
244
ok ( $borrower = Borrower->find({ 'borrowernumber' => 2 }), 'find our "edited" mock patron' );
245
$lite->mock(
246
    endre => sub { return SOAP::Deserializer->deserialize( endre_success() )->result; }
247
);
248
is ( BorrowerSync->find({ 'borrowernumber' => 2 })->get_column('syncstatus'), 'edited', 'patron is edited' );
249
ok ( $result = NLSync({ 'patron' => $borrower }), 'successfull call to NLSync ("endre")' );
250
is ( BorrowerSync->find({ 'borrowernumber' => 2 })->get_column('syncstatus'), 'synced', 'patron is synced' );
251
252
=head3 Deleted patron
253
254
=cut
255
256
ok ( $borrower = Borrower->find({ 'borrowernumber' => 3 }), 'find our "deleted" mock patron' );
257
$lite->mock(
258
    slett => sub { return SOAP::Deserializer->deserialize( endre_success() )->result; }
259
);
260
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('syncstatus'), 'delete', 'patron is marked for deletion' );
261
ok ( $result = NLSync({ 'patron' => $borrower }), 'successfull call to NLSync ("slett")' );
262
is ( BorrowerSync->find({ 'borrowernumber' => 3 })->get_column('sync'), 0, 'sync is now disabled' );
263
264
=head2 NLGetChanged
265
266
=cut
267
268
# Mock a successfull call to the "soekEndret" method
269
$lite->mock(
270
    soekEndret => sub { return SOAP::Deserializer->deserialize( soekEndret_success() ); }
271
);
272
ok( $res = NLGetChanged(), 'successfull call to NLGetChanged - 2 results' );
273
is( $res->{'melding'}, 'OK', 'got "OK"' );
274
is( $res->{'antall_poster_returnert'}, 2, 'got 2 records' );
275
isa_ok( $res, "Resultat" );
276
isa_ok( $res->{'respons_poster'}, "LaanerListe" );
277
isa_ok( $res->{'respons_poster'}[0], "Laaner" );
278
279
280
# Mock a successfull call to the "soekEndret" method, but with zero new records
281
$lite->mock(
282
    soekEndret => sub { return SOAP::Deserializer->deserialize( soekEndret_zero_new() ); }
283
);
284
ok( $res = NLGetChanged(), 'successfull call to NLGetChanged - 0 results' );
285
is( $res->{'melding'}, 'ingen treff', 'got "ingen treff"' );
286
is( $res->{'antall_poster_returnert'}, 0, 'got 0 records' );
287
is( $res->{'antall_treff'}, 0, 'got 0 records' );
288
289
done_testing();
290
291
=head1 SAMPLE SOAP XML RESPONSES
292
293
These responses can be gathered by setting "outputxml()" to true on the SOAP
294
client:
295
296
    my $client = SOAP::Lite
297
        ->on_action( sub { return '""';})
298
        ->uri('http://lanekortet.no')
299
        ->proxy('https://fl.lanekortet.no/laanekort/fl_test.php')
300
        ->outputxml(1);
301
    my $response = $client->slett( $x );
302
    say $response;
303
304
Pretty formatting can be achieved by piping the output from a test script
305
through xmllint:
306
307
    perl my_test_script.pl > xmllint --format -
308
309
=cut
310
311
sub slett_success {
312
313
    return <<'ENDRESPONSE';
314
<?xml version="1.0" encoding="UTF-8"?>
315
<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/">
316
  <SOAP-ENV:Body>
317
    <ns1:slettResponse>
318
      <return xsi:type="ns1:Svar">
319
        <status xsi:type="xsd:boolean">true</status>
320
        <melding xsi:type="xsd:string">Test Testersen (1973-08-11) er slettet fra registeret</melding>
321
        <lnr xsi:type="xsd:string">N000106188</lnr>
322
        <server_tid xsi:type="xsd:string">2014-06-02T16:51:58</server_tid>
323
      </return>
324
    </ns1:slettResponse>
325
  </SOAP-ENV:Body>
326
</SOAP-ENV:Envelope>
327
ENDRESPONSE
328
329
}
330
331
sub endre_success {
332
333
    return <<'ENDRESPONSE';
334
<?xml version="1.0" encoding="UTF-8"?>
335
<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/">
336
  <SOAP-ENV:Body>
337
    <ns1:endreResponse>
338
      <return xsi:type="ns1:Svar">
339
        <status xsi:type="xsd:boolean">true</status>
340
        <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>
341
        <lnr xsi:type="xsd:string">N000106188</lnr>
342
        <server_tid xsi:type="xsd:string">2014-06-02T16:42:32</server_tid>
343
      </return>
344
    </ns1:endreResponse>
345
  </SOAP-ENV:Body>
346
</SOAP-ENV:Envelope>
347
ENDRESPONSE
348
349
}
350
351
sub nyPost_success {
352
353
    return <<'ENDRESPONSE';
354
<?xml version="1.0" encoding="UTF-8"?>
355
<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/">
356
  <SOAP-ENV:Body>
357
    <ns1:nyPostResponse>
358
      <return xsi:type="ns1:Svar">
359
        <status xsi:type="xsd:boolean">true</status>
360
        <melding xsi:type="xsd:string">Ny post er opprettet</melding>
361
        <lnr xsi:type="xsd:string">N000106188</lnr>
362
        <server_tid xsi:type="xsd:string">2014-06-02T14:10:09</server_tid>
363
      </return>
364
    </ns1:nyPostResponse>
365
  </SOAP-ENV:Body>
366
</SOAP-ENV:Envelope>
367
ENDRESPONSE
368
369
}
370
371
sub soekEndret_success {
372
373
return <<'ENDRESPONSE';
374
<?xml version="1.0" encoding="UTF-8"?>
375
<SOAP-ENV:Envelope
376
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
377
    xmlns:ns1="http://lanekortet.no"
378
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
379
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
380
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
381
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
382
  <SOAP-ENV:Body>
383
    <ns1:soekEndretResponse>
384
      <return xsi:type="ns1:Resultat">
385
        <status xsi:type="xsd:boolean">true</status>
386
        <melding xsi:type="xsd:string">OK</melding>
387
        <antall_treff xsi:type="xsd:int">2</antall_treff>
388
        <antall_poster_returnert xsi:type="xsd:int">2</antall_poster_returnert>
389
        <neste_indeks xsi:type="xsd:int">0</neste_indeks>
390
        <respons_poster SOAP-ENC:arrayType="ns1:Laaner[2]" xsi:type="ns1:LaanerListe">
391
          <item xsi:type="ns1:Laaner">
392
            <lnr xsi:type="xsd:string">N000106186</lnr>
393
            <navn xsi:type="xsd:string">Hansen, Hanne</navn>
394
            <p_adresse1 xsi:type="xsd:string"/>
395
            <p_adresse2 xsi:type="xsd:string"/>
396
            <p_postnr xsi:type="xsd:string"/>
397
            <p_sted xsi:type="xsd:string">BØDØ</p_sted>
398
            <p_land xsi:type="xsd:string">no</p_land>
399
            <p_sjekk xsi:type="xsd:string">0</p_sjekk>
400
            <m_adresse1 xsi:type="xsd:string"/>
401
            <m_adresse2 xsi:type="xsd:string"/>
402
            <m_postnr xsi:type="xsd:string"/>
403
            <m_sted xsi:type="xsd:string"/>
404
            <m_land xsi:type="xsd:string"/>
405
            <m_sjekk xsi:type="xsd:string">0</m_sjekk>
406
            <m_gyldig_til xsi:type="xsd:string">0000-00-00</m_gyldig_til>
407
            <tlf_hjemme xsi:type="xsd:string"/>
408
            <tlf_jobb xsi:type="xsd:string"/>
409
            <tlf_mobil xsi:type="xsd:string"/>
410
            <epost xsi:type="xsd:string"/>
411
            <epost_sjekk xsi:type="xsd:string"/>
412
            <prim_kontakt xsi:type="xsd:string"/>
413
            <hjemmebibliotek xsi:type="xsd:string">5180401</hjemmebibliotek>
414
            <fdato xsi:type="xsd:string">1994-04-08</fdato>
415
            <fnr_hash xsi:type="xsd:string">11087395628</fnr_hash>
416
            <kjonn xsi:type="xsd:string">F</kjonn>
417
            <pin xsi:type="xsd:string">89308dfc85ee7a5826ae14e2d8efad1e</pin>
418
            <passord xsi:type="xsd:string"/>
419
            <feide xsi:type="xsd:string">0</feide>
420
            <opprettet xsi:type="xsd:string">2014-04-28T15:20:38</opprettet>
421
            <opprettet_av xsi:type="xsd:string">5180401</opprettet_av>
422
            <sist_endret xsi:type="xsd:string">2014-04-28T15:20:38</sist_endret>
423
            <sist_endret_av xsi:type="xsd:string">5180401</sist_endret_av>
424
            <folkeregsjekk_dato xsi:type="xsd:string">0000-00-00</folkeregsjekk_dato>
425
          </item>
426
          <item xsi:type="ns1:Laaner">
427
            <lnr xsi:type="xsd:string">N000106184</lnr>
428
            <navn xsi:type="xsd:string">Enger, Magnus</navn>
429
            <p_adresse1 xsi:type="xsd:string">Svarthammarveien 633333</p_adresse1>
430
            <p_adresse2 xsi:type="xsd:string"/>
431
            <p_postnr xsi:type="xsd:string">8015</p_postnr>
432
            <p_sted xsi:type="xsd:string">Bodø</p_sted>
433
            <p_land xsi:type="xsd:string">no</p_land>
434
            <p_sjekk xsi:type="xsd:string">0</p_sjekk>
435
            <m_adresse1 xsi:type="xsd:string"/>
436
            <m_adresse2 xsi:type="xsd:string"/>
437
            <m_postnr xsi:type="xsd:string"/>
438
            <m_sted xsi:type="xsd:string"/>
439
            <m_land xsi:type="xsd:string">no</m_land>
440
            <m_sjekk xsi:type="xsd:string">0</m_sjekk>
441
            <m_gyldig_til xsi:type="xsd:string">0000-00-00</m_gyldig_til>
442
            <tlf_hjemme xsi:type="xsd:string">95158548</tlf_hjemme>
443
            <tlf_jobb xsi:type="xsd:string"/>
444
            <tlf_mobil xsi:type="xsd:string"/>
445
            <epost xsi:type="xsd:string">magnus@enger.priv.no</epost>
446
            <epost_sjekk xsi:type="xsd:string"/>
447
            <prim_kontakt xsi:type="xsd:string"/>
448
            <hjemmebibliotek xsi:type="xsd:string">5180401</hjemmebibliotek>
449
            <fdato xsi:type="xsd:string">1973-08-11</fdato>
450
            <fnr_hash xsi:type="xsd:string">11087345795</fnr_hash>
451
            <kjonn xsi:type="xsd:string">M</kjonn>
452
            <pin xsi:type="xsd:string">a632c504b8c4fba3149115cb07e0796c</pin>
453
            <passord xsi:type="xsd:string"/>
454
            <feide xsi:type="xsd:string">0</feide>
455
            <opprettet xsi:type="xsd:string">2014-04-28T14:52:02</opprettet>
456
            <opprettet_av xsi:type="xsd:string">5180401</opprettet_av>
457
            <sist_endret xsi:type="xsd:string">2014-05-13T11:01:33</sist_endret>
458
            <sist_endret_av xsi:type="xsd:string">5180401</sist_endret_av>
459
            <folkeregsjekk_dato xsi:type="xsd:string">0000-00-00</folkeregsjekk_dato>
460
          </item>
461
        </respons_poster>
462
        <server_tid xsi:type="xsd:string">2014-05-16T14:44:44</server_tid>
463
      </return>
464
    </ns1:soekEndretResponse>
465
  </SOAP-ENV:Body>
466
</SOAP-ENV:Envelope>
467
ENDRESPONSE
468
}
469
470
sub soekEndret_zero_new {
471
    return <<'ENDRESPONSE';
472
<?xml version="1.0" encoding="UTF-8"?>
473
    <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/">
474
      <SOAP-ENV:Body>
475
        <ns1:soekEndretResponse>
476
          <return xsi:type="ns1:Resultat">
477
            <status xsi:type="xsd:boolean">false</status>
478
            <melding xsi:type="xsd:string">ingen treff</melding>
479
            <antall_treff xsi:type="xsd:int">0</antall_treff>
480
            <antall_poster_returnert xsi:type="xsd:int">0</antall_poster_returnert>
481
            <neste_indeks xsi:type="xsd:int">0</neste_indeks>
482
            <respons_poster SOAP-ENC:arrayType="ns1:Laaner[0]" xsi:type="ns1:LaanerListe"/>
483
            <server_tid xsi:type="xsd:string">2014-05-20T13:02:02</server_tid>
484
          </return>
485
        </ns1:soekEndretResponse>
486
      </SOAP-ENV:Body>
487
    </SOAP-ENV:Envelope>
488
ENDRESPONSE
489
}
490
491
sub hent_failure {
492
    return <<'ENDRESPONSE';
493
<?xml version="1.0" encoding="UTF-8"?>
494
<SOAP-ENV:Envelope
495
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
496
    xmlns:ns1="http://lanekortet.no"
497
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
498
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
499
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
500
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
501
  <SOAP-ENV:Body>
502
    <ns1:hentResponse>
503
      <return xsi:type="ns1:Resultat">
504
        <status xsi:type="xsd:boolean">false</status>
505
        <melding xsi:type="xsd:string">hent: Ulovlig argument: hverken LNR eller FNR_HASH</melding>
506
        <antall_treff xsi:type="xsd:int">0</antall_treff>
507
        <antall_poster_returnert xsi:type="xsd:int">0</antall_poster_returnert>
508
        <neste_indeks xsi:type="xsd:int">0</neste_indeks>
509
        <respons_poster SOAP-ENC:arrayType="ns1:Laaner[0]" xsi:type="ns1:LaanerListe"/>
510
        <server_tid xsi:type="xsd:string">2014-05-15T10:56:24</server_tid>
511
      </return>
512
    </ns1:hentResponse>
513
  </SOAP-ENV:Body>
514
</SOAP-ENV:Envelope>
515
ENDRESPONSE
516
517
}
518
519
sub hent_success {
520
521
return <<'ENDRESPONSE';
522
<?xml version="1.0" encoding="UTF-8"?>
523
<SOAP-ENV:Envelope
524
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
525
    xmlns:ns1="http://lanekortet.no"
526
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
527
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
528
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
529
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
530
  <SOAP-ENV:Body>
531
    <ns1:hentResponse>
532
      <return xsi:type="ns1:Resultat">
533
        <status xsi:type="xsd:boolean">true</status>
534
        <melding xsi:type="xsd:string">OK</melding>
535
        <antall_treff xsi:type="xsd:int">1</antall_treff>
536
        <antall_poster_returnert xsi:type="xsd:int">1</antall_poster_returnert>
537
        <neste_indeks xsi:type="xsd:int">0</neste_indeks>
538
        <respons_poster SOAP-ENC:arrayType="ns1:Laaner[1]" xsi:type="ns1:LaanerListe">
539
          <item xsi:type="ns1:Laaner">
540
            <lnr xsi:type="xsd:string">N000123456</lnr>
541
            <navn xsi:type="xsd:string">Test, Testersen</navn>
542
            <p_adresse1 xsi:type="xsd:string">Bibliotekveien 6</p_adresse1>
543
            <p_adresse2 xsi:type="xsd:string"/>
544
            <p_postnr xsi:type="xsd:string">1234</p_postnr>
545
            <p_sted xsi:type="xsd:string">Lillevik</p_sted>
546
            <p_land xsi:type="xsd:string">no</p_land>
547
            <p_sjekk xsi:type="xsd:string">0</p_sjekk>
548
            <m_adresse1 xsi:type="xsd:string"/>
549
            <m_adresse2 xsi:type="xsd:string"/>
550
            <m_postnr xsi:type="xsd:string"/>
551
            <m_sted xsi:type="xsd:string"/>
552
            <m_land xsi:type="xsd:string">no</m_land>
553
            <m_sjekk xsi:type="xsd:string">0</m_sjekk>
554
            <m_gyldig_til xsi:type="xsd:string">0000-00-00</m_gyldig_til>
555
            <tlf_hjemme xsi:type="xsd:string"/>
556
            <tlf_jobb xsi:type="xsd:string"/>
557
            <tlf_mobil xsi:type="xsd:string">12345678</tlf_mobil>
558
            <epost xsi:type="xsd:string">test@example.com</epost>
559
            <epost_sjekk xsi:type="xsd:string">0</epost_sjekk>
560
            <prim_kontakt xsi:type="xsd:string"/>
561
            <hjemmebibliotek xsi:type="xsd:string">2060000</hjemmebibliotek>
562
            <fdato xsi:type="xsd:string">1964-05-22</fdato>
563
            <fnr_hash xsi:type="xsd:string">22056412345</fnr_hash>
564
            <kjonn xsi:type="xsd:string">F</kjonn>
565
            <pin xsi:type="xsd:string">g345abc123dab567abc78900abc123ab</pin>
566
            <passord xsi:type="xsd:string"/>
567
            <feide xsi:type="xsd:string"/>
568
            <opprettet xsi:type="xsd:string">2005-10-20</opprettet>
569
            <opprettet_av xsi:type="xsd:string">2060000</opprettet_av>
570
            <sist_endret xsi:type="xsd:string">2013-05-13T13:51:24</sist_endret>
571
            <sist_endret_av xsi:type="xsd:string">2060000</sist_endret_av>
572
            <gyldig_til xsi:type="xsd:string"/>
573
            <folkeregsjekk_dato xsi:type="xsd:string">0000-00-00</folkeregsjekk_dato>
574
          </item>
575
        </respons_poster>
576
        <server_tid xsi:type="xsd:string">2014-01-07T14:43:18</server_tid>
577
      </return>
578
    </ns1:hentResponse>
579
  </SOAP-ENV:Body>
580
</SOAP-ENV:Envelope>
581
ENDRESPONSE
582
583
}

Return to bug 11401