Bug 4461: Checks on library email before enqueuing letter
[koha.git] / misc / sip_cli_emulator.pl
blob5f4b326a2603e3f4fa438da7a04357bfe88735a3
1 #!/usr/bin/perl
3 # This file is part of Koha.
5 # Copyright (C) 2012-2013 ByWater Solutions
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.
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.
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>.
20 use Modern::Perl;
22 use Socket qw(:crlf);
23 use IO::Socket::INET;
24 use Getopt::Long;
26 use C4::SIP::Sip::Constants qw(:all);
27 use C4::SIP::Sip;
29 use constant { LANGUAGE => '001' };
31 my $help = 0;
33 my $host;
34 my $port = '6001';
36 my $login_user_id;
37 my $login_password;
38 my $location_code;
40 my $patron_identifier;
41 my $patron_password;
43 my $summary;
45 my $item_identifier;
47 my $fee_acknowledged = 0;
49 my $fee_type;
50 my $payment_type;
51 my $currency_type;
52 my $fee_amount;
53 my $fee_identifier;
54 my $transaction_id;
55 my $pickup_location;
57 my $terminator = q{};
59 my @messages;
61 GetOptions(
62 "a|address|host|hostaddress=s" => \$host, # sip server ip
63 "p|port=s" => \$port, # sip server port
64 "su|sip_user=s" => \$login_user_id, # sip user
65 "sp|sip_pass=s" => \$login_password, # sip password
66 "l|location|location_code=s" => \$location_code, # sip location code
68 "patron=s" => \$patron_identifier, # patron cardnumber or login
69 "password=s" => \$patron_password, # patron's password
71 "i|item=s" => \$item_identifier,
73 "fa|fee-acknowledged" => \$fee_acknowledged,
75 "s|summary=s" => \$summary,
77 "fee-type=s" => \$fee_type,
78 "payment-type=s" => \$payment_type,
79 "currency-type=s" => \$currency_type,
80 "fee-amount=s" => \$fee_amount,
81 "fee-identifier=s" => \$fee_identifier,
82 "transaction-id=s" => \$transaction_id,
83 "pickup-location=s" => \$pickup_location,
85 "t|terminator=s" => \$terminator,
87 "m|message=s" => \@messages,
89 'h|help|?' => \$help
92 if ( $help
93 || !$host
94 || !$login_user_id
95 || !$login_password
96 || !$location_code )
98 say &help();
99 exit();
102 $terminator = ( $terminator eq 'CR' ) ? $CR : $CRLF;
104 # Set perl to expect the same record terminator it is sending
105 $/ = $terminator;
107 my $transaction_date = C4::SIP::Sip::timestamp();
109 my $terminal_password = $login_password;
111 $| = 1;
112 print "Attempting socket connection to $host:$port...";
114 my $socket = IO::Socket::INET->new("$host:$port")
115 or die "failed! : $!\n";
116 say "connected!";
118 my $handlers = {
119 login => {
120 name => 'Login',
121 subroutine => \&build_login_command_message,
122 parameters => {
123 login_user_id => $login_user_id,
124 login_password => $login_password,
125 location_code => $location_code,
128 patron_status_request => {
129 name => 'Patron Status Request',
130 subroutine => \&build_patron_status_request_command_message,
131 parameters => {
132 transaction_date => $transaction_date,
133 institution_id => $location_code,
134 patron_identifier => $patron_identifier,
135 terminal_password => $terminal_password,
136 patron_password => $patron_password,
138 optional => [ 'patron_password', ],
140 patron_information => {
141 name => 'Patron Information',
142 subroutine => \&build_patron_information_command_message,
143 parameters => {
144 transaction_date => $transaction_date,
145 institution_id => $location_code,
146 patron_identifier => $patron_identifier,
147 terminal_password => $terminal_password,
148 patron_password => $patron_password,
149 summary => $summary,
151 optional => [ 'patron_password', 'summary' ],
153 item_information => {
154 name => 'Item Information',
155 subroutine => \&build_item_information_command_message,
156 parameters => {
157 transaction_date => $transaction_date,
158 institution_id => $location_code,
159 item_identifier => $item_identifier,
160 terminal_password => $terminal_password,
162 optional => [],
164 checkout => {
165 name => 'Checkout',
166 subroutine => \&build_checkout_command_message,
167 parameters => {
168 SC_renewal_policy => 'Y',
169 no_block => 'N',
170 transaction_date => $transaction_date,
171 nb_due_date => undef,
172 institution_id => $location_code,
173 patron_identifier => $patron_identifier,
174 item_identifier => $item_identifier,
175 terminal_password => $terminal_password,
176 item_properties => undef,
177 patron_password => $patron_password,
178 fee_acknowledged => $fee_acknowledged,
179 cancel => undef,
181 optional => [
182 'nb_due_date', # defaults to transaction date
183 'item_properties',
184 'patron_password',
185 'fee_acknowledged',
186 'cancel',
189 checkin => {
190 name => 'Checkin',
191 subroutine => \&build_checkin_command_message,
192 parameters => {
193 no_block => 'N',
194 transaction_date => $transaction_date,
195 return_date => $transaction_date,
196 current_location => $location_code,
197 institution_id => $location_code,
198 item_identifier => $item_identifier,
199 terminal_password => $terminal_password,
200 item_properties => undef,
201 cancel => undef,
203 optional => [
204 'return_date', # defaults to transaction date
205 'item_properties',
206 'patron_password',
207 'cancel',
210 renew => {
211 name => 'Renew',
212 subroutine => \&build_renew_command_message,
213 parameters => {
214 third_party_allowed => 'N',
215 no_block => 'N',
216 transaction_date => $transaction_date,
217 nb_due_date => undef,
218 institution_id => $location_code,
219 patron_identifier => $patron_identifier,
220 patron_password => $patron_password,
221 item_identifier => $item_identifier,
222 title_identifier => undef,
223 terminal_password => $terminal_password,
224 item_properties => undef,
225 fee_acknowledged => $fee_acknowledged,
227 optional => [
228 'nb_due_date', # defaults to transaction date
229 'patron_password',
230 'item_identifier',
231 'title_identifier',
232 'terminal_password',
233 'item_properties',
234 'fee_acknowledged',
237 fee_paid => {
238 name => 'Fee Paid',
239 subroutine => \&build_fee_paid_command_message,
240 parameters => {
241 transaction_date => $transaction_date,
242 fee_type => $fee_type,
243 payment_type => $payment_type,
244 currency_type => $currency_type,
245 fee_amount => $fee_amount,
246 institution_id => $location_code,
247 patron_identifier => $patron_identifier,
248 terminal_password => $terminal_password,
249 patron_password => $patron_password,
250 fee_identifier => $fee_identifier,
251 transaction_id => $transaction_id,
253 optional => [
254 'fee_type', # has default
255 'payment_type', # has default
256 'currency_type', #has default
257 'terminal_password',
258 'patron_password',
259 'fee_identifier',
260 'transaction_id',
263 hold => {
264 name => 'Hold',
265 subroutine => \&build_hold_command_message,
266 parameters => {
267 hold_mode => '+',
268 transaction_date => $transaction_date,
269 expiration_date => undef,
270 pickup_location => $pickup_location,
271 hold_type => undef,
272 institution_id => $location_code,
273 patron_identifier => $patron_identifier,
274 patron_password => $patron_password,
275 item_identifier => $item_identifier,
276 title_identifier => undef,
277 terminal_password => $terminal_password,
278 fee_acknowledged => $fee_acknowledged,
280 optional => [
281 'expiration_date',
282 'pickup_location',
283 'hold_type',
284 'patron_password',
285 'item_identifier',
286 'title_identifier',
287 'terminal_password',
288 'fee_acknowledged',
293 my $data = run_command_message('login');
295 if ( $data =~ '^941' ) { ## we are logged in
296 foreach my $m (@messages) {
297 say "Trying '$m'";
299 my $data = run_command_message($m);
303 else {
304 say "Login Failed!";
307 sub build_command_message {
308 my ($message) = @_;
310 ##FIXME It would be much better to use exception handling so we aren't priting from subs
311 unless ( $handlers->{$message} ) {
312 say "$message is an unsupported command!";
313 return;
316 my $subroutine = $handlers->{$message}->{subroutine};
317 my $parameters = $handlers->{$message}->{parameters};
318 my %optional = map { $_ => 1 } @{ $handlers->{$message}->{optional} };
320 foreach my $key ( keys %$parameters ) {
321 unless ( $parameters->{$key} ) {
322 unless ( $optional{$key} ) {
323 say "$key is required for $message";
324 return;
329 return &$subroutine($parameters);
332 sub run_command_message {
333 my ($message) = @_;
335 my $command_message = build_command_message($message);
337 return unless $command_message;
339 say "SEND: $command_message";
340 print $socket $command_message . $terminator;
342 my $data = <$socket>;
344 say "READ: $data";
346 return $data;
349 sub build_login_command_message {
350 my ($params) = @_;
352 my $login_user_id = $params->{login_user_id};
353 my $login_password = $params->{login_password};
354 my $location_code = $params->{location_code};
356 return
357 LOGIN . "00"
358 . build_field( FID_LOGIN_UID, $login_user_id )
359 . build_field( FID_LOGIN_PWD, $login_password )
360 . build_field( FID_LOCATION_CODE, $location_code );
363 sub build_patron_status_request_command_message {
364 my ($params) = @_;
366 my $transaction_date = $params->{transaction_date};
367 my $institution_id = $params->{institution_id};
368 my $patron_identifier = $params->{patron_identifier};
369 my $terminal_password = $params->{terminal_password};
370 my $patron_password = $params->{patron_password};
372 return
373 PATRON_STATUS_REQ
374 . LANGUAGE
375 . $transaction_date
376 . build_field( FID_INST_ID, $institution_id )
377 . build_field( FID_PATRON_ID, $patron_identifier )
378 . build_field( FID_TERMINAL_PWD, $terminal_password )
379 . build_field( FID_PATRON_PWD, $patron_password );
382 sub build_patron_information_command_message {
383 my ($params) = @_;
385 my $transaction_date = $params->{transaction_date};
386 my $institution_id = $params->{institution_id};
387 my $patron_identifier = $params->{patron_identifier};
388 my $terminal_password = $params->{terminal_password};
389 my $patron_password = $params->{patron_password};
390 my $summary = $params->{summary};
392 $summary //= " ";
394 return
395 PATRON_INFO
396 . LANGUAGE
397 . $transaction_date
398 . $summary
399 . build_field( FID_INST_ID, $institution_id )
400 . build_field( FID_PATRON_ID, $patron_identifier )
401 . build_field( FID_TERMINAL_PWD, $terminal_password )
402 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } );
405 sub build_item_information_command_message {
406 my ($params) = @_;
408 my $transaction_date = $params->{transaction_date};
409 my $institution_id = $params->{institution_id};
410 my $item_identifier = $params->{item_identifier};
411 my $terminal_password = $params->{terminal_password};
413 return
414 ITEM_INFORMATION
415 . LANGUAGE
416 . $transaction_date
417 . build_field( FID_INST_ID, $institution_id )
418 . build_field( FID_ITEM_ID, $item_identifier )
419 . build_field( FID_TERMINAL_PWD, $terminal_password );
422 sub build_checkout_command_message {
423 my ($params) = @_;
425 my $SC_renewal_policy = $params->{SC_renewal_policy} || 'N';
426 my $no_block = $params->{no_block} || 'N';
427 my $transaction_date = $params->{transaction_date};
428 my $nb_due_date = $params->{nb_due_date};
429 my $institution_id = $params->{institution_id};
430 my $patron_identifier = $params->{patron_identifier};
431 my $item_identifier = $params->{item_identifier};
432 my $terminal_password = $params->{terminal_password};
433 my $item_properties = $params->{item_properties};
434 my $patron_password = $params->{patron_password};
435 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
436 my $cancel = $params->{cancel} || 'N';
438 $SC_renewal_policy = $SC_renewal_policy eq 'Y' ? 'Y' : 'N';
439 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
440 $fee_acknowledged = $fee_acknowledged eq 'Y' ? 'Y' : 'N';
441 $cancel = $cancel eq 'Y' ? 'Y' : 'N';
443 $nb_due_date ||= $transaction_date;
445 return
446 CHECKOUT
447 . $SC_renewal_policy
448 . $no_block
449 . $transaction_date
450 . $nb_due_date
451 . build_field( FID_INST_ID, $institution_id )
452 . build_field( FID_PATRON_ID, $patron_identifier )
453 . build_field( FID_ITEM_ID, $item_identifier )
454 . build_field( FID_TERMINAL_PWD, $terminal_password )
455 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
456 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
457 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } )
458 . build_field( FID_CANCEL, $cancel, { optional => 1 } );
461 sub build_checkin_command_message {
462 my ($params) = @_;
464 my $no_block = $params->{no_block} || 'N';
465 my $transaction_date = $params->{transaction_date};
466 my $return_date = $params->{return_date};
467 my $current_location = $params->{current_location};
468 my $institution_id = $params->{institution_id};
469 my $item_identifier = $params->{item_identifier};
470 my $terminal_password = $params->{terminal_password};
471 my $item_properties = $params->{item_properties};
472 my $cancel = $params->{cancel} || 'N';
474 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
475 $cancel = $cancel eq 'Y' ? 'Y' : 'N';
477 $return_date ||= $transaction_date;
479 return
480 CHECKIN
481 . $no_block
482 . $transaction_date
483 . $return_date
484 . build_field( FID_CURRENT_LOCN, $current_location )
485 . build_field( FID_INST_ID, $institution_id )
486 . build_field( FID_ITEM_ID, $item_identifier )
487 . build_field( FID_TERMINAL_PWD, $terminal_password )
488 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
489 . build_field( FID_CANCEL, $cancel, { optional => 1 } );
492 sub build_hold_command_message {
493 my ($params) = @_;
495 my $hold_mode = $params->{hold_mode} || '+';
496 my $transaction_date = $params->{transaction_date};
497 my $expiration_date = $params->{expiration_date};
498 my $pickup_location = $params->{pickup_location};
499 my $hold_type = $params->{hold_type};
500 my $institution_id = $params->{institution_id};
501 my $patron_identifier = $params->{patron_identifier};
502 my $patron_password = $params->{patron_password};
503 my $item_identifier = $params->{item_identifier};
504 my $title_identifier = $params->{title_identifier};
505 my $terminal_password = $params->{terminal_password};
506 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
508 return
509 HOLD
510 . $hold_mode
511 . $transaction_date
512 . build_field( FID_EXPIRATION, $expiration_date, { optional => 1 } )
513 . build_field( FID_PICKUP_LOCN, $pickup_location, { optional => 1 } )
514 . build_field( FID_HOLD_TYPE, $hold_type, { optional => 1 } )
515 . build_field( FID_INST_ID, $institution_id )
516 . build_field( FID_PATRON_ID, $patron_identifier )
517 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
518 . build_field( FID_ITEM_ID, $item_identifier, { optional => 1 } )
519 . build_field( FID_TITLE_ID, $title_identifier, { optional => 1 } )
520 . build_field( FID_TERMINAL_PWD, $terminal_password, { optional => 1 } )
521 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } );
524 sub build_renew_command_message {
525 my ($params) = @_;
527 my $third_party_allowed = $params->{third_party_allowed} || 'N';
528 my $no_block = $params->{no_block} || 'N';
529 my $transaction_date = $params->{transaction_date};
530 my $nb_due_date = $params->{nb_due_date};
531 my $institution_id = $params->{institution_id};
532 my $patron_identifier = $params->{patron_identifier};
533 my $patron_password = $params->{patron_password};
534 my $item_identifier = $params->{item_identifier};
535 my $title_identifier = $params->{title_identifier};
536 my $terminal_password = $params->{terminal_password};
537 my $item_properties = $params->{item_properties};
538 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
540 $third_party_allowed = $third_party_allowed eq 'Y' ? 'Y' : 'N';
541 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
542 $fee_acknowledged = $fee_acknowledged eq 'Y' ? 'Y' : 'N';
544 $nb_due_date ||= $transaction_date;
546 return
547 RENEW
548 . $third_party_allowed
549 . $no_block
550 . $transaction_date
551 . $nb_due_date
552 . build_field( FID_INST_ID, $institution_id )
553 . build_field( FID_PATRON_ID, $patron_identifier )
554 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
555 . build_field( FID_ITEM_ID, $item_identifier )
556 . build_field( FID_TITLE_ID, $title_identifier )
557 . build_field( FID_TERMINAL_PWD, $terminal_password )
558 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
559 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } );
562 sub build_fee_paid_command_message {
563 my ($params) = @_;
565 my $transaction_date = $params->{transaction_date};
566 my $fee_type = $params->{fee_type} || '01';
567 my $payment_type = $params->{payment_type} || '00';
568 my $currency_type = $params->{currency_type} || 'USD';
569 my $fee_amount = $params->{fee_amount};
570 my $institution_id = $params->{location_code};
571 my $patron_identifier = $params->{patron_identifier};
572 my $terminal_password = $params->{terminal_password};
573 my $patron_password = $params->{patron_password};
574 my $fee_identifier = $params->{fee_identifier};
575 my $transaction_id = $params->{transaction_id};
577 return
578 FEE_PAID
579 . $transaction_date
580 . $fee_type
581 . $payment_type
582 . $currency_type
583 . build_field( FID_FEE_AMT, $fee_amount )
584 . build_field( FID_INST_ID, $institution_id )
585 . build_field( FID_PATRON_ID, $patron_identifier )
586 . build_field( FID_TERMINAL_PWD, $terminal_password, { optional => 1 } )
587 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
588 . build_field( FID_FEE_ID, $fee_identifier, { optional => 1 } )
589 . build_field( FID_TRANSACTION_ID, $transaction_id, { optional => 1 } );
592 sub build_field {
593 my ( $field_identifier, $value, $params ) = @_;
595 $params //= {};
597 return q{} if ( $params->{optional} && !$value );
599 return $field_identifier . (($value) ? $value : '') . '|';
602 sub help {
603 say q/sip_cli_emulator.pl - SIP command line emulator
605 Test a SIP2 service by sending patron status and patron
606 information requests.
608 Usage:
609 sip_cli_emulator.pl [OPTIONS]
611 Options:
612 --help display help message
614 -a --address SIP server ip address or host name
615 -p --port SIP server port
617 -su --sip_user SIP server login username
618 -sp --sip_pass SIP server login password
620 -l --location SIP location code
622 --patron ILS patron cardnumber or username
623 --password ILS patron password
625 -s --summary Optionally define the patron information request summary field.
626 Please refer to the SIP2 protocol specification for details
628 --item ILS item identifier ( item barcode )
630 -t --terminator SIP2 message terminator, either CR, or CRLF
631 (defaults to CRLF)
633 -fa --fee-acknowledged Sends a confirmation of checkout fee
635 --fee-type Fee type for Fee Paid message, defaults to '01'
636 --payment-type Payment type for Fee Paid message, default to '00'
637 --currency-type Currency type for Fee Paid message, defaults to 'USD'
638 --fee-amount Fee amount for Fee Paid message, required
639 --fee-identifier Fee identifier for Fee Paid message, optional
640 --transaction-id Transaction id for Fee Paid message, optional
641 --pickup-location Pickup location (branchcode) for Hold message, optional
643 -m --message SIP2 message to execute
645 Implemented Messages:
646 checkin
647 checkout
648 fee_paid
649 hold
650 item_information
651 patron_information
652 patron_status_request
653 renew