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>.
26 use C4::SIP::Sip::Constants qw(:all);
29 use constant { LANGUAGE => '001' };
40 my $patron_identifier;
47 my $fee_acknowledged = 0;
63 "a|address|host|hostaddress=s" => \$host, # sip server ip
64 "p|port=s" => \$port, # sip server port
65 "su|sip_user=s" => \$login_user_id, # sip user
66 "sp|sip_pass=s" => \$login_password, # sip password
67 "l|location|location_code=s" => \$location_code, # sip location code
69 "patron=s" => \$patron_identifier, # patron cardnumber or login
70 "password=s" => \$patron_password, # patron's password
72 "i|item=s" => \$item_identifier,
74 "fa|fee-acknowledged" => \$fee_acknowledged,
76 "s|summary=s" => \$summary,
78 "fee-type=s" => \$fee_type,
79 "payment-type=s" => \$payment_type,
80 "currency-type=s" => \$currency_type,
81 "fee-amount=s" => \$fee_amount,
82 "fee-identifier=s" => \$fee_identifier,
83 "transaction-id=s" => \$transaction_id,
84 "pickup-location=s" => \$pickup_location,
85 "hold-mode=s" => \$hold_mode,
87 "t|terminator=s" => \$terminator,
89 "m|message=s" => \@messages,
104 $terminator = ( $terminator eq 'CR' ) ? $CR : $CRLF;
106 # Set perl to expect the same record terminator it is sending
109 my $transaction_date = C4::SIP::Sip::timestamp();
111 my $terminal_password = $login_password;
114 print "Attempting socket connection to $host:$port...";
116 my $socket = IO::Socket::INET->new("$host:$port")
117 or die "failed! : $!\n";
123 subroutine => \&build_login_command_message,
125 login_user_id => $login_user_id,
126 login_password => $login_password,
127 location_code => $location_code,
130 patron_status_request => {
131 name => 'Patron Status Request',
132 subroutine => \&build_patron_status_request_command_message,
134 transaction_date => $transaction_date,
135 institution_id => $location_code,
136 patron_identifier => $patron_identifier,
137 terminal_password => $terminal_password,
138 patron_password => $patron_password,
140 optional => [ 'patron_password', ],
142 patron_information => {
143 name => 'Patron Information',
144 subroutine => \&build_patron_information_command_message,
146 transaction_date => $transaction_date,
147 institution_id => $location_code,
148 patron_identifier => $patron_identifier,
149 terminal_password => $terminal_password,
150 patron_password => $patron_password,
153 optional => [ 'patron_password', 'summary' ],
155 item_information => {
156 name => 'Item Information',
157 subroutine => \&build_item_information_command_message,
159 transaction_date => $transaction_date,
160 institution_id => $location_code,
161 item_identifier => $item_identifier,
162 terminal_password => $terminal_password,
168 subroutine => \&build_checkout_command_message,
170 SC_renewal_policy => 'Y',
172 transaction_date => $transaction_date,
173 nb_due_date => undef,
174 institution_id => $location_code,
175 patron_identifier => $patron_identifier,
176 item_identifier => $item_identifier,
177 terminal_password => $terminal_password,
178 item_properties => undef,
179 patron_password => $patron_password,
180 fee_acknowledged => $fee_acknowledged,
184 'nb_due_date', # defaults to transaction date
193 subroutine => \&build_checkin_command_message,
196 transaction_date => $transaction_date,
197 return_date => $transaction_date,
198 current_location => $location_code,
199 institution_id => $location_code,
200 item_identifier => $item_identifier,
201 terminal_password => $terminal_password,
202 item_properties => undef,
206 'return_date', # defaults to transaction date
214 subroutine => \&build_renew_command_message,
216 third_party_allowed => 'N',
218 transaction_date => $transaction_date,
219 nb_due_date => undef,
220 institution_id => $location_code,
221 patron_identifier => $patron_identifier,
222 patron_password => $patron_password,
223 item_identifier => $item_identifier,
224 title_identifier => undef,
225 terminal_password => $terminal_password,
226 item_properties => undef,
227 fee_acknowledged => $fee_acknowledged,
230 'nb_due_date', # defaults to transaction date
241 subroutine => \&build_fee_paid_command_message,
243 transaction_date => $transaction_date,
244 fee_type => $fee_type,
245 payment_type => $payment_type,
246 currency_type => $currency_type,
247 fee_amount => $fee_amount,
248 institution_id => $location_code,
249 patron_identifier => $patron_identifier,
250 terminal_password => $terminal_password,
251 patron_password => $patron_password,
252 fee_identifier => $fee_identifier,
253 transaction_id => $transaction_id,
256 'fee_type', # has default
257 'payment_type', # has default
258 'currency_type', #has default
267 subroutine => \&build_hold_command_message,
269 hold_mode => $hold_mode eq '-' ? '-' : '+',
270 transaction_date => $transaction_date,
271 expiration_date => undef,
272 pickup_location => $pickup_location,
274 institution_id => $location_code,
275 patron_identifier => $patron_identifier,
276 patron_password => $patron_password,
277 item_identifier => $item_identifier,
278 title_identifier => undef,
279 terminal_password => $terminal_password,
280 fee_acknowledged => $fee_acknowledged,
295 my $data = run_command_message('login');
297 if ( $data =~ '^941' ) { ## we are logged in
298 foreach my $m (@messages) {
301 my $data = run_command_message($m);
309 sub build_command_message {
312 ##FIXME It would be much better to use exception handling so we aren't priting from subs
313 unless ( $handlers->{$message} ) {
314 say "$message is an unsupported command!";
318 my $subroutine = $handlers->{$message}->{subroutine};
319 my $parameters = $handlers->{$message}->{parameters};
320 my %optional = map { $_ => 1 } @{ $handlers->{$message}->{optional} };
322 foreach my $key ( keys %$parameters ) {
323 unless ( $parameters->{$key} ) {
324 unless ( $optional{$key} ) {
325 say "$key is required for $message";
331 return &$subroutine($parameters);
334 sub run_command_message {
337 my $command_message = build_command_message($message);
339 return unless $command_message;
341 say "SEND: $command_message";
342 print $socket $command_message . $terminator;
344 my $data = <$socket>;
351 sub build_login_command_message {
354 my $login_user_id = $params->{login_user_id};
355 my $login_password = $params->{login_password};
356 my $location_code = $params->{location_code};
360 . build_field( FID_LOGIN_UID, $login_user_id )
361 . build_field( FID_LOGIN_PWD, $login_password )
362 . build_field( FID_LOCATION_CODE, $location_code );
365 sub build_patron_status_request_command_message {
368 my $transaction_date = $params->{transaction_date};
369 my $institution_id = $params->{institution_id};
370 my $patron_identifier = $params->{patron_identifier};
371 my $terminal_password = $params->{terminal_password};
372 my $patron_password = $params->{patron_password};
378 . build_field( FID_INST_ID, $institution_id )
379 . build_field( FID_PATRON_ID, $patron_identifier )
380 . build_field( FID_TERMINAL_PWD, $terminal_password )
381 . build_field( FID_PATRON_PWD, $patron_password );
384 sub build_patron_information_command_message {
387 my $transaction_date = $params->{transaction_date};
388 my $institution_id = $params->{institution_id};
389 my $patron_identifier = $params->{patron_identifier};
390 my $terminal_password = $params->{terminal_password};
391 my $patron_password = $params->{patron_password};
392 my $summary = $params->{summary};
401 . build_field( FID_INST_ID, $institution_id )
402 . build_field( FID_PATRON_ID, $patron_identifier )
403 . build_field( FID_TERMINAL_PWD, $terminal_password )
404 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } );
407 sub build_item_information_command_message {
410 my $transaction_date = $params->{transaction_date};
411 my $institution_id = $params->{institution_id};
412 my $item_identifier = $params->{item_identifier};
413 my $terminal_password = $params->{terminal_password};
419 . build_field( FID_INST_ID, $institution_id )
420 . build_field( FID_ITEM_ID, $item_identifier )
421 . build_field( FID_TERMINAL_PWD, $terminal_password );
424 sub build_checkout_command_message {
427 my $SC_renewal_policy = $params->{SC_renewal_policy} || 'N';
428 my $no_block = $params->{no_block} || 'N';
429 my $transaction_date = $params->{transaction_date};
430 my $nb_due_date = $params->{nb_due_date};
431 my $institution_id = $params->{institution_id};
432 my $patron_identifier = $params->{patron_identifier};
433 my $item_identifier = $params->{item_identifier};
434 my $terminal_password = $params->{terminal_password};
435 my $item_properties = $params->{item_properties};
436 my $patron_password = $params->{patron_password};
437 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
438 my $cancel = $params->{cancel} || 'N';
440 $SC_renewal_policy = $SC_renewal_policy eq 'Y' ? 'Y' : 'N';
441 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
442 $fee_acknowledged = $fee_acknowledged eq 'Y' ? 'Y' : 'N';
443 $cancel = $cancel eq 'Y' ? 'Y' : 'N';
445 $nb_due_date ||= $transaction_date;
453 . build_field( FID_INST_ID, $institution_id )
454 . build_field( FID_PATRON_ID, $patron_identifier )
455 . build_field( FID_ITEM_ID, $item_identifier )
456 . build_field( FID_TERMINAL_PWD, $terminal_password )
457 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
458 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
459 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } )
460 . build_field( FID_CANCEL, $cancel, { optional => 1 } );
463 sub build_checkin_command_message {
466 my $no_block = $params->{no_block} || 'N';
467 my $transaction_date = $params->{transaction_date};
468 my $return_date = $params->{return_date};
469 my $current_location = $params->{current_location};
470 my $institution_id = $params->{institution_id};
471 my $item_identifier = $params->{item_identifier};
472 my $terminal_password = $params->{terminal_password};
473 my $item_properties = $params->{item_properties};
474 my $cancel = $params->{cancel} || 'N';
476 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
477 $cancel = $cancel eq 'Y' ? 'Y' : 'N';
479 $return_date ||= $transaction_date;
486 . build_field( FID_CURRENT_LOCN, $current_location )
487 . build_field( FID_INST_ID, $institution_id )
488 . build_field( FID_ITEM_ID, $item_identifier )
489 . build_field( FID_TERMINAL_PWD, $terminal_password )
490 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
491 . build_field( FID_CANCEL, $cancel, { optional => 1 } );
494 sub build_hold_command_message {
497 my $hold_mode = $params->{hold_mode};
498 my $transaction_date = $params->{transaction_date};
499 my $expiration_date = $params->{expiration_date};
500 my $pickup_location = $params->{pickup_location};
501 my $hold_type = $params->{hold_type};
502 my $institution_id = $params->{institution_id};
503 my $patron_identifier = $params->{patron_identifier};
504 my $patron_password = $params->{patron_password};
505 my $item_identifier = $params->{item_identifier};
506 my $title_identifier = $params->{title_identifier};
507 my $terminal_password = $params->{terminal_password};
508 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
514 . build_field( FID_EXPIRATION, $expiration_date, { optional => 1 } )
515 . build_field( FID_PICKUP_LOCN, $pickup_location, { optional => 1 } )
516 . build_field( FID_HOLD_TYPE, $hold_type, { optional => 1 } )
517 . build_field( FID_INST_ID, $institution_id )
518 . build_field( FID_PATRON_ID, $patron_identifier )
519 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
520 . build_field( FID_ITEM_ID, $item_identifier, { optional => 1 } )
521 . build_field( FID_TITLE_ID, $title_identifier, { optional => 1 } )
522 . build_field( FID_TERMINAL_PWD, $terminal_password, { optional => 1 } )
523 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } );
526 sub build_renew_command_message {
529 my $third_party_allowed = $params->{third_party_allowed} || 'N';
530 my $no_block = $params->{no_block} || 'N';
531 my $transaction_date = $params->{transaction_date};
532 my $nb_due_date = $params->{nb_due_date};
533 my $institution_id = $params->{institution_id};
534 my $patron_identifier = $params->{patron_identifier};
535 my $patron_password = $params->{patron_password};
536 my $item_identifier = $params->{item_identifier};
537 my $title_identifier = $params->{title_identifier};
538 my $terminal_password = $params->{terminal_password};
539 my $item_properties = $params->{item_properties};
540 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
542 $third_party_allowed = $third_party_allowed eq 'Y' ? 'Y' : 'N';
543 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
544 $fee_acknowledged = $fee_acknowledged eq 'Y' ? 'Y' : 'N';
546 $nb_due_date ||= $transaction_date;
550 . $third_party_allowed
554 . build_field( FID_INST_ID, $institution_id )
555 . build_field( FID_PATRON_ID, $patron_identifier )
556 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
557 . build_field( FID_ITEM_ID, $item_identifier )
558 . build_field( FID_TITLE_ID, $title_identifier )
559 . build_field( FID_TERMINAL_PWD, $terminal_password )
560 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
561 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } );
564 sub build_fee_paid_command_message {
567 my $transaction_date = $params->{transaction_date};
568 my $fee_type = $params->{fee_type} || '01';
569 my $payment_type = $params->{payment_type} || '00';
570 my $currency_type = $params->{currency_type} || 'USD';
571 my $fee_amount = $params->{fee_amount};
572 my $institution_id = $params->{location_code};
573 my $patron_identifier = $params->{patron_identifier};
574 my $terminal_password = $params->{terminal_password};
575 my $patron_password = $params->{patron_password};
576 my $fee_identifier = $params->{fee_identifier};
577 my $transaction_id = $params->{transaction_id};
585 . build_field( FID_FEE_AMT, $fee_amount )
586 . build_field( FID_INST_ID, $institution_id )
587 . build_field( FID_PATRON_ID, $patron_identifier )
588 . build_field( FID_TERMINAL_PWD, $terminal_password, { optional => 1 } )
589 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
590 . build_field( FID_FEE_ID, $fee_identifier, { optional => 1 } )
591 . build_field( FID_TRANSACTION_ID, $transaction_id, { optional => 1 } );
595 my ( $field_identifier, $value, $params ) = @_;
599 return q{} if ( $params->{optional} && !$value );
601 return $field_identifier . (($value) ? $value : '') . '|';
605 say q/sip_cli_emulator.pl - SIP command line emulator
607 Test a SIP2 service by sending patron status and patron
608 information requests.
611 sip_cli_emulator.pl [OPTIONS]
614 --help display help message
616 -a --address SIP server ip address or host name
617 -p --port SIP server port
619 -su --sip_user SIP server login username
620 -sp --sip_pass SIP server login password
622 -l --location SIP location code
624 --patron ILS patron cardnumber or username
625 --password ILS patron password
627 -s --summary Optionally define the patron information request summary field.
628 Please refer to the SIP2 protocol specification for details
630 --item ILS item identifier ( item barcode )
632 -t --terminator SIP2 message terminator, either CR, or CRLF
635 -fa --fee-acknowledged Sends a confirmation of checkout fee
637 --fee-type Fee type for Fee Paid message, defaults to '01'
638 --payment-type Payment type for Fee Paid message, default to '00'
639 --currency-type Currency type for Fee Paid message, defaults to 'USD'
640 --fee-amount Fee amount for Fee Paid message, required
641 --fee-identifier Fee identifier for Fee Paid message, optional
642 --transaction-id Transaction id for Fee Paid message, optional
643 --pickup-location Pickup location (branchcode) for Hold message, optional
644 --hold-mode Accepts "+" to add hold or "-" to cancel hold, defaults to +
646 -m --message SIP2 message to execute
648 Implemented Messages:
655 patron_status_request