# GNU General Public License for more details.
# ---------------------------------------------------------------
-
package OpenILS::Application::Circ::Money;
use base qw/OpenILS::Application/;
use strict; use warnings;
use OpenILS::Utils::Penalty;
__PACKAGE__->register_method(
- method => "make_payments",
- api_name => "open-ils.circ.money.payment",
+ method => "make_payments",
+ api_name => "open-ils.circ.money.payment",
signature => {
desc => q/Create payments for a given user and set of transactions,
- login must have CREATE_PAYMENT priveleges.
- If any payments fail, all are reverted back./,
+ login must have CREATE_PAYMENT privileges.
+ If any payments fail, all are reverted back./,
params => [
{desc => 'Authtoken', type => 'string'},
{desc => q/Arguments Hash, supporting the following params:
userid
patron_credit
note
- cc_args : {
- type
- number
- expire_month
- expire_year
- approval_code
- }
+ cc_args: {
+ where_process 1 to use processor, !1 for out-of-band
+ approval_code (for out-of-band payment)
+ type (for out-of-band payment)
+ number (for call to payment processor)
+ expire_month (for call to payment processor)
+ expire_year (for call to payment processor)
+ note (if payments->{note} is blank, use this)
+ },
check_number
payments: [
[trans_id, amt],
]
}
);
-
sub make_payments {
- my($self, $client, $auth, $payments) = @_;
+ my($self, $client, $auth, $payments) = @_;
- my $e = new_editor(authtoken => $auth, xact => 1);
+ my $e = new_editor(authtoken => $auth, xact => 1);
return $e->die_event unless $e->checkauth;
- my $type = $payments->{payment_type};
- my $user_id = $payments->{userid};
- my $credit = $payments->{patron_credit} || 0;
- my $drawer = $e->requestor->wsid;
- my $note = $payments->{note};
- my $check_number = $payments->{check_number};
+ my $type = $payments->{payment_type};
+ my $user_id = $payments->{userid};
+ my $credit = $payments->{patron_credit} || 0;
+ my $drawer = $e->requestor->wsid;
+ my $note = $payments->{note};
my $cc_args = $payments->{cc_args};
- my $total_paid = 0;
+ my $check_number = $payments->{check_number};
+ my $total_paid = 0;
+ my $this_ou = $e->requestor->ws_ou;
my %orgs;
+ # unless/until determined by payment processor API
+ my ($approval_code, $cc_processor, $cc_type) = (undef,undef,undef);
+
my $patron = $e->retrieve_actor_user($user_id) or return $e->die_event;
# A user is allowed to make credit card payments on his/her own behalf
# All other scenarious require permission
unless($type eq 'credit_card_payment' and $user_id == $e->requestor->id) {
- return $e->die_event unless $e->allowed('CREATE_PAYMENT', $patron->home_ou);
+ return $e->die_event unless $e->allowed('CREATE_PAYMENT', $patron->home_ou);
}
# first collect the transactions and make sure the transaction
# user matches the requested user
my %xacts;
for my $pay (@{$payments->{payments}}) {
-
my $xact_id = $pay->[0];
my $xact = $e->retrieve_money_billable_transaction_summary($xact_id)
or return $e->die_event;
my @payment_objs;
- for my $pay (@{$payments->{payments}}) {
-
+ for my $pay (@{$payments->{payments}}) {
my $transid = $pay->[0];
- my $amount = $pay->[1];
- $amount =~ s/\$//og; # just to be safe
+ my $amount = $pay->[1];
+ $amount =~ s/\$//og; # just to be safe
my $trans = $xacts{$transid};
- $total_paid += $amount;
+ $total_paid += $amount;
$orgs{$U->xact_org($transid, $e)} = 1;
- # making payment with existing patron credit
- $credit -= $amount if $type eq 'credit_payment';
-
- # A negative payment is a refund.
- if( $amount < 0 ) {
+ # A negative payment is a refund.
+ if( $amount < 0 ) {
# Negative credit card payments are not allowed
if($type eq 'credit_card_payment') {
$e->rollback;
- return OpenILS::Event->new(
+ return OpenILS::Event->new(
'BAD_PARAMS',
note => q/Negative credit card payments not allowed/
);
}
- # If the refund causes the transaction balance to exceed 0 dollars,
- # we are in effect loaning the patron money. This is not allowed.
- if( ($trans->balance_owed - $amount) > 0 ) {
+ # If the refund causes the transaction balance to exceed 0 dollars,
+ # we are in effect loaning the patron money. This is not allowed.
+ if( ($trans->balance_owed - $amount) > 0 ) {
$e->rollback;
- return OpenILS::Event->new('REFUND_EXCEEDS_BALANCE');
- }
+ return OpenILS::Event->new('REFUND_EXCEEDS_BALANCE');
+ }
- # Otherwise, make sure the refund does not exceed desk payments
- # This is also not allowed
- my $desk_total = 0;
- my $desk_payments = $e->search_money_desk_payment({xact => $transid, voided => 'f'});
- $desk_total += $_->amount for @$desk_payments;
+ # Otherwise, make sure the refund does not exceed desk payments
+ # This is also not allowed
+ my $desk_total = 0;
+ my $desk_payments = $e->search_money_desk_payment({xact => $transid, voided => 'f'});
+ $desk_total += $_->amount for @$desk_payments;
- if( (-$amount) > $desk_total ) {
+ if( (-$amount) > $desk_total ) {
$e->rollback;
- return OpenILS::Event->new(
- 'REFUND_EXCEEDS_DESK_PAYMENTS',
- payload => { allowed_refund => $desk_total, submitted_refund => -$amount } );
- }
- }
-
- my $payobj = "Fieldmapper::money::$type";
- $payobj = $payobj->new;
-
- $payobj->amount($amount);
- $payobj->amount_collected($amount);
- $payobj->xact($transid);
- $payobj->note($note);
-
- if ($payobj->has_field('accepting_usr')) { $payobj->accepting_usr($e->requestor->id); }
- if ($payobj->has_field('cash_drawer')) { $payobj->cash_drawer($drawer); }
- if ($payobj->has_field('cc_type')) { $payobj->cc_type($cc_args->{type}); }
- if ($payobj->has_field('check_number')) { $payobj->check_number($check_number); }
-
- # Store the last 4 digits?
- #if ($payobj->has_field('cc_number')) { $payobj->cc_number($cc_args->{number}); }
- #if ($payobj->has_field('approval_code')) { $payobj->approval_code($cc_args->{approval_code}); }
- if ($payobj->has_field('expire_month')) { $payobj->expire_month($cc_args->{expire_month}); }
- if ($payobj->has_field('expire_year')) { $payobj->expire_year($cc_args->{expire_year}); }
-
- # update the transaction if it's done
- if( (my $cred = ($trans->balance_owed - $amount)) <= 0 ) {
-
- # Any overpay on this transaction goes directly into patron credit
- $cred = -$cred;
- $credit += $cred;
- my $circ = $e->retrieve_action_circulation($transid);
+ return OpenILS::Event->new(
+ 'REFUND_EXCEEDS_DESK_PAYMENTS',
+ payload => { allowed_refund => $desk_total, submitted_refund => -$amount } );
+ }
+ }
- if(!$circ || $circ->stop_fines) {
- # If this is a circulation, we can't close the transaction unless stop_fines is set
- $trans = $e->retrieve_money_billable_transaction($transid);
- $trans->xact_finish("now");
- $e->update_money_billable_transaction($trans) or return $e->die_event;
- }
- }
+ my $payobj = "Fieldmapper::money::$type";
+ $payobj = $payobj->new;
- my $method = "create_money_$type";
- $e->$method($payobj) or return $e->die_event;
- push(@payment_objs, $payobj);
+ $payobj->amount($amount);
+ $payobj->amount_collected($amount);
+ $payobj->xact($transid);
+ $payobj->note($note);
+ if ((not $payobj->note) and ($type eq 'credit_card_payment')) {
+ $payobj->note($cc_args->{note});
+ }
- } # all payment objects have been created and inserted.
+ if ($payobj->has_field('accepting_usr')) { $payobj->accepting_usr($e->requestor->id); }
+ if ($payobj->has_field('cash_drawer')) { $payobj->cash_drawer($drawer); }
+ if ($payobj->has_field('cc_type')) { $payobj->cc_type($cc_args->{type}); }
+ if ($payobj->has_field('check_number')) { $payobj->check_number($check_number); }
- my $evt = _update_patron_credit($e, $patron, $credit);
- return $evt if $evt;
+ # Store the last 4 digits of the CC number
+ if ($payobj->has_field('cc_number')) {
+ $payobj->cc_number(substr($cc_args->{number}, -4));
+ }
+ if ($payobj->has_field('expire_month')) { $payobj->expire_month($cc_args->{expire_month}); }
+ if ($payobj->has_field('expire_year')) { $payobj->expire_year($cc_args->{expire_year}); }
+
+ # Note: It is important not to set approval_code
+ # on the fieldmapper object yet.
- for my $org_id (keys %orgs) {
- # calculate penalties for each of the affected orgs
- $evt = OpenILS::Utils::Penalty->calculate_penalties($e, $user_id, $org_id);
- return $evt if $evt;
- }
+ push(@payment_objs, $payobj);
+
+ } # all payment objects have been created and inserted.
+ #### NO WRITES TO THE DB ABOVE THIS LINE -- THEY'LL ONLY BE DISCARDED ###
+ $e->rollback;
+
+ # After we try to externally process a credit card (if desired), we'll
+ # open a new transaction. We cannot leave one open while credit card
+ # processing might be happening, as it can easily time out the database
+ # transaction.
if($type eq 'credit_card_payment') {
- my $this_ou = $e->requestor->ws_ou;
- my $response = $apputils->simplereq(
- 'open-ils.credit',
- 'open-ils.credit.process',
- {
- "desc" => $payments->{note},
- "amount" => $total_paid,
- "patron_id" => $user_id,
- "cc" => $payments->{cc_number},
- "expiration" => sprintf(
- "%02d-%04d",
- $payments->{expire_month},
- $payments->{expire_year}
- ),
- "ou" => $this_ou
+ $approval_code = $cc_args->{approval_code};
+ # If an approval code was not given, we'll need
+ # to call to the payment processor ourselves.
+ if ($cc_args->{where_process} == 1) {
+ return OpenILS::Event->new('BAD_PARAMS', note => 'Need CC number')
+ if not $cc_args->{number};
+ my $response = $apputils->simplereq(
+ 'open-ils.credit',
+ 'open-ils.credit.process',
+ {
+ "desc" => $cc_args->{note},
+ "amount" => $total_paid,
+ "patron_id" => $user_id,
+ "cc" => $cc_args->{number},
+ "expiration" => sprintf(
+ "%02d-%04d",
+ $cc_args->{expire_month},
+ $cc_args->{expire_year}
+ ),
+ "ou" => $this_ou
+ }
+ );
+
+ if (exists $response->{ilsevent}) {
+ return $response;
}
- );
+ if ($response->{statusCode} != 200) {
+ $logger->info("Credit card payment for user $user_id " .
+ "failed with message: " . $response->{statusText});
+ return OpenILS::Event->new(
+ 'CREDIT_PROCESSOR_DECLINED_TRANSACTION',
+ note => $response->{statusText}
+ );
+ }
+ $approval_code = $response->{approvalCode};
+ $cc_type = $response->{cardType};
+ $cc_processor = $response->{processor};
+ $logger->info("Credit card payment processing for " .
+ "user $user_id succeeded");
+ }
+ else {
+ return OpenILS::Event->new(
+ 'BAD_PARAMS', note => 'Need approval code'
+ ) if not $cc_args->{approval_code};
+ }
+ }
- if (exists $response->{ilsevent}) {
- $e->rollback;
- return $response;
+ ### RE-OPEN TRANSACTION HERE ###
+ $e->xact_begin;
+
+ # create payment records
+ my $create_money_method = "create_money_" . $type;
+ for my $payment (@payment_objs) {
+ # update the transaction if it's done
+ my $amount = $payment->amount;
+ my $transid = $payment->xact;
+ my $trans = $xacts{$transid};
+ if( (my $cred = ($trans->balance_owed - $amount)) <= 0 ) {
+ # Any overpay on this transaction goes directly into patron
+ # credit making payment with existing patron credit.
+ $credit -= $amount if $type eq 'credit_payment';
+
+ $cred = -$cred;
+ $credit += $cred;
+ my $circ = $e->retrieve_action_circulation($transid);
+
+ if(!$circ || $circ->stop_fines) {
+ # If this is a circulation, we can't close the transaction
+ # unless stop_fines is set.
+ $trans = $e->retrieve_money_billable_transaction($transid);
+ $trans->xact_finish("now");
+ if (!$e->update_money_billable_transaction($trans)) {
+ $logger->warn("update_money_billable_transaction() " .
+ "failed");
+ $e->rollback;
+ return OpenILS::Event->new(
+ 'CREDIT_PROCESSOR_SUCCESS_WO_RECORD',
+ note => 'update_money_billable_transaction() failed'
+ );
+ }
+ }
}
- if ($response->{statusCode} != 200) {
+
+ $payment->approval_code($approval_code) if $approval_code;
+ $payment->cc_type($cc_type) if $cc_type;
+ $payment->cc_processor($cc_processor) if $cc_processor;
+ if (!$e->$create_money_method($payment)) {
+ $logger->warn("$create_money_method failed: " .
+ Dumper($payment)); # won't contain CC number.
$e->rollback;
- $logger->info("Credit card payment for user $user_id failed with message: " . $response->{statusText});
return OpenILS::Event->new(
- 'CREDIT_PROCESSOR_DECLINED_TRANSACTION',
- note => $response->{statusText}
+ 'CREDIT_PROCESSOR_SUCCESS_WO_RECORD',
+ note => "$create_money_method failed"
);
}
+ }
- for my $payment (@payment_objs) {
- $payment->approval_code($response->{approvalCode});
- $e->update_money_credit_card_payment($payment) or return $e->die_event;
+ my $evt = _update_patron_credit($e, $patron, $credit);
+ if ($evt) {
+ $logger->warn("_update_patron_credit() failed");
+ $e->rollback;
+ return OpenILS::Event->new(
+ 'CREDIT_PROCESSOR_SUCCESS_WO_RECORD',
+ note => "_update_patron_credit() failed"
+ );
+ }
+
+ for my $org_id (keys %orgs) {
+ # calculate penalties for each of the affected orgs
+ $evt = OpenILS::Utils::Penalty->calculate_penalties(
+ $e, $user_id, $org_id
+ );
+ if ($evt) {
+ $logger->warn(
+ "OpenILS::Utils::Penalty::calculate_penalties() failed"
+ );
+ $e->rollback;
+ return OpenILS::Event->new(
+ 'CREDIT_PROCESSOR_SUCCESS_WO_RECORD',
+ note => "OpenILS::Utils::Penalty::calculate_penalties() failed"
+ );
}
- $logger->info("Credit card payment for user $user_id succeeded");
}
$e->commit;
return 1;
}
-
sub _update_patron_credit {
- my($e, $patron, $credit) = @_;
+ my($e, $patron, $credit) = @_;
return undef if $credit == 0;
- $patron->credit_forward_balance($patron->credit_forward_balance + $credit);
+ $patron->credit_forward_balance($patron->credit_forward_balance + $credit);
return OpenILS::Event->new('NEGATIVE_PATRON_BALANCE') if $patron->credit_forward_balance < 0;
$e->update_actor_user($patron) or return $e->die_event;
- return undef;
+ return undef;
}
__PACKAGE__->register_method(
- method => "retrieve_payments",
- api_name => "open-ils.circ.money.payment.retrieve.all_",
- notes => "Returns a list of payments attached to a given transaction"
- );
-
+ method => "retrieve_payments",
+ api_name => "open-ils.circ.money.payment.retrieve.all_",
+ notes => "Returns a list of payments attached to a given transaction"
+ );
sub retrieve_payments {
- my( $self, $client, $login, $transid ) = @_;
+ my( $self, $client, $login, $transid ) = @_;
- my( $staff, $evt ) =
- $apputils->checksesperm($login, 'VIEW_TRANSACTION');
- return $evt if $evt;
+ my( $staff, $evt ) =
+ $apputils->checksesperm($login, 'VIEW_TRANSACTION');
+ return $evt if $evt;
- # XXX the logic here is wrong.. we need to check the owner of the transaction
- # to make sure the requestor has access
+ # XXX the logic here is wrong.. we need to check the owner of the transaction
+ # to make sure the requestor has access
- # XXX grab the view, for each object in the view, grab the real object
+ # XXX grab the view, for each object in the view, grab the real object
- return $apputils->simplereq(
- 'open-ils.cstore',
- 'open-ils.cstore.direct.money.payment.search.atomic', { xact => $transid } );
+ return $apputils->simplereq(
+ 'open-ils.cstore',
+ 'open-ils.cstore.direct.money.payment.search.atomic', { xact => $transid } );
}
-
__PACKAGE__->register_method(
- method => "retrieve_payments2",
+ method => "retrieve_payments2",
authoritative => 1,
- api_name => "open-ils.circ.money.payment.retrieve.all",
- notes => "Returns a list of payments attached to a given transaction"
- );
-
+ api_name => "open-ils.circ.money.payment.retrieve.all",
+ notes => "Returns a list of payments attached to a given transaction"
+ );
+
sub retrieve_payments2 {
- my( $self, $client, $login, $transid ) = @_;
-
- my $e = new_editor(authtoken=>$login);
- return $e->event unless $e->checkauth;
- return $e->event unless $e->allowed('VIEW_TRANSACTION');
-
- my @payments;
- my $pmnts = $e->search_money_payment({ xact => $transid });
- for( @$pmnts ) {
- my $type = $_->payment_type;
- my $meth = "retrieve_money_$type";
- my $p = $e->$meth($_->id) or return $e->event;
- $p->payment_type($type);
- $p->cash_drawer($e->retrieve_actor_workstation($p->cash_drawer))
- if $p->has_field('cash_drawer');
- push( @payments, $p );
- }
-
- return \@payments;
-}
+ my( $self, $client, $login, $transid ) = @_;
+
+ my $e = new_editor(authtoken=>$login);
+ return $e->event unless $e->checkauth;
+ return $e->event unless $e->allowed('VIEW_TRANSACTION');
+
+ my @payments;
+ my $pmnts = $e->search_money_payment({ xact => $transid });
+ for( @$pmnts ) {
+ my $type = $_->payment_type;
+ my $meth = "retrieve_money_$type";
+ my $p = $e->$meth($_->id) or return $e->event;
+ $p->payment_type($type);
+ $p->cash_drawer($e->retrieve_actor_workstation($p->cash_drawer))
+ if $p->has_field('cash_drawer');
+ push( @payments, $p );
+ }
+ return \@payments;
+}
__PACKAGE__->register_method(
- method => "create_grocery_bill",
- api_name => "open-ils.circ.money.grocery.create",
- notes => <<" NOTE");
- Creates a new grocery transaction using the transaction object provided
- PARAMS: (login_session, money.grocery (mg) object)
- NOTE
+ method => "create_grocery_bill",
+ api_name => "open-ils.circ.money.grocery.create",
+ notes => <<" NOTE");
+ Creates a new grocery transaction using the transaction object provided
+ PARAMS: (login_session, money.grocery (mg) object)
+ NOTE
sub create_grocery_bill {
- my( $self, $client, $login, $transaction ) = @_;
+ my( $self, $client, $login, $transaction ) = @_;
- my( $staff, $evt ) = $apputils->checkses($login);
- return $evt if $evt;
- $evt = $apputils->check_perms($staff->id,
- $transaction->billing_location, 'CREATE_TRANSACTION' );
- return $evt if $evt;
+ my( $staff, $evt ) = $apputils->checkses($login);
+ return $evt if $evt;
+ $evt = $apputils->check_perms($staff->id,
+ $transaction->billing_location, 'CREATE_TRANSACTION' );
+ return $evt if $evt;
- $logger->activity("Creating grocery bill " . Dumper($transaction) );
+ $logger->activity("Creating grocery bill " . Dumper($transaction) );
- $transaction->clear_id;
- my $session = $apputils->start_db_session;
- my $transid = $session->request(
- 'open-ils.storage.direct.money.grocery.create', $transaction)->gather(1);
+ $transaction->clear_id;
+ my $session = $apputils->start_db_session;
+ my $transid = $session->request(
+ 'open-ils.storage.direct.money.grocery.create', $transaction)->gather(1);
- throw OpenSRF::EX ("Error creating new money.grocery") unless defined $transid;
+ throw OpenSRF::EX ("Error creating new money.grocery") unless defined $transid;
- $logger->debug("Created new grocery transaction $transid");
-
- $apputils->commit_db_session($session);
+ $logger->debug("Created new grocery transaction $transid");
+
+ $apputils->commit_db_session($session);
my $e = new_editor(xact=>1);
$evt = _check_open_xact($e, $transid);
return $evt if $evt;
$e->commit;
- return $transid;
+ return $transid;
}
__PACKAGE__->register_method(
- method => 'fetch_grocery',
- api_name => 'open-ils.circ.money.grocery.retrieve'
+ method => 'fetch_grocery',
+ api_name => 'open-ils.circ.money.grocery.retrieve'
);
-
sub fetch_grocery {
- my( $self, $conn, $auth, $id ) = @_;
- my $e = new_editor(authtoken=>$auth);
- return $e->event unless $e->checkauth;
- return $e->event unless $e->allowed('VIEW_TRANSACTION'); # eh.. basically the same permission
- my $g = $e->retrieve_money_grocery($id)
- or return $e->event;
- return $g;
+ my( $self, $conn, $auth, $id ) = @_;
+ my $e = new_editor(authtoken=>$auth);
+ return $e->event unless $e->checkauth;
+ return $e->event unless $e->allowed('VIEW_TRANSACTION'); # eh.. basically the same permission
+ my $g = $e->retrieve_money_grocery($id)
+ or return $e->event;
+ return $g;
}
__PACKAGE__->register_method(
- method => "billing_items",
+ method => "billing_items",
authoritative => 1,
- api_name => "open-ils.circ.money.billing.retrieve.all",
- notes =><<" NOTE");
- Returns a list of billing items for the given transaction.
- PARAMS( login, transaction_id )
- NOTE
+ api_name => "open-ils.circ.money.billing.retrieve.all",
+ notes =><<" NOTE");
+ Returns a list of billing items for the given transaction.
+ PARAMS( login, transaction_id )
+ NOTE
sub billing_items {
- my( $self, $client, $login, $transid ) = @_;
-
- my( $trans, $evt ) = $U->fetch_billable_xact($transid);
- return $evt if $evt;
-
- my $staff;
- ($staff, $evt ) = $apputils->checkses($login);
- return $evt if $evt;
-
- if($staff->id ne $trans->usr) {
- $evt = $U->check_perms($staff->id, $staff->home_ou, 'VIEW_TRANSACTION');
- return $evt if $evt;
- }
-
- return $apputils->simplereq( 'open-ils.cstore',
- 'open-ils.cstore.direct.money.billing.search.atomic', { xact => $transid } )
+ my( $self, $client, $login, $transid ) = @_;
+
+ my( $trans, $evt ) = $U->fetch_billable_xact($transid);
+ return $evt if $evt;
+
+ my $staff;
+ ($staff, $evt ) = $apputils->checkses($login);
+ return $evt if $evt;
+
+ if($staff->id ne $trans->usr) {
+ $evt = $U->check_perms($staff->id, $staff->home_ou, 'VIEW_TRANSACTION');
+ return $evt if $evt;
+ }
+
+ return $apputils->simplereq( 'open-ils.cstore',
+ 'open-ils.cstore.direct.money.billing.search.atomic', { xact => $transid } )
}
__PACKAGE__->register_method(
- method => "billing_items_create",
- api_name => "open-ils.circ.money.billing.create",
- notes =><<" NOTE");
- Creates a new billing line item
- PARAMS( login, bill_object (mb) )
- NOTE
+ method => "billing_items_create",
+ api_name => "open-ils.circ.money.billing.create",
+ notes =><<" NOTE");
+ Creates a new billing line item
+ PARAMS( login, bill_object (mb) )
+ NOTE
sub billing_items_create {
- my( $self, $client, $login, $billing ) = @_;
+ my( $self, $client, $login, $billing ) = @_;
- my $e = new_editor(authtoken => $login, xact => 1);
- return $e->die_event unless $e->checkauth;
- return $e->die_event unless $e->allowed('CREATE_BILL');
+ my $e = new_editor(authtoken => $login, xact => 1);
+ return $e->die_event unless $e->checkauth;
+ return $e->die_event unless $e->allowed('CREATE_BILL');
- my $xact = $e->retrieve_money_billable_transaction($billing->xact)
- or return $e->die_event;
+ my $xact = $e->retrieve_money_billable_transaction($billing->xact)
+ or return $e->die_event;
- # if the transaction was closed, re-open it
- if($xact->xact_finish) {
- $xact->clear_xact_finish;
- $e->update_money_billable_transaction($xact)
- or return $e->die_event;
- }
+ # if the transaction was closed, re-open it
+ if($xact->xact_finish) {
+ $xact->clear_xact_finish;
+ $e->update_money_billable_transaction($xact)
+ or return $e->die_event;
+ }
- my $amt = $billing->amount;
- $amt =~ s/\$//og;
- $billing->amount($amt);
+ my $amt = $billing->amount;
+ $amt =~ s/\$//og;
+ $billing->amount($amt);
- $e->create_money_billing($billing) or return $e->die_event;
+ $e->create_money_billing($billing) or return $e->die_event;
my $evt = OpenILS::Utils::Penalty->calculate_penalties($e, $xact->usr, $U->xact_org($xact->id));
return $evt if $evt;
- $e->commit;
+ $e->commit;
- return $billing->id;
+ return $billing->id;
}
+
__PACKAGE__->register_method(
- method => 'void_bill',
- api_name => 'open-ils.circ.money.billing.void',
- signature => q/
- Voids a bill
- @param authtoken Login session key
- @param billid Id for the bill to void. This parameter may be repeated to reference other bills.
- @return 1 on success, Event on error
- /
+ method => 'void_bill',
+ api_name => 'open-ils.circ.money.billing.void',
+ signature => q/
+ Voids a bill
+ @param authtoken Login session key
+ @param billid Id for the bill to void. This parameter may be repeated to reference other bills.
+ @return 1 on success, Event on error
+ /
);
-
-
sub void_bill {
- my( $s, $c, $authtoken, @billids ) = @_;
+ my( $s, $c, $authtoken, @billids ) = @_;
- my $e = new_editor( authtoken => $authtoken, xact => 1 );
- return $e->die_event unless $e->checkauth;
- return $e->die_event unless $e->allowed('VOID_BILLING');
+ my $e = new_editor( authtoken => $authtoken, xact => 1 );
+ return $e->die_event unless $e->checkauth;
+ return $e->die_event unless $e->allowed('VOID_BILLING');
my %users;
for my $billid (@billids) {
- my $bill = $e->retrieve_money_billing($billid)
- or return $e->die_event;
+ my $bill = $e->retrieve_money_billing($billid)
+ or return $e->die_event;
my $xact = $e->retrieve_money_billable_transaction($bill->xact)
or return $e->die_event;
if($U->is_true($bill->voided)) {
$e->rollback;
- return OpenILS::Event->new('BILL_ALREADY_VOIDED', payload => $bill);
+ return OpenILS::Event->new('BILL_ALREADY_VOIDED', payload => $bill);
}
my $org = $U->xact_org($bill->xact, $e);
$users{$xact->usr} = {} unless $users{$xact->usr};
$users{$xact->usr}->{$org} = 1;
- $bill->voided('t');
- $bill->voider($e->requestor->id);
- $bill->void_time('now');
+ $bill->voided('t');
+ $bill->voider($e->requestor->id);
+ $bill->void_time('now');
- $e->update_money_billing($bill) or return $e->die_event;
- my $evt = _check_open_xact($e, $bill->xact, $xact);
- return $evt if $evt;
+ $e->update_money_billing($bill) or return $e->die_event;
+ my $evt = _check_open_xact($e, $bill->xact, $xact);
+ return $evt if $evt;
}
# calculate penalties for all user/org combinations
OpenILS::Utils::Penalty->calculate_penalties($e, $user_id, $org_id);
}
}
-
- $e->commit;
- return 1;
+ $e->commit;
+ return 1;
}
+
__PACKAGE__->register_method(
- method => 'edit_bill_note',
- api_name => 'open-ils.circ.money.billing.note.edit',
- signature => q/
- Edits the note for a bill
- @param authtoken Login session key
+ method => 'edit_bill_note',
+ api_name => 'open-ils.circ.money.billing.note.edit',
+ signature => q/
+ Edits the note for a bill
+ @param authtoken Login session key
@param note The replacement note for the bills we're editing
- @param billid Id for the bill to edit the note of. This parameter may be repeated to reference other bills.
- @return 1 on success, Event on error
- /
+ @param billid Id for the bill to edit the note of. This parameter may be repeated to reference other bills.
+ @return 1 on success, Event on error
+ /
);
-
-
sub edit_bill_note {
- my( $s, $c, $authtoken, $note, @billids ) = @_;
+ my( $s, $c, $authtoken, $note, @billids ) = @_;
- my $e = new_editor( authtoken => $authtoken, xact => 1 );
- return $e->die_event unless $e->checkauth;
- return $e->die_event unless $e->allowed('UPDATE_BILL_NOTE');
+ my $e = new_editor( authtoken => $authtoken, xact => 1 );
+ return $e->die_event unless $e->checkauth;
+ return $e->die_event unless $e->allowed('UPDATE_BILL_NOTE');
for my $billid (@billids) {
- my $bill = $e->retrieve_money_billing($billid)
- or return $e->die_event;
+ my $bill = $e->retrieve_money_billing($billid)
+ or return $e->die_event;
- $bill->note($note);
+ $bill->note($note);
# FIXME: Does this get audited? Need some way so that the original creator of the bill does not get credit/blame for the new note.
- $e->update_money_billing($bill) or return $e->die_event;
+ $e->update_money_billing($bill) or return $e->die_event;
}
-
- $e->commit;
- return 1;
+ $e->commit;
+ return 1;
}
+
__PACKAGE__->register_method(
- method => 'edit_payment_note',
- api_name => 'open-ils.circ.money.payment.note.edit',
- signature => q/
- Edits the note for a payment
- @param authtoken Login session key
+ method => 'edit_payment_note',
+ api_name => 'open-ils.circ.money.payment.note.edit',
+ signature => q/
+ Edits the note for a payment
+ @param authtoken Login session key
@param note The replacement note for the payments we're editing
- @param paymentid Id for the payment to edit the note of. This parameter may be repeated to reference other payments.
- @return 1 on success, Event on error
- /
+ @param paymentid Id for the payment to edit the note of. This parameter may be repeated to reference other payments.
+ @return 1 on success, Event on error
+ /
);
-
-
sub edit_payment_note {
- my( $s, $c, $authtoken, $note, @paymentids ) = @_;
+ my( $s, $c, $authtoken, $note, @paymentids ) = @_;
- my $e = new_editor( authtoken => $authtoken, xact => 1 );
- return $e->die_event unless $e->checkauth;
- return $e->die_event unless $e->allowed('UPDATE_PAYMENT_NOTE');
+ my $e = new_editor( authtoken => $authtoken, xact => 1 );
+ return $e->die_event unless $e->checkauth;
+ return $e->die_event unless $e->allowed('UPDATE_PAYMENT_NOTE');
for my $paymentid (@paymentids) {
- my $payment = $e->retrieve_money_payment($paymentid)
- or return $e->die_event;
+ my $payment = $e->retrieve_money_payment($paymentid)
+ or return $e->die_event;
- $payment->note($note);
+ $payment->note($note);
# FIXME: Does this get audited? Need some way so that the original taker of the payment does not get credit/blame for the new note.
- $e->update_money_payment($payment) or return $e->die_event;
+ $e->update_money_payment($payment) or return $e->die_event;
}
- $e->commit;
- return 1;
+ $e->commit;
+ return 1;
}
sub _check_open_xact {
- my( $editor, $xactid, $xact ) = @_;
+ my( $editor, $xactid, $xact ) = @_;
- # Grab the transaction
- $xact ||= $editor->retrieve_money_billable_transaction($xactid);
+ # Grab the transaction
+ $xact ||= $editor->retrieve_money_billable_transaction($xactid);
return $editor->event unless $xact;
$xactid ||= $xact->id;
- # grab the summary and see how much is owed on this transaction
- my ($summary) = $U->fetch_mbts($xactid, $editor);
-
- # grab the circulation if it is a circ;
- my $circ = $editor->retrieve_action_circulation($xactid);
-
- # If nothing is owed on the transaction but it is still open
- # and this transaction is not an open circulation, close it
- if(
- ( $summary->balance_owed == 0 and ! $xact->xact_finish ) and
- ( !$circ or $circ->stop_fines )) {
-
- $logger->info("closing transaction ".$xact->id. ' becauase balance_owed == 0');
- $xact->xact_finish('now');
- $editor->update_money_billable_transaction($xact)
- or return $editor->event;
- return undef;
- }
-
- # If money is owed or a refund is due on the xact and xact_finish
- # is set, clear it (to reopen the xact) and update
- if( $summary->balance_owed != 0 and $xact->xact_finish ) {
- $logger->info("re-opening transaction ".$xact->id. ' becauase balance_owed != 0');
- $xact->clear_xact_finish;
- $editor->update_money_billable_transaction($xact)
- or return $editor->event;
- return undef;
- }
-
- return undef;
-}
+ # grab the summary and see how much is owed on this transaction
+ my ($summary) = $U->fetch_mbts($xactid, $editor);
+
+ # grab the circulation if it is a circ;
+ my $circ = $editor->retrieve_action_circulation($xactid);
+ # If nothing is owed on the transaction but it is still open
+ # and this transaction is not an open circulation, close it
+ if(
+ ( $summary->balance_owed == 0 and ! $xact->xact_finish ) and
+ ( !$circ or $circ->stop_fines )) {
+
+ $logger->info("closing transaction ".$xact->id. ' becauase balance_owed == 0');
+ $xact->xact_finish('now');
+ $editor->update_money_billable_transaction($xact)
+ or return $editor->event;
+ return undef;
+ }
+
+ # If money is owed or a refund is due on the xact and xact_finish
+ # is set, clear it (to reopen the xact) and update
+ if( $summary->balance_owed != 0 and $xact->xact_finish ) {
+ $logger->info("re-opening transaction ".$xact->id. ' becauase balance_owed != 0');
+ $xact->clear_xact_finish;
+ $editor->update_money_billable_transaction($xact)
+ or return $editor->event;
+ return undef;
+ }
+ return undef;
+}
__PACKAGE__->register_method (
- method => 'fetch_mbts',
+ method => 'fetch_mbts',
authoritative => 1,
- api_name => 'open-ils.circ.money.billable_xact_summary.retrieve'
+ api_name => 'open-ils.circ.money.billable_xact_summary.retrieve'
);
sub fetch_mbts {
- my( $self, $conn, $auth, $id) = @_;
+ my( $self, $conn, $auth, $id) = @_;
- my $e = new_editor(xact => 1, authtoken=>$auth);
- return $e->event unless $e->checkauth;
- my ($mbts) = $U->fetch_mbts($id, $e);
+ my $e = new_editor(xact => 1, authtoken=>$auth);
+ return $e->event unless $e->checkauth;
+ my ($mbts) = $U->fetch_mbts($id, $e);
- my $user = $e->retrieve_actor_user($mbts->usr)
- or return $e->die_event;
+ my $user = $e->retrieve_actor_user($mbts->usr)
+ or return $e->die_event;
- return $e->die_event unless $e->allowed('VIEW_TRANSACTION', $user->home_ou);
- $e->rollback;
- return $mbts
+ return $e->die_event unless $e->allowed('VIEW_TRANSACTION', $user->home_ou);
+ $e->rollback;
+ return $mbts
}
-
__PACKAGE__->register_method(
- method => 'desk_payments',
- api_name => 'open-ils.circ.money.org_unit.desk_payments'
+ method => 'desk_payments',
+ api_name => 'open-ils.circ.money.org_unit.desk_payments'
);
-
sub desk_payments {
- my( $self, $conn, $auth, $org, $start_date, $end_date ) = @_;
- my $e = new_editor(authtoken=>$auth);
- return $e->event unless $e->checkauth;
- return $e->event unless $e->allowed('VIEW_TRANSACTION', $org);
- my $data = $U->storagereq(
- 'open-ils.storage.money.org_unit.desk_payments.atomic',
- $org, $start_date, $end_date );
-
- $_->workstation( $_->workstation->name ) for(@$data);
- return $data;
+ my( $self, $conn, $auth, $org, $start_date, $end_date ) = @_;
+ my $e = new_editor(authtoken=>$auth);
+ return $e->event unless $e->checkauth;
+ return $e->event unless $e->allowed('VIEW_TRANSACTION', $org);
+ my $data = $U->storagereq(
+ 'open-ils.storage.money.org_unit.desk_payments.atomic',
+ $org, $start_date, $end_date );
+
+ $_->workstation( $_->workstation->name ) for(@$data);
+ return $data;
}
__PACKAGE__->register_method(
- method => 'user_payments',
- api_name => 'open-ils.circ.money.org_unit.user_payments'
+ method => 'user_payments',
+ api_name => 'open-ils.circ.money.org_unit.user_payments'
);
sub user_payments {
- my( $self, $conn, $auth, $org, $start_date, $end_date ) = @_;
- my $e = new_editor(authtoken=>$auth);
- return $e->event unless $e->checkauth;
- return $e->event unless $e->allowed('VIEW_TRANSACTION', $org);
- my $data = $U->storagereq(
- 'open-ils.storage.money.org_unit.user_payments.atomic',
- $org, $start_date, $end_date );
- for(@$data) {
- $_->usr->card(
- $e->retrieve_actor_card($_->usr->card)->barcode);
- $_->usr->home_ou(
- $e->retrieve_actor_org_unit($_->usr->home_ou)->shortname);
- }
- return $data;
+ my( $self, $conn, $auth, $org, $start_date, $end_date ) = @_;
+ my $e = new_editor(authtoken=>$auth);
+ return $e->event unless $e->checkauth;
+ return $e->event unless $e->allowed('VIEW_TRANSACTION', $org);
+ my $data = $U->storagereq(
+ 'open-ils.storage.money.org_unit.user_payments.atomic',
+ $org, $start_date, $end_date );
+ for(@$data) {
+ $_->usr->card(
+ $e->retrieve_actor_card($_->usr->card)->barcode);
+ $_->usr->home_ou(
+ $e->retrieve_actor_org_unit($_->usr->home_ou)->shortname);
+ }
+ return $data;
}
-
-
-
1;
-
-
-
<?xul-overlay href="/xul/server/OpenILS/util_overlay.xul"?>
<window id="patron_bill" title="&staff.patron.bill_cc_info.title;"
- orient="vertical" style="overflow: auto"
- onload="try{info_init(); font_helper();}catch(E){alert(E);}"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ orient="vertical" style="overflow: auto"
+ onload="try{info_init(); font_helper();refresh_fields();}catch(E){alert(E);}"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<!-- ///////////////////////////////////////////////////////////////////////////////////////////////////////////// -->
<!-- BEHAVIOR -->
<script type="text/javascript">var myPackageDir = 'open_ils_staff_client'; var IAMXUL = true; var g = {};</script>
<scripts id="openils_util_scripts"/>
- <script type="text/javascript" src="/xul/server/main/JSAN.js"/>
-
- <script>
- <![CDATA[
- function $(id) { return document.getElementById(id); }
-
- function info_init() {
- netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
- if (typeof JSAN == 'undefined') { throw( $("commonStrings").getString('common.jsan.missing') ); }
- JSAN.errorLevel = "die"; // none, warn, or die
- JSAN.addRepository('/xul/server/');
- JSAN.use('util.error'); g.error = new util.error();
- g.error.sdump('D_TRACE','my_init() for patron_display.xul');
- g.OpenILS = {}; JSAN.use('OpenILS.data'); g.OpenILS.data = new OpenILS.data();
- g.OpenILS.data.init({'via':'stash'});
- g.payment_blob = { 'cc_args' : {}, 'cancelled' : true };
- g.OpenILS.data.temp = js2JSON( g.payment_blob );
- g.OpenILS.data.stash('temp');
-
- document.getElementById('cc_number').focus();
+ <script type="text/javascript" src="/xul/server/main/JSAN.js"/>
+
+ <script>
+ <![CDATA[
+ function $(id) { return document.getElementById(id); }
+
+ XULElement.prototype.hide = function() {
+ this.style.display = "none";
+ }
+ XULElement.prototype.reveal = function() {
+ this.style.display = "";
+ }
+
+ var show = {'int': 1, 'ext': 2}; // tied to Application::Circ::Money
+ var fields_of_interest = {
+ "cc_type": show['ext'],
+ "cc_number": show['int'],
+ "expire_month": show['int'],
+ "expire_year": show['int'],
+ "approval_code": show['ext'],
+ "note": show['ext'] + show['int'],
+ "where_process": show['ext'] + show['int']
+ };
+
+ function is_relevant_here(field) {
+ var flag = $('where_process').value;
+ var field_flag = fields_of_interest[field];
+ return ((field_flag & flag) == flag);
+ }
+
+ function refresh_fields() {
+ for (var field in fields_of_interest) {
+ if (is_relevant_here(field)) {
+ $('row_' + field).reveal();
+ }
+ else {
+ $('row_' + field).hide();
+ }
+ }
}
- function info_finish() {
- /* FIXME -- need unique temp space name */
- delete( g.payment_blob.cancelled );
- g.OpenILS.data.temp = js2JSON( g.payment_blob );
- g.OpenILS.data.stash('temp');
+ function info_init() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ if (typeof JSAN == 'undefined') { throw( $("commonStrings").getString('common.jsan.missing') ); }
+ JSAN.errorLevel = "die"; // none, warn, or die
+ JSAN.addRepository('/xul/server/');
+ JSAN.use('util.error'); g.error = new util.error();
+ g.error.sdump('D_TRACE','my_init() for patron_display.xul');
+ g.OpenILS = {}; JSAN.use('OpenILS.data'); g.OpenILS.data = new OpenILS.data();
+ g.OpenILS.data.init({'via':'stash'});
+ /* 'true' as a string matches the expectations in bills.js */
+ g.payment_blob = { 'cc_args' : {}, 'cancelled' : 'true' };
+ g.OpenILS.data.temp = js2JSON( g.payment_blob );
+ g.OpenILS.data.stash('temp');
+
+ document.getElementById('cc_number').focus();
+ }
+
+ function sanity_check() {
+ if ($('where_process').value == show['int']) { // internal process
+ if ($('cc_number').value.match(/^\s*$/)) {
+ alert($('patronStrings').getString('staff.patron.bill_cc_info.need_cc_number'));
+ return false;
+ }
+ }
+ else { // external
+ if ($('approval_code').value.match(/^\s*$/)) {
+ alert($('patronStrings').getString('staff.patron.bill_cc_info.need_approval_code'));
+ return false;
+ }
+ }
+ return true;
}
- ]]>
- </script>
-
- <messagecatalog id="patronStrings" src="/xul/server/locale/<!--#echo var='locale'-->/patron.properties" />
-
- <groupbox>
- <caption label="&staff.patron.bill_cc_info.info.label;"/>
- <grid>
- <columns> <column flex="0" /> <column flex="0" /> </columns>
- <rows>
- <row>
- <label value="&staff.patron.bill_cc_info.type.label;"/>
- <menulist id="cc_type" oncommand="g.payment_blob.cc_args.type = this.value;">
- <menupopup>
- <menuitem label="&staff.patron.bill_cc_info.visa.label;" value="Visa"/>
- <menuitem label="&staff.patron.bill_cc_info.mastercard.label;" value="Mastercard"/>
- <menuitem label="&staff.patron.bill_cc_info.american_express.label;" value="American Express"/>
- <menuitem label="&staff.patron.bill_cc_info.discover.label;" value="Discover"/>
- <menuitem label="&staff.patron.bill_cc_info.other.label;" value="Other"/>
- </menupopup>
- </menulist>
- </row>
- <row>
- <label value="&staff.patron.bill_cc_info.cc_number.value;"/>
- <textbox id="cc_number" onchange="g.payment_blob.cc_args.number = event.target.value" context="clipboard"/>
- </row>
- <row>
- <label value="&staff.patron.bill_cc_info.month_expire.value;"/>
- <textbox id="expire_month" onchange="g.payment_blob.cc_args.expire_month = event.target.value" context="clipboard"/>
- </row>
- <row>
- <label value="&staff.patron.bill_cc_info.year_expire.value;"/>
- <textbox id="expire_year" onchange="g.payment_blob.cc_args.expire_year = event.target.value" context="clipboard"/>
- </row>
- <row>
- <label value="&staff.patron.bill_cc_info.approval_code.value;"/>
- <textbox id="approval_code" onchange="g.payment_blob.cc_args.approval_code = event.target.value" context="clipboard"/>
- </row>
- <row>
- <label value="&staff.patron.bill_cc_info.note.value;"/>
- <textbox id="note" onchange="g.payment_blob.note = event.target.value" multiline="true" context="clipboard"/>
- </row>
- </rows>
- </grid>
- <hbox>
- <spacer flex="1"/>
- <button label="&staff.patron.bill_cc_info.cancel.label;" oncommand="window.close()" accesskey="&staff.patron.bill_cc_info.cancel.accesskey;"/>
- <button label="&staff.patron.bill_cc_info.submit.label;" oncommand="info_finish(); window.close();" accesskey="&staff.patron.bill_cc_info.submit.accesskey;"/>
- </hbox>
- </groupbox>
+ function info_finish() {
+ /* FIXME -- need unique temp space name */
+
+ /* The following for loop gathers our payment_blob values from
+ the widgets in this window. This is better than the method of
+ gathering data that was here before (using oncommand attributes
+ to set values in this JS object whenever a field value changed)
+ because (if for no other reason), a select menu, if left at the
+ default value, would never reach the payment_blob, because its
+ oncommand attribute would never fire. */
+ for (var field in fields_of_interest) {
+ if (is_relevant_here(field)) {
+ var matches = field.match(/^cc_(.+)$/);
+ var target_key = matches ? matches[1] : field;
+ g.payment_blob.cc_args[target_key] = $(field).value;
+ }
+ }
+ delete( g.payment_blob.cancelled );
+ g.OpenILS.data.temp = js2JSON( g.payment_blob );
+ g.OpenILS.data.stash('temp');
+ }
+
+ ]]>
+ </script>
+
+ <messagecatalog id="patronStrings" src="/xul/server/locale/<!--#echo var='locale'-->/patron.properties" />
+
+ <groupbox>
+ <caption label="&staff.patron.bill_cc_info.info.label;"/>
+ <grid>
+ <columns> <column flex="0" /> <column flex="0" /> </columns>
+ <rows>
+ <row id="row_where_process">
+ <label value="&staff.patron.bill_cc_info.where_process.label;"/>
+ <menulist id="where_process" oncommand="refresh_fields();">
+ <menupopup>
+ <menuitem label="&staff.patron.bill_cc_info.process_int.label;" value="1"/>
+ <menuitem label="&staff.patron.bill_cc_info.process_ext.label;" value="2"/>
+ </menupopup>
+ </menulist>
+ </row>
+ <row id="row_cc_type">
+ <label value="&staff.patron.bill_cc_info.type.label;"/>
+ <menulist id="cc_type">
+ <menupopup>
+ <menuitem label="&staff.patron.bill_cc_info.visa.label;" value="VISA"/><!-- capitalization to match CC processors' output -->
+ <menuitem label="&staff.patron.bill_cc_info.mastercard.label;" value="MasterCard"/><!-- capitalization to match CC processors' output -->
+ <menuitem label="&staff.patron.bill_cc_info.american_express.label;" value="American Express"/>
+ <menuitem label="&staff.patron.bill_cc_info.discover.label;" value="Discover"/>
+ <menuitem label="&staff.patron.bill_cc_info.other.label;" value="Other"/>
+ </menupopup>
+ </menulist>
+ </row>
+ <row id="row_approval_code">
+ <label value="&staff.patron.bill_cc_info.approval_code.value;"/>
+ <textbox id="approval_code" context="clipboard"/>
+ </row>
+ <row id="row_cc_number">
+ <label value="&staff.patron.bill_cc_info.cc_number.value;"/>
+ <textbox id="cc_number" context="clipboard"/>
+ </row>
+ <row id="row_expire_month">
+ <label value="&staff.patron.bill_cc_info.month_expire.value;"/>
+ <textbox id="expire_month" context="clipboard"/>
+ </row>
+ <row id="row_expire_year">
+ <label value="&staff.patron.bill_cc_info.year_expire.value;"/>
+ <textbox id="expire_year" context="clipboard"/>
+ </row>
+ <row id="row_note">
+ <label value="&staff.patron.bill_cc_info.note.value;"/>
+ <textbox id="note" multiline="true" context="clipboard"/>
+ </row>
+ </rows>
+ </grid>
+ <hbox>
+ <spacer flex="1"/>
+ <button label="&staff.patron.bill_cc_info.cancel.label;" oncommand="window.close()" accesskey="&staff.patron.bill_cc_info.cancel.accesskey;"/>
+ <button label="&staff.patron.bill_cc_info.submit.label;" oncommand="if (sanity_check()) { info_finish(); window.close(); }" accesskey="&staff.patron.bill_cc_info.submit.accesskey;"/>
+ </hbox>
+ </groupbox>
</window>
-