From: erickson Date: Thu, 13 Jul 2006 22:00:10 +0000 (+0000) Subject: adding X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=6d86e1b7fd19d1b79f901d46622e3bc360266e0c;p=Evergreen.git adding much work required git-svn-id: svn://svn.open-ils.org/ILS/trunk@4989 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- diff --git a/Open-ILS/src/perlmods/OpenILS/SIP.pm b/Open-ILS/src/perlmods/OpenILS/SIP.pm new file mode 100644 index 0000000000..91beb5ef7c --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/SIP.pm @@ -0,0 +1,555 @@ +# +# ILS.pm: Test ILS interface module +# + +package OpenILS::SIP; +use warnings; use strict; + +use Sys::Syslog qw(syslog); + +use OpenILS::SIP::Item; +use OpenILS::SIP::Patron; +use OpenILS::SIP::Transaction; +use OpenILS::SIP::Transaction::Checkout; +use OpenILS::SIP::Transaction::Checkin; +use OpenILS::SIP::Transaction::FeePayment; +use OpenILS::SIP::Transaction::Hold; +use OpenILS::SIP::Transaction::Renew; +use OpenILS::SIP::Transaction::RenewAll; + + +use OpenSRF::System; +use OpenILS::Utils::Fieldmapper; +use OpenSRF::Utils::SettingsClient; +use OpenILS::Application::AppUtils; + +use Digest::MD5 qw(md5_hex); + +my $U = 'OpenILS::Application::AppUtils'; + +# PUT ME IN THE CONFIG XXX +my %supports = ( + 'magnetic media' => 1, + 'security inhibit' => 0, + 'offline operation' => 0 + ); + + +sub new { + my ($class, $institution, $login) = @_; + my $type = ref($class) || $class; + my $self = {}; + + syslog("LOG_DEBUG", "new ILS '%s'", $institution->{id}); + $self->{institution} = $institution; + + my $config = $institution->{implementation_config}->{bootstrap}; + + syslog('LOG_DEBUG', "loading bootstrap config: $config"); + + local $/ = "\n"; + OpenSRF::System->bootstrap_client(config_file => $config); + syslog('LOG_DEBUG', "bootstrap loaded.."); + + $self->{osrf_config} = OpenSRF::Utils::SettingsClient->new; + + Fieldmapper->import($self->{osrf_config}->config_value('IDL')); + + bless( $self, $type ); + + return undef unless + $self->login( $login->{id}, $login->{password} ); + + return $self; +} + +sub login { + my( $self, $username, $password ) = @_; + syslog('LOG_DEBUG', "OpenILS: Logging in with username $username"); + + my $seed = $U->simplereq( + 'open-ils.auth', + 'open-ils.auth.authenticate.init', $username ); + + my $response = $U->simplereq( + 'open-ils.auth', + 'open-ils.auth.authenticate.complete', + { + username => $username, + password => md5_hex($seed . md5_hex($password)), + type => 'opac', + } + ); + + my $key; + if( ref($response) eq 'HASH' and $response->{payload} + and $key = $response->{payload}->{authtoken} ) { + syslog('LOG_INFO', "OpenILS: Login succeeded for $username : authkey = $key"); + + } else { + syslog('LOG_WARN', "OpenILS: Login failed for $username"); + } + + return $self->{authtoken} = $key; +} + + +sub find_patron { + my $self = shift; + return OpenILS::SIP::Patron->new(@_); +} + + +sub find_item { + my $self = shift; + return OpenILS::SIP::Item->new(@_); +} + + +sub institution { + my $self = shift; + + return $self->{institution}->{id}; +} + + +# XXX Get me from the config? +sub supports { + my ($self, $op) = @_; + return exists($supports{$op}) ? $supports{$op} : 0; +} + +sub check_inst_id { + my ($self, $id, $whence) = @_; + + if ($id ne $self->{institution}->{id}) { + syslog("LOG_WARNING", "%s: received institution '%s', expected '%s'", + $whence, $id, $self->{institution}->{id}); + } +} + + + + +# XXX by default, these should come from the config +sub checkout_ok { + return 1; +} + +sub checkin_ok { + return 0; +} + +sub status_update_ok { + return 1; +} + +sub offline_ok { + return 0; +} + + +## +## Checkout(patron_id, item_id, sc_renew): +## patron_id & item_id are the identifiers send by the terminal +## sc_renew is the renewal policy configured on the terminal +## returns a status opject that can be queried for the various bits +## of information that the protocol (SIP or NCIP) needs to generate +## the response. +## + +sub checkout { + my ($self, $patron_id, $item_id, $sc_renew) = @_; + + syslog('LOG_DEBUG', "OpenILS::Checkout attempt: patron=$patron_id, item=$item_id"); + + my $xact = OpenILS::SIP::Transaction::Checkout->new( authtoken => $self->{authtoken} ); + my $patron = OpenILS::SIP::Patron->new($patron_id); + my $item = OpenILS::SIP::Item->new($item_id); + + $xact->patron($patron); + $xact->item($item); + + if (!$patron) { + $xact->screen_msg("Invalid Patron"); + return $xact; + } + + if (!$patron->charge_ok) { + $xact->screen_msg("Patron Blocked"); + return $xact; + } + + if( !$item ) { + $xact->screen_msg("Invalid Item"); + return $xact; + } + + syslog('LOG_DEBUG', "OpenILS::Checkout data loaded OK, checking out..."); + $xact->do_checkout(); + + if ($item->{patron} && ($item->{patron} ne $patron_id)) { + # I can't deal with this right now + # XXX check in then check out? + $xact->screen_msg("Item checked out to another patron"); + $xact->ok(0); + } + + $xact->desensitize(!$item->magnetic); + + if( $xact->ok ) { + + $xact->editor->commit; + syslog("LOG_DEBUG", "OpenILS::Checkout: " . + "patron %s checke out %s succeeded", $patron_id, $item_id); + + } else { + + $xact->editor->xact_rollback; + syslog("LOG_DEBUG", "OpenILS::Checkout: " . + "patron %s checke out %s FAILED, rolling back xact...", $patron_id, $item_id); + } + + return $xact; +} + + +sub checkin { + my ($self, $item_id, $trans_date, $return_date, + $current_loc, $item_props, $cancel) = @_; + + syslog('LOG_DEBUG', "OpenILS::Checkin on item=$item_id"); + + my $patron; + my $xact = OpenILS::SIP::Transaction::Checkin->new(authtoken => $self->{authtoken}); + my $item = OpenILS::SIP::Item->new($item_id); + + $xact->item($item); + + $xact->do_checkin( $trans_date, $return_date, $current_loc, $item_props ); + + if ($xact->ok) { + + $xact->patron($patron = OpenILS::SIP::Patron->new($item->{patron})); + delete $item->{patron}; + delete $item->{due_date}; + syslog('LOG_INFO', "OpenILS: Checkin succeeded"); + $xact->editor->commit; + + } else { + + $xact->editor->xact_rollback; + syslog('LOG_WARNING', "OpenILS: Checkin failed"); + } + # END TRANSACTION + + return $xact; +} + + + + +## If the ILS caches patron information, this lets it free +## it up +#sub end_patron_session { +# my ($self, $patron_id) = @_; +# +# # success?, screen_msg, print_line +# return (1, 'Thank you for using OpenILS!', ''); +#} +# +#sub pay_fee { +# my ($self, $patron_id, $patron_pwd, $fee_amt, $fee_type, +# $pay_type, $fee_id, $trans_id, $currency) = @_; +# my $trans; +# my $patron; +# +# $trans = new ILS::Transaction::FeePayment; +# +# $patron = new ILS::Patron $patron_id; +# +# $trans->transaction_id($trans_id); +# $trans->patron($patron); +# $trans->ok(1); +# +# return $trans; +#} +# +#sub add_hold { +# my ($self, $patron_id, $patron_pwd, $item_id, $title_id, +# $expiry_date, $pickup_location, $hold_type, $fee_ack) = @_; +# my ($patron, $item); +# my $hold; +# my $trans; +# +# +# $trans = new ILS::Transaction::Hold; +# +# # BEGIN TRANSACTION +# $patron = new ILS::Patron $patron_id; +# if (!$patron +# || (defined($patron_pwd) && !$patron->check_password($patron_pwd))) { +# $trans->screen_msg("Invalid Patron."); +# +# return $trans; +# } +# +# $item = new ILS::Item ($item_id || $title_id); +# if (!$item) { +# $trans->screen_msg("No such item."); +# +# # END TRANSACTION (conditionally) +# return $trans; +# } elsif ($item->fee && ($fee_ack ne 'Y')) { +# $trans->screen_msg = "Fee required to place hold."; +# +# # END TRANSACTION (conditionally) +# return $trans; +# } +# +# $hold = { +# item_id => $item->id, +# patron_id => $patron->id, +# expiration_date => $expiry_date, +# pickup_location => $pickup_location, +# hold_type => $hold_type, +# }; +# +# $trans->ok(1); +# $trans->patron($patron); +# $trans->item($item); +# $trans->pickup_location($pickup_location); +# +# push(@{$item->hold_queue}, $hold); +# push(@{$patron->{hold_items}}, $hold); +# +# +# # END TRANSACTION +# return $trans; +#} +# +#sub cancel_hold { +# my ($self, $patron_id, $patron_pwd, $item_id, $title_id) = @_; +# my ($patron, $item, $hold); +# my $trans; +# +# $trans = new ILS::Transaction::Hold; +# +# # BEGIN TRANSACTION +# $patron = new ILS::Patron $patron_id; +# if (!$patron) { +# $trans->screen_msg("Invalid patron barcode."); +# +# return $trans; +# } elsif (defined($patron_pwd) && !$patron->check_password($patron_pwd)) { +# $trans->screen_msg('Invalid patron password.'); +# +# return $trans; +# } +# +# $item = new ILS::Item ($item_id || $title_id); +# if (!$item) { +# $trans->screen_msg("No such item."); +# +# # END TRANSACTION (conditionally) +# return $trans; +# } +# +# # Remove the hold from the patron's record first +# $trans->ok($patron->drop_hold($item_id)); +# +# if (!$trans->ok) { +# # We didn't find it on the patron record +# $trans->screen_msg("No such hold on patron record."); +# +# # END TRANSACTION (conditionally) +# return $trans; +# } +# +# # Now, remove it from the item record. If it was on the patron +# # record but not on the item record, we'll treat that as success. +# foreach my $i (0 .. scalar @{$item->hold_queue}) { +# $hold = $item->hold_queue->[$i]; +# +# if ($hold->{patron_id} eq $patron->id) { +# # found it: delete it. +# splice @{$item->hold_queue}, $i, 1; +# last; +# } +# } +# +# $trans->screen_msg("Hold Cancelled."); +# $trans->patron($patron); +# $trans->item($item); +# +# return $trans; +#} +# +# +## The patron and item id's can't be altered, but the +## date, location, and type can. +#sub alter_hold { +# my ($self, $patron_id, $patron_pwd, $item_id, $title_id, +# $expiry_date, $pickup_location, $hold_type, $fee_ack) = @_; +# my ($patron, $item); +# my $hold; +# my $trans; +# +# $trans = new ILS::Transaction::Hold; +# +# # BEGIN TRANSACTION +# $patron = new ILS::Patron $patron_id; +# if (!$patron) { +# $trans->screen_msg("Invalid patron barcode."); +# +# return $trans; +# } +# +# foreach my $i (0 .. scalar @{$patron->{hold_items}}) { +# $hold = $patron->{hold_items}[$i]; +# +# if ($hold->{item_id} eq $item_id) { +# # Found it. So fix it. +# $hold->{expiration_date} = $expiry_date if $expiry_date; +# $hold->{pickup_location} = $pickup_location if $pickup_location; +# $hold->{hold_type} = $hold_type if $hold_type; +# +# $trans->ok(1); +# $trans->screen_msg("Hold updated."); +# $trans->patron($patron); +# $trans->item(new ILS::Item $hold->{item_id}); +# last; +# } +# } +# +# # The same hold structure is linked into both the patron's +# # list of hold items and into the queue of outstanding holds +# # for the item, so we don't need to search the hold queue for +# # the item, since it's already been updated by the patron code. +# +# if (!$trans->ok) { +# $trans->screen_msg("No such outstanding hold."); +# } +# +# return $trans; +#} +# +#sub renew { +# my ($self, $patron_id, $patron_pwd, $item_id, $title_id, +# $no_block, $nb_due_date, $third_party, +# $item_props, $fee_ack) = @_; +# my ($patron, $item); +# my $trans; +# +# $trans = new ILS::Transaction::Renew; +# +# $trans->patron($patron = new ILS::Patron $patron_id); +# if (!$patron) { +# $trans->screen_msg("Invalid patron barcode."); +# +# return $trans; +# } elsif (!$patron->renew_ok) { +# +# $trans->screen_msg("Renewals not allowed."); +# +# return $trans; +# } +# +# if (defined($title_id)) { +# # renewing a title, rather than an item (sort of) +# # This is gross, but in a real ILS it would be better +# foreach my $i (@{$patron->{items}}) { +# $item = new ILS::Item $i; +# last if ($title_id eq $item->title_id); +# $item = undef; +# } +# } else { +# foreach my $i (@{$patron->{items}}) { +# if ($i == $item_id) { +# # We have it checked out +# $item = new ILS::Item $item_id; +# last; +# } +# } +# } +# +# if (!defined($item)) { +# # It's not checked out to $patron_id +# $trans->screen_msg("Item not checked out to " . $patron->name); +# } elsif (!$item->available($patron_id)) { +# $trans->screen_msg("Item has outstanding holds"); +# } else { +# $trans->item($item); +# $trans->renewal_ok(1); +# +# $trans->desensitize(0); # It's already checked out +# +# if ($no_block eq 'Y') { +# $item->{due_date} = $nb_due_date; +# } else { +# $item->{due_date} = time + (14*24*60*60); # two weeks +# } +# if ($item_props) { +# $item->{sip_item_properties} = $item_props; +# } +# $trans->ok(1); +# $trans->renewal_ok(1); +# +# return $trans; +# } +# +# return $trans; +#} +# +#sub renew_all { +# my ($self, $patron_id, $patron_pwd, $fee_ack) = @_; +# my ($patron, $item_id); +# my $trans; +# +# $trans = new ILS::Transaction::RenewAll; +# +# $trans->patron($patron = new ILS::Patron $patron_id); +# if (defined $patron) { +# syslog("LOG_DEBUG", "ILS::renew_all: patron '%s': renew_ok: %s", +# $patron->name, $patron->renew_ok); +# } else { +# syslog("LOG_DEBUG", "ILS::renew_all: Invalid patron id: '%s'", +# $patron_id); +# } +# +# if (!defined($patron)) { +# $trans->screen_msg("Invalid patron barcode."); +# return $trans; +# } elsif (!$patron->renew_ok) { +# $trans->screen_msg("Renewals not allowed."); +# return $trans; +# } elsif (defined($patron_pwd) && !$patron->check_password($patron_pwd)) { +# $trans->screen_msg("Invalid patron password."); +# return $trans; +# } +# +# foreach $item_id (@{$patron->{items}}) { +# my $item = new ILS::Item $item_id; +# +# if (!defined($item)) { +# syslog("LOG_WARNING", +# "renew_all: Invalid item id associated with patron '%s'", +# $patron->id); +# next; +# } +# +# if (@{$item->hold_queue}) { +# # Can't renew if there are outstanding holds +# push @{$trans->unrenewed}, $item_id; +# } else { +# $item->{due_date} = time + (14*24*60*60); # two weeks hence +# push @{$trans->renewed}, $item_id; +# } +# } +# +# $trans->ok(1); +# +# return $trans; +#} + +1; diff --git a/Open-ILS/src/perlmods/OpenILS/SIP/Item.pm b/Open-ILS/src/perlmods/OpenILS/SIP/Item.pm new file mode 100644 index 0000000000..f7e02be97d --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/SIP/Item.pm @@ -0,0 +1,215 @@ +# +# +# A Class for hiding the ILS's concept of the item from the OpenSIP +# system +# + +package OpenILS::SIP::Item; + +use strict; +use warnings; + +use Sys::Syslog qw(syslog); + +use OpenILS::SIP::Transaction; +use OpenILS::Application::AppUtils; +my $U = 'OpenILS::Application::AppUtils'; + +my %item_db; + +sub new { + my ($class, $item_id) = @_; + my $type = ref($class) || $class; + my $self = {}; + bless $self, $type; + + require OpenILS::Utils::CStoreEditor; + my $e = OpenILS::Utils::CStoreEditor->new; + + if(!UNIVERSAL::can($e, 'search_actor_card')) { + syslog("LOG_WARNING", "Reloading CStoreEditor..."); + delete $INC{'OpenILS/Utils/CStoreEditor.pm'}; + require OpenILS::Utils::CStoreEditor; + $e = OpenILS::Utils::CStoreEditor->new; + } + + + # FLESH ME + my $copy = $e->search_asset_copy( + [ + { barcode => $item_id }, + { + flesh => 3, + flesh_fields => { + acp => [ 'circ_lib', 'call_number' ], + acn => [ 'owning_lib', 'record' ], + } + } + ] + ); + + if(!@$copy) { + syslog("LOG_DEBUG", "OpenILS: Item '%s' : not found", $item_id); + return undef; + } + + $copy = $$copy[0]; + + # XXX See if i am checked out, if so set $self->{patron} to the user's barcode + my ($circ) = $U->fetch_open_circulation($copy->id); + if($circ) { + my $user = $e->retrieve_actor_user( + [ + $circ->usr, + { + flesh => 1, + flesh_fields => { + "au" => [ 'card' ], + } + } + ] + ); + + $self->{patron} = $user->card->barcode if $user; + $self->{patron_object} = $user; + } + + $self->{id} = $item_id; + $self->{copy} = $copy; + $self->{volume} = $copy->call_number; + $self->{record} = $copy->call_number->record; + + $self->{mods} = $U->record_to_mvr($self->{record}) if $self->{record}->marc; + + syslog("LOG_DEBUG", "new OpenILS Item('%s'): found with title '%s'", + $item_id, $self->title_id); + + return $self; +} + +sub magnetic { + my $self = shift; + return 0; +} + +sub sip_media_type { + my $self = shift; + return '001'; +} + +sub sip_item_properties { + my $self = shift; + return ""; +} + +sub status_update { + my ($self, $props) = @_; + my $status = new OpenILS::SIP::Transaction; + $self->{sip_item_properties} = $props; + $status->{ok} = 1; + return $status; +} + + +sub id { + my $self = shift; + return $self->{id}; +} + +sub title_id { + my $self = shift; + return ($self->{mods}) ? $self->{mods}->title : $self->{copy}->dummy_title; +} + +sub permanent_location { + my $self = shift; + return $self->{volume}->owning_lib->name; +} + +sub current_location { + my $self = shift; + return $self->{copy}->circ_lib->name; +} + + +# 2 chars 0-99 +sub sip_circulation_status { + my $self = shift; + return '01'; +} + +sub sip_security_marker { + return '02'; +} + +sub sip_fee_type { + return '01'; +} + +sub fee { + my $self = shift; + return 0; +} + + +sub fee_currency { + my $self = shift; + 'CAD'; +} + +sub owner { + my $self = shift; + return $self->{volume}->owning_lib->name; +} + +sub hold_queue { + my $self = shift; + return []; +} + +sub hold_queue_position { + my ($self, $patron_id) = @_; + return 1; +} + +sub due_date { + my $self = shift; + return 0; +} + +sub recall_date { + my $self = shift; + return 0; +} + +sub hold_pickup_date { + my $self = shift; + return 0; +} + +# message to display on console +sub screen_msg { + my $self = shift; + return $self->{screen_msg} || ''; +} + + +# reciept printer +sub print_line { + my $self = shift; + return $self->{print_line} || ''; +} + + +# An item is available for a patron if +# 1) It's not checked out and (there's no hold queue OR patron +# is at the front of the queue) +# OR +# 2) It's checked out to the patron and there's no hold queue +sub available { + my ($self, $for_patron) = @_; + return 1; +} + + +1; diff --git a/Open-ILS/src/perlmods/OpenILS/SIP/Patron.pm b/Open-ILS/src/perlmods/OpenILS/SIP/Patron.pm new file mode 100644 index 0000000000..648783018a --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/SIP/Patron.pm @@ -0,0 +1,397 @@ +# +# +# A Class for hiding the ILS's concept of the patron from the OpenSIP +# system +# + +package OpenILS::SIP::Patron; + +use strict; +use warnings; +use Exporter; + +use Sys::Syslog qw(syslog); +use Data::Dumper; +use Digest::MD5 qw(md5_hex); + +use OpenILS::Application::AppUtils; +my $U = 'OpenILS::Application::AppUtils'; + +our (@ISA, @EXPORT_OK); + +@ISA = qw(Exporter); + +@EXPORT_OK = qw(invalid_patron); + +sub new { + my ($class, $patron_id) = @_; + my $type = ref($class) || $class; + my $self = {}; + + syslog("LOG_DEBUG", "new OpenILS Patron(%s): searching...", $patron_id); + + require OpenILS::Utils::CStoreEditor; + my $e = OpenILS::Utils::CStoreEditor->new; + + if(!UNIVERSAL::can($e, 'search_actor_card')) { + syslog("LOG_WARNING", "Reloading CStoreEditor..."); + delete $INC{'OpenILS/Utils/CStoreEditor.pm'}; + require OpenILS::Utils::CStoreEditor; + $e = OpenILS::Utils::CStoreEditor->new; + } + + + my $c = $e->search_actor_card({barcode => $patron_id}, {idlist=>1}); + my $user; + + if( @$c ) { + + $user = $e->search_actor_user( + [ + { card => $$c[0] }, + { + flesh => 1, + flesh_fields => { + "au" => [ + #"cards", + "card", + "standing_penalties", + "addresses", + "billing_address", + "mailing_address", + #"stat_cat_entries", + 'profile', + ] + } + } + ] + ); + + $user = (@$user) ? $$user[0] : undef; + } + + if(!$user) { + syslog("LOG_WARNING", "Unable to find patron %s", $patron_id); + return undef; + } + + $self->{user} = $user; + $self->{id} = $patron_id; + $self->{editor} = $e; + + syslog("LOG_DEBUG", "new OpenILS Patron(%s): found patron '%s'", $patron_id); + + bless $self, $type; + return $self; +} + +sub id { + my $self = shift; + return $self->{id}; +} + +sub name { + my $self = shift; + my $u = $self->{user}; + return $u->first_given_name . ' ' . + $u->second_given_name . ' ' . $u->family_name; +} + +sub __addr_string { + my $addr = shift; + return "" unless $addr; + return $addr->street1 .' '. + $addr->street2 .' '. + $addr->city .' '. + $addr->county .' '. + $addr->state .' '. + $addr->country .' '. + $addr->post_code; +} + +sub address { + my $self = shift; + my $u = $self->{user}; + my $addr = $u->billing_address; + my $str = __addr_string($addr); + my $maddr = $u->mailing_address; + $str .= "\n" . __addr_string($maddr) + if $maddr and $maddr->id ne $addr->id; + return $str; +} + +sub email_addr { + my $self = shift; + return $self->{user}->email; +} + +sub home_phone { + my $self = shift; + return $self->{user}->day_phone; +} + +sub sip_birthdate { + my $self = shift; + return $self->{user}->dob; +} + +sub ptype { + my $self = shift; + return $self->{user}->profile->name; +} + +sub language { + my $self = shift; + return '000'; # Unspecified +} + +# How much more detail do we need to check here? +sub charge_ok { + my $self = shift; + my $u = $self->{user}; + return ($u->barred ne 't') and ($u->card->active ne 'f'); +} + +# How much more detail do we need to check here? +sub renew_ok { + my $self = shift; + my $u = $self->{user}; + return ($u->barred ne 'f') and ($u->card->active ne 'f'); +} + +sub recall_ok { + my $self = shift; + return 0; +} + +sub hold_ok { + my $self = shift; + return 0; +} + +# return true if the card provided is marked as lost +sub card_lost { + my $self = shift; + return 0; +} + +sub recall_overdue { + my $self = shift; + return 0; +} + + +sub check_password { + my ($self, $pwd) = @_; + return md5_hex($pwd) eq $self->{user}->passwd; +} + + +sub currency { + my $self = shift; + return 'usd'; +} + + +sub fee_amount { + my $self = shift; + return 0; +} + +sub screen_msg { + my $self = shift; + return ''; +} + +sub print_line { + my $self = shift; + return ''; +} + +sub too_many_charged { + my $self = shift; + return 0; +} + +sub too_many_overdue { + my $self = shift; + if( $self->{user}->standing_penalties ) { + return grep { $_->penalty_type eq 'PATRON_EXCEEDS_OVERDUE_COUNT' } + @{$self->{user}->standing_penalties}; + } + return 0; +} + +# not completely sure what this means +sub too_many_renewal { + my $self = shift; + return 0; +} + +# not relevant, handled by fines/fees +sub too_many_claim_return { + my $self = shift; + return 0; +} + +# not relevant, handled by fines/fees +sub too_many_lost { + my $self = shift; + return 0; +} + +sub excessive_fines { + my $self = shift; + if( $self->{user}->standing_penalties ) { + return grep { $_->penalty_type eq 'PATRON_EXCEEDS_FINES' } + @{$self->{user}->standing_penalties}; + } + return 0; +} + + +# Until someone suggests otherwise, fees and fines are the same + +sub excessive_fees { + my $self = shift; + if( $self->{user}->standing_penalties ) { + return grep { $_->penalty_type eq 'PATRON_EXCEEDS_FINES' } + @{$self->{user}->standing_penalties}; + } + return 0; +} + +# not relevant, handled by fines/fees +sub too_many_billed { + my $self = shift; + return 0; +} + + + +# +# List of outstanding holds placed +# +sub hold_items { + my ($self, $start, $end) = @_; + + my $holds = $self->{editor}->search_action_hold_request( + { usr => $self->{user}->id, fulfillment_time => undef } + ); + + my @holds; + push( @holds, $self->__hold_to_title($_) ) for @$holds; + + return (defined $start and defined $end) ? + [ $holds[($start-1)..($end-1)] ] : + \@holds; +} + +sub __hold_to_title { + my $self = shift; + my $hold = shift; + my $e = $self->{editor}; + + my( $id, $mods, $title, $volume, $copy ); + + if( $hold->hold_type eq 'C' ) { + $copy = $e->retrieve_asset_copy($hold->target); + } + + if( $copy || $hold->hold_type eq 'V' ) { + return $copy->dummy_title if $copy and $copy->call_number == -1; + $id = ($copy) ? $copy->call_number : $hold->target; + $volume = $e->retrieve_asset_call_number($id); + } + + if( $volume || $hold->hold_type eq 'T' ) { + $id = ($volume) ? $volume->record : $hold->target; + $mods = $U->simplereq( + 'open-ils.search', + 'open-ils.search.biblio.record.mods_slim.retrieve', $id ); + } + + if( $hold->hold_type eq 'M' ) { + $mods = $U->simplereq( + 'open-ils.search', + 'open-ils.search.biblio.metarecord.mods_slim.retrieve', $hold->target); + } + + + return ($mods) ? $mods->title : ""; +} + +# +# remove the hold on item item_id from my hold queue. +# return true if I was holding the item, false otherwise. +# +sub drop_hold { + my ($self, $item_id) = @_; + return 0; +} + +sub overdue_items { + my ($self, $start, $end) = @_; + my @overdues; + + return (defined $start and defined $end) ? + [ $overdues[($start-1)..($end-1)] ] : + \@overdues; +} + +sub charged_items { + my ($self, $start, $end) = shift; + my @charges; + + return (defined $start and defined $end) ? + [ $charges[($start-1)..($end-1)] ] : + \@charges; +} + +sub fine_items { + my ($self, $start, $end) = @_; + my @fines; + return (defined $start and defined $end) ? + [ $fines[($start-1)..($end-1)] ] : \@fines; +} + +# not currently supported +sub recall_items { + my ($self, $start, $end) = @_; + return []; +} + +sub unavail_holds { + my ($self, $start, $end) = @_; + my @holds; + return (defined $start and defined $end) ? + [ $holds[($start-1)..($end-1)] ] : \@holds; +} + +sub block { + my ($self, $card_retained, $blocked_card_msg) = @_; + # Mark the card as inactive, set patron alert + return $self; +} + +# Testing purposes only +sub enable { + my $self = shift; + # Un-mark card as inactive, grep out the patron alert + $self->{screen_msg} = "All privileges restored."; + return $self; +} + +# +# Messages +# + +sub invalid_patron { + return "Please contact library staff"; +} + +sub charge_denied { + return "Please contact library staff"; +} + +1; diff --git a/Open-ILS/src/perlmods/OpenILS/SIP/Transaction.pm b/Open-ILS/src/perlmods/OpenILS/SIP/Transaction.pm new file mode 100644 index 0000000000..6aabd4367a --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/SIP/Transaction.pm @@ -0,0 +1,126 @@ +# +# Transaction: Superclass of all the transactional status objects +# + +package OpenILS::SIP::Transaction; + +use Carp; +use strict; use warnings; +use Sys::Syslog qw(syslog); + + +my %fields = ( + ok => 0, + patron => undef, + item => undef, + desensitize => 0, + alert => '', + transation_id => undef, + sip_fee_type => '01', # Other/Unknown + fee_amount => undef, + sip_currency => 'CAD', + screen_msg => '', + print_line => '', + editor => undef, + authtoken => '', + ); + +our $AUTOLOAD; + +# returns the global transaction pointer +#sub get_xact { +# my $class = shift; +# return $XACT; +#} +# +#sub session { +# my( $self, $session ) = @_; +# $self->{session} = $session if $session; +# return $self->{session}; +#} +# +# +#sub create_session { +# my( $self, $patron ) = @_; +# $self->commit_session if $self->session_is_alive; +# require OpenILS::Utils::CStoreEditor; +# return $self->{session} = { +# editor => OpenILS::Utils::CStoreEditor->new(xact=>1), +# patron => $patron +# } +#} +# +#sub commit_session { +# my $self = shift; +# if( my $session = $self->session ) { +# $session->{editor}->commit; +# delete $$session{editor}; +# delete $$session{patron}; +# } +#} +# +# +#sub rollback_session { +# my $self = shift; +# if( my $session = $self->session ) { +# $session->{editor}->xact_rollback; +# delete $$session{editor}; +# delete $$session{patron}; +# } +#} +# +#sub session_is_alive { +# my $self = shift; +# return $self->session and $self->session->{editor}; +#} + + + +sub new { + my( $class, %args ) = @_; + + use Data::Dumper; + warn 'ARGS = ' . Dumper(\@_); + + warn "AUTH = " . $args{authtoken} . "\n"; + + my $self = { + _permitted => \%fields, + %fields, + }; + + bless $self, $class; + $self->authtoken($args{authtoken}); + + syslog('LOG_DEBUG', "OpenILS: Created new transaction with authtoken %s", $self->authtoken); + + require OpenILS::Utils::CStoreEditor; + $self->editor(OpenILS::Utils::CStoreEditor->new( + xact=>1, authtoken => $self->authtoken)); + + return $self; +} + +sub DESTROY { + # be cool +} + +sub AUTOLOAD { + my $self = shift; + my $class = ref($self) or croak "$self is not an object"; + my $name = $AUTOLOAD; + + $name =~ s/.*://; + + unless (exists $self->{_permitted}->{$name}) { + croak "Can't access '$name' field of class '$class'"; + } + + if (@_) { + return $self->{$name} = shift; + } else { + return $self->{$name}; + } +} + +1; diff --git a/Open-ILS/src/perlmods/OpenILS/SIP/Transaction/Checkin.pm b/Open-ILS/src/perlmods/OpenILS/SIP/Transaction/Checkin.pm new file mode 100644 index 0000000000..e349879c97 --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/SIP/Transaction/Checkin.pm @@ -0,0 +1,72 @@ +# +# An object to handle checkin status +# + +package OpenILS::SIP::Transaction::Checkin; + +use warnings; +use strict; + +use POSIX qw(strftime); + +use OpenILS::SIP; +use OpenILS::SIP::Transaction; +use Data::Dumper; + +use OpenILS::Application::AppUtils; +my $U = 'OpenILS::Application::AppUtils'; + +our @ISA = qw(OpenILS::SIP::Transaction); + +my %fields = ( + magnetic => 0, + sort_bin => undef, + ); + +sub new { + my $class = shift;; + my $self = $class->SUPER::new(@_); + my $element; + + foreach $element (keys %fields) { + $self->{_permitted}->{$element} = $fields{$element}; + } + + @{$self}{keys %fields} = values %fields; + + return bless $self, $class; +} + +sub resensitize { + my $self = shift; + return !$self->{item}->magnetic; +} + + +sub do_checkin { + my $self = shift; + + my $resp = $U->simplereq( + 'open-ils.circ', + 'open-ils.circ.checkin', + $self->{authtoken}, { barcode => $self->{item}->id } ); + + + my $circ = $resp->{payload}->{circ}; + + if(!$circ) { + warn 'CHECKIN: ' . Dumper($resp) . "\n"; + $self->ok(0); + return 0; + } + + $self->{item}->{patron} = $self->editor->search_actor_card( + { usr => $circ->usr, active => 't' } )->[0]->barcode; + + $self->ok(1); + + return 1; +} + + +1; diff --git a/Open-ILS/src/perlmods/OpenILS/SIP/Transaction/Checkout.pm b/Open-ILS/src/perlmods/OpenILS/SIP/Transaction/Checkout.pm new file mode 100644 index 0000000000..0cefd22550 --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/SIP/Transaction/Checkout.pm @@ -0,0 +1,111 @@ +# +# An object to handle checkout status +# + +package OpenILS::SIP::Transaction::Checkout; + +use warnings; +use strict; + +use POSIX qw(strftime); + +use OpenILS::SIP; +use OpenILS::SIP::Transaction; +use Sys::Syslog qw(syslog); + +use OpenILS::Application::AppUtils; +my $U = 'OpenILS::Application::AppUtils'; + + +our @ISA = qw(OpenILS::SIP::Transaction); + +# Most fields are handled by the Transaction superclass +my %fields = ( + security_inhibit => 0, + due => undef, + renew_ok => 0, + ); + +sub new { + my $class = shift; + + use Data::Dumper; + warn 'ARGS = ' . Dumper(\@_); + + my $self = $class->SUPER::new(@_); + + my $element; + + foreach $element (keys %fields) { + $self->{_permitted}->{$element} = $fields{$element}; + } + + @{$self}{keys %fields} = values %fields; + + return bless $self, $class; +} + + +# if this item is already checked out to the requested patron, +# renew the item and set $self->renew_ok to true. +# XXX if it's a renewal and the renewal is not permitted, set +# $self->screen_msg("Item on Hold for Another User"); (or somesuch) +# XXX Set $self->ok(0) on any errors +sub do_checkout { + my $self = shift; + syslog('LOG_DEBUG', "OpenILS: performing checkout..."); + + my $args = { + barcode => $self->{item}->id, + patron_barcode => $self->{patron}->id + }; + + my $resp = $U->simplereq( + 'open-ils.circ', + 'open-ils.circ.checkout.permit', + $self->{authtoken}, $args ); + + my $key; + + if( ref($resp) eq 'HASH' and $key = $resp->{payload} ) { + syslog('LOG_INFO', "OpenILS: circ permit key => $key"); + + } else { + syslog('LOG_INFO', "OpenILS: Circ permit failed :\n" . Dumper($resp) ); + $self->ok(0); + return 0; + } + + $args = { + permit_key => $key, + patron_barcode => $self->{patron}->id, + barcode => $self->{item}->id + }; + + $resp = $U->simplereq( + 'open-ils.circ', + 'open-ils.circ.checkout', $self->{authtoken}, $args ); + + # XXX Check for events + if( $resp ) { + syslog('LOG_INFO', "OpenILS: Checkout succeeded"); + my $evt = $resp->{ilsevent}; + my $circ = $resp->{payload}->{circ}; + + if(!$circ or $evt ne 0) { + $self->ok(0); + warn 'CHECKOUT RESPONSE: ' . Dumper($resp) . "\n"; + return 0; + } + + $self->{'due'} = $circ->due_date; + $self->ok(1); + return 1; + } + + return 0; +} + + + +1;