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;
64 "a|address|host|hostaddress=s" => \$host, # sip server ip
65 "p|port=s" => \$port, # sip server port
66 "su|sip_user=s" => \$login_user_id, # sip user
67 "sp|sip_pass=s" => \$login_password, # sip password
68 "l|location|location_code=s" => \$location_code, # sip location code
70 "patron=s" => \$patron_identifier, # patron cardnumber or login
71 "password=s" => \$patron_password, # patron's password
73 "i|item=s" => \$item_identifier,
75 "fa|fee-acknowledged" => \$fee_acknowledged,
77 "s|summary=s" => \$summary,
79 "fee-type=s" => \$fee_type,
80 "payment-type=s" => \$payment_type,
81 "currency-type=s" => \$currency_type,
82 "fee-amount=s" => \$fee_amount,
83 "fee-identifier=s" => \$fee_identifier,
84 "transaction-id=s" => \$transaction_id,
85 "pickup-location=s" => \$pickup_location,
86 "hold-mode=s" => \$hold_mode,
87 "n|no-block=s" => \$no_block,
89 "t|terminator=s" => \$terminator,
91 "m|message=s" => \@messages,
106 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
107 $terminator = $terminator eq 'CR' ? $CR : $CRLF;
109 # Set perl to expect the same record terminator it is sending
112 my $transaction_date = C4::SIP::Sip::timestamp();
114 my $terminal_password = $login_password;
117 print "Attempting socket connection to $host:$port...";
119 my $socket = IO::Socket::INET->new("$host:$port")
120 or die "failed! : $!\n";
126 subroutine => \&build_login_command_message,
128 login_user_id => $login_user_id,
129 login_password => $login_password,
130 location_code => $location_code,
133 sc_status_request => {
135 subroutine => \&build_sc_status_command_message,
139 patron_status_request => {
140 name => 'Patron Status Request',
141 subroutine => \&build_patron_status_request_command_message,
143 transaction_date => $transaction_date,
144 institution_id => $location_code,
145 patron_identifier => $patron_identifier,
146 terminal_password => $terminal_password,
147 patron_password => $patron_password,
149 optional => [ 'patron_password', ],
151 patron_information => {
152 name => 'Patron Information',
153 subroutine => \&build_patron_information_command_message,
155 transaction_date => $transaction_date,
156 institution_id => $location_code,
157 patron_identifier => $patron_identifier,
158 terminal_password => $terminal_password,
159 patron_password => $patron_password,
162 optional => [ 'patron_password', 'summary' ],
164 item_information => {
165 name => 'Item Information',
166 subroutine => \&build_item_information_command_message,
168 transaction_date => $transaction_date,
169 institution_id => $location_code,
170 item_identifier => $item_identifier,
171 terminal_password => $terminal_password,
177 subroutine => \&build_checkout_command_message,
179 SC_renewal_policy => 'Y',
180 no_block => $no_block,
181 transaction_date => $transaction_date,
182 nb_due_date => undef,
183 institution_id => $location_code,
184 patron_identifier => $patron_identifier,
185 item_identifier => $item_identifier,
186 terminal_password => $terminal_password,
187 item_properties => undef,
188 patron_password => $patron_password,
189 fee_acknowledged => $fee_acknowledged,
193 'nb_due_date', # defaults to transaction date
202 subroutine => \&build_checkin_command_message,
204 no_block => $no_block,
205 transaction_date => $transaction_date,
206 return_date => $transaction_date,
207 current_location => $location_code,
208 institution_id => $location_code,
209 item_identifier => $item_identifier,
210 terminal_password => $terminal_password,
211 item_properties => undef,
215 'return_date', # defaults to transaction date
223 subroutine => \&build_renew_command_message,
225 third_party_allowed => 'N',
226 no_block => $no_block,
227 transaction_date => $transaction_date,
228 nb_due_date => undef,
229 institution_id => $location_code,
230 patron_identifier => $patron_identifier,
231 patron_password => $patron_password,
232 item_identifier => $item_identifier,
233 title_identifier => undef,
234 terminal_password => $terminal_password,
235 item_properties => undef,
236 fee_acknowledged => $fee_acknowledged,
239 'nb_due_date', # defaults to transaction date
250 subroutine => \&build_fee_paid_command_message,
252 transaction_date => $transaction_date,
253 fee_type => $fee_type,
254 payment_type => $payment_type,
255 currency_type => $currency_type,
256 fee_amount => $fee_amount,
257 institution_id => $location_code,
258 patron_identifier => $patron_identifier,
259 terminal_password => $terminal_password,
260 patron_password => $patron_password,
261 fee_identifier => $fee_identifier,
262 transaction_id => $transaction_id,
265 'fee_type', # has default
266 'payment_type', # has default
267 'currency_type', #has default
276 subroutine => \&build_hold_command_message,
278 hold_mode => $hold_mode eq '-' ? '-' : '+',
279 transaction_date => $transaction_date,
280 expiration_date => undef,
281 pickup_location => $pickup_location,
283 institution_id => $location_code,
284 patron_identifier => $patron_identifier,
285 patron_password => $patron_password,
286 item_identifier => $item_identifier,
287 title_identifier => undef,
288 terminal_password => $terminal_password,
289 fee_acknowledged => $fee_acknowledged,
304 my $data = run_command_message('login');
306 if ( $data =~ '^941' ) { ## we are logged in
307 foreach my $m (@messages) {
310 my $data = run_command_message($m);
318 sub build_command_message {
321 ##FIXME It would be much better to use exception handling so we aren't priting from subs
322 unless ( $handlers->{$message} ) {
323 say "$message is an unsupported command!";
327 my $subroutine = $handlers->{$message}->{subroutine};
328 my $parameters = $handlers->{$message}->{parameters};
329 my %optional = map { $_ => 1 } @{ $handlers->{$message}->{optional} };
331 foreach my $key ( keys %$parameters ) {
332 unless ( $parameters->{$key} ) {
333 unless ( $optional{$key} ) {
334 say "$key is required for $message";
340 return &$subroutine($parameters);
343 sub run_command_message {
346 my $command_message = build_command_message($message);
348 return unless $command_message;
350 say "SEND: $command_message";
351 print $socket $command_message . $terminator;
353 my $data = <$socket>;
360 sub build_login_command_message {
363 my $login_user_id = $params->{login_user_id};
364 my $login_password = $params->{login_password};
365 my $location_code = $params->{location_code};
369 . build_field( FID_LOGIN_UID, $login_user_id )
370 . build_field( FID_LOGIN_PWD, $login_password )
371 . build_field( FID_LOCATION_CODE, $location_code );
374 sub build_sc_status_command_message {
377 return SC_STATUS . "0" . "030" . "2.00";
380 sub build_patron_status_request_command_message {
383 my $transaction_date = $params->{transaction_date};
384 my $institution_id = $params->{institution_id};
385 my $patron_identifier = $params->{patron_identifier};
386 my $terminal_password = $params->{terminal_password};
387 my $patron_password = $params->{patron_password};
393 . build_field( FID_INST_ID, $institution_id )
394 . build_field( FID_PATRON_ID, $patron_identifier )
395 . build_field( FID_TERMINAL_PWD, $terminal_password )
396 . build_field( FID_PATRON_PWD, $patron_password );
399 sub build_patron_information_command_message {
402 my $transaction_date = $params->{transaction_date};
403 my $institution_id = $params->{institution_id};
404 my $patron_identifier = $params->{patron_identifier};
405 my $terminal_password = $params->{terminal_password};
406 my $patron_password = $params->{patron_password};
407 my $summary = $params->{summary};
416 . build_field( FID_INST_ID, $institution_id )
417 . build_field( FID_PATRON_ID, $patron_identifier )
418 . build_field( FID_TERMINAL_PWD, $terminal_password )
419 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } );
422 sub build_item_information_command_message {
425 my $transaction_date = $params->{transaction_date};
426 my $institution_id = $params->{institution_id};
427 my $item_identifier = $params->{item_identifier};
428 my $terminal_password = $params->{terminal_password};
434 . build_field( FID_INST_ID, $institution_id )
435 . build_field( FID_ITEM_ID, $item_identifier )
436 . build_field( FID_TERMINAL_PWD, $terminal_password );
439 sub build_checkout_command_message {
442 my $SC_renewal_policy = $params->{SC_renewal_policy} || 'N';
443 my $no_block = $params->{no_block} || 'N';
444 my $transaction_date = $params->{transaction_date};
445 my $nb_due_date = $params->{nb_due_date};
446 my $institution_id = $params->{institution_id};
447 my $patron_identifier = $params->{patron_identifier};
448 my $item_identifier = $params->{item_identifier};
449 my $terminal_password = $params->{terminal_password};
450 my $item_properties = $params->{item_properties};
451 my $patron_password = $params->{patron_password};
452 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
453 my $cancel = $params->{cancel} || 'N';
455 $SC_renewal_policy = $SC_renewal_policy eq 'Y' ? 'Y' : 'N';
456 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
457 $fee_acknowledged = $fee_acknowledged eq 'Y' ? 'Y' : 'N';
458 $cancel = $cancel eq 'Y' ? 'Y' : 'N';
460 $nb_due_date ||= $transaction_date;
468 . build_field( FID_INST_ID, $institution_id )
469 . build_field( FID_PATRON_ID, $patron_identifier )
470 . build_field( FID_ITEM_ID, $item_identifier )
471 . build_field( FID_TERMINAL_PWD, $terminal_password )
472 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
473 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
474 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } )
475 . build_field( FID_CANCEL, $cancel, { optional => 1 } );
478 sub build_checkin_command_message {
481 my $no_block = $params->{no_block} || 'N';
482 my $transaction_date = $params->{transaction_date};
483 my $return_date = $params->{return_date};
484 my $current_location = $params->{current_location};
485 my $institution_id = $params->{institution_id};
486 my $item_identifier = $params->{item_identifier};
487 my $terminal_password = $params->{terminal_password};
488 my $item_properties = $params->{item_properties};
489 my $cancel = $params->{cancel} || 'N';
491 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
492 $cancel = $cancel eq 'Y' ? 'Y' : 'N';
494 $return_date ||= $transaction_date;
501 . build_field( FID_CURRENT_LOCN, $current_location )
502 . build_field( FID_INST_ID, $institution_id )
503 . build_field( FID_ITEM_ID, $item_identifier )
504 . build_field( FID_TERMINAL_PWD, $terminal_password )
505 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
506 . build_field( FID_CANCEL, $cancel, { optional => 1 } );
509 sub build_hold_command_message {
512 my $hold_mode = $params->{hold_mode};
513 my $transaction_date = $params->{transaction_date};
514 my $expiration_date = $params->{expiration_date};
515 my $pickup_location = $params->{pickup_location};
516 my $hold_type = $params->{hold_type};
517 my $institution_id = $params->{institution_id};
518 my $patron_identifier = $params->{patron_identifier};
519 my $patron_password = $params->{patron_password};
520 my $item_identifier = $params->{item_identifier};
521 my $title_identifier = $params->{title_identifier};
522 my $terminal_password = $params->{terminal_password};
523 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
529 . build_field( FID_EXPIRATION, $expiration_date, { optional => 1 } )
530 . build_field( FID_PICKUP_LOCN, $pickup_location, { optional => 1 } )
531 . build_field( FID_HOLD_TYPE, $hold_type, { optional => 1 } )
532 . build_field( FID_INST_ID, $institution_id )
533 . build_field( FID_PATRON_ID, $patron_identifier )
534 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
535 . build_field( FID_ITEM_ID, $item_identifier, { optional => 1 } )
536 . build_field( FID_TITLE_ID, $title_identifier, { optional => 1 } )
537 . build_field( FID_TERMINAL_PWD, $terminal_password, { optional => 1 } )
538 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } );
541 sub build_renew_command_message {
544 my $third_party_allowed = $params->{third_party_allowed} || 'N';
545 my $no_block = $params->{no_block} || 'N';
546 my $transaction_date = $params->{transaction_date};
547 my $nb_due_date = $params->{nb_due_date};
548 my $institution_id = $params->{institution_id};
549 my $patron_identifier = $params->{patron_identifier};
550 my $patron_password = $params->{patron_password};
551 my $item_identifier = $params->{item_identifier};
552 my $title_identifier = $params->{title_identifier};
553 my $terminal_password = $params->{terminal_password};
554 my $item_properties = $params->{item_properties};
555 my $fee_acknowledged = $params->{fee_acknowledged} || 'N';
557 $third_party_allowed = $third_party_allowed eq 'Y' ? 'Y' : 'N';
558 $no_block = $no_block eq 'Y' ? 'Y' : 'N';
559 $fee_acknowledged = $fee_acknowledged eq 'Y' ? 'Y' : 'N';
561 $nb_due_date ||= $transaction_date;
565 . $third_party_allowed
569 . build_field( FID_INST_ID, $institution_id )
570 . build_field( FID_PATRON_ID, $patron_identifier )
571 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
572 . build_field( FID_ITEM_ID, $item_identifier )
573 . build_field( FID_TITLE_ID, $title_identifier )
574 . build_field( FID_TERMINAL_PWD, $terminal_password )
575 . build_field( FID_ITEM_PROPS, $item_properties, { optional => 1 } )
576 . build_field( FID_FEE_ACK, $fee_acknowledged, { optional => 1 } );
579 sub build_fee_paid_command_message {
582 my $transaction_date = $params->{transaction_date};
583 my $fee_type = $params->{fee_type} || '01';
584 my $payment_type = $params->{payment_type} || '00';
585 my $currency_type = $params->{currency_type} || 'USD';
586 my $fee_amount = $params->{fee_amount};
587 my $institution_id = $params->{location_code};
588 my $patron_identifier = $params->{patron_identifier};
589 my $terminal_password = $params->{terminal_password};
590 my $patron_password = $params->{patron_password};
591 my $fee_identifier = $params->{fee_identifier};
592 my $transaction_id = $params->{transaction_id};
600 . build_field( FID_FEE_AMT, $fee_amount )
601 . build_field( FID_INST_ID, $institution_id )
602 . build_field( FID_PATRON_ID, $patron_identifier )
603 . build_field( FID_TERMINAL_PWD, $terminal_password, { optional => 1 } )
604 . build_field( FID_PATRON_PWD, $patron_password, { optional => 1 } )
605 . build_field( FID_FEE_ID, $fee_identifier, { optional => 1 } )
606 . build_field( FID_TRANSACTION_ID, $transaction_id, { optional => 1 } );
610 my ( $field_identifier, $value, $params ) = @_;
614 return q{} if ( $params->{optional} && !$value );
616 return $field_identifier . (($value) ? $value : '') . '|';
620 say q/sip_cli_emulator.pl - SIP command line emulator
622 Test a SIP2 service by sending patron status and patron
623 information requests.
626 sip_cli_emulator.pl [OPTIONS]
629 --help display help message
631 -a --address SIP server ip address or host name
632 -p --port SIP server port
634 -su --sip_user SIP server login username
635 -sp --sip_pass SIP server login password
637 -l --location SIP location code
639 --patron ILS patron cardnumber or username
640 --password ILS patron password
642 -s --summary Optionally define the patron information request summary field.
643 Please refer to the SIP2 protocol specification for details
645 --item ILS item identifier ( item barcode )
647 -t --terminator SIP2 message terminator, either CR, or CRLF
650 -fa --fee-acknowledged Sends a confirmation of checkout fee
652 --fee-type Fee type for Fee Paid message, defaults to '01'
653 --payment-type Payment type for Fee Paid message, default to '00'
654 --currency-type Currency type for Fee Paid message, defaults to 'USD'
655 --fee-amount Fee amount for Fee Paid message, required
656 --fee-identifier Fee identifier for Fee Paid message, optional
657 --transaction-id Transaction id for Fee Paid message, optional
658 --pickup-location Pickup location (branchcode) for Hold message, optional
659 --hold-mode Accepts "+" to add hold or "-" to cancel hold, defaults to +
660 -n --no-block Accepts "N" for standard operatoin, "Y" for no-block, defaults to "N"
662 -m --message SIP2 message to execute
664 Implemented Messages:
671 patron_status_request