Bugzilla – Attachment 22873 Details for
Bug 6427
Rewrite of the accounts system
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 6427 - Rewrite of the accounts system - WIP
Bug-6427---Rewrite-of-the-accounts-system---WIP.patch (text/plain), 173.55 KB, created by
Kyle M Hall (khall)
on 2013-11-12 13:29:44 UTC
(
hide
)
Description:
Bug 6427 - Rewrite of the accounts system - WIP
Filename:
MIME Type:
Creator:
Kyle M Hall (khall)
Created:
2013-11-12 13:29:44 UTC
Size:
173.55 KB
patch
obsolete
>From 57f4ef0c18d6c053a6c1ab04f2f9cf33bbb5d6f1 Mon Sep 17 00:00:00 2001 >From: Kyle M Hall <kyle@bywatersolutions.com> >Date: Wed, 9 Oct 2013 10:36:44 -0400 >Subject: [PATCH] Bug 6427 - Rewrite of the accounts system - WIP > >--- > C4/Circulation.pm | 313 ++++++------- > C4/Members.pm | 67 ++-- > C4/Overdues.pm | 219 ++++----- > C4/Reserves.pm | 22 +- > Koha/Accounts.pm | 515 ++++++++++++++++++++ > Koha/Accounts/CreditTypes.pm | 117 +++++ > Koha/Accounts/DebitTypes.pm | 160 ++++++ > Koha/Accounts/OffsetTypes.pm | 72 +++ > Koha/DateUtils.pm | 7 +- > Koha/Schema/Result/AccountCredit.pm | 134 +++++ > Koha/Schema/Result/AccountDebit.pm | 177 +++++++ > Koha/Schema/Result/AccountOffset.pm | 118 +++++ > Koha/Schema/Result/Borrower.pm | 132 +++--- > Koha/Schema/Result/Issue.pm | 9 +- > Koha/Schema/Result/OldIssue.pm | 28 +- > Koha/Template/Plugin/Currency.pm | 64 +++ > installer/data/mysql/kohastructure.sql | 83 ++++ > installer/data/mysql/updatedatabase.pl | 76 +++ > .../intranet-tmpl/prog/en/includes/circ-menu.inc | 2 +- > .../intranet-tmpl/prog/en/includes/circ-menu.tt | 2 +- > .../prog/en/includes/members-menu.inc | 2 +- > .../prog/en/modules/circ/circulation.tt | 7 +- > .../intranet-tmpl/prog/en/modules/circ/returns.tt | 2 +- > .../prog/en/modules/members/account.tt | 166 +++++++ > .../prog/en/modules/members/account_credit.tt | 91 ++++ > .../prog/en/modules/members/account_debit.tt | 108 ++++ > .../prog/en/modules/members/account_payment.tt | 200 ++++++++ > .../prog/en/modules/members/boraccount.tt | 12 +- > .../prog/en/modules/members/mancredit.tt | 12 +- > .../prog/en/modules/members/maninvoice.tt | 12 +- > .../intranet-tmpl/prog/en/modules/members/pay.tt | 12 +- > .../prog/en/modules/members/paycollect.tt | 18 +- > members/account.pl | 111 +++++ > members/account_credit.pl | 104 ++++ > members/account_credit_do.pl | 68 +++ > members/account_debit.pl | 104 ++++ > members/account_debit_do.pl | 69 +++ > members/account_payment.pl | 123 +++++ > members/account_payment_do.pl | 62 +++ > members/mancredit.pl | 2 +- > members/maninvoice.pl | 2 +- > members/pay.pl | 4 +- > members/paycollect.pl | 4 +- > members/printfeercpt.pl | 2 +- > members/printinvoice.pl | 2 +- > misc/cronjobs/create_koc_db.pl | 41 +-- > misc/cronjobs/fines.pl | 10 +- > misc/release_notes/release_notes_3_10_0.txt | 2 +- > misc/release_notes/release_notes_3_12_0.txt | 2 +- > t/db_dependent/Accounts.t | 189 +++++++- > t/db_dependent/Circulation.t | 22 +- > 51 files changed, 3367 insertions(+), 515 deletions(-) > create mode 100644 Koha/Accounts.pm > create mode 100644 Koha/Accounts/CreditTypes.pm > create mode 100644 Koha/Accounts/DebitTypes.pm > create mode 100644 Koha/Accounts/OffsetTypes.pm > create mode 100644 Koha/Schema/Result/AccountCredit.pm > create mode 100644 Koha/Schema/Result/AccountDebit.pm > create mode 100644 Koha/Schema/Result/AccountOffset.pm > create mode 100644 Koha/Template/Plugin/Currency.pm > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/account.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/account_credit.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/account_debit.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/account_payment.tt > create mode 100755 members/account.pl > create mode 100755 members/account_credit.pl > create mode 100755 members/account_credit_do.pl > create mode 100755 members/account_debit.pl > create mode 100755 members/account_debit_do.pl > create mode 100755 members/account_payment.pl > create mode 100755 members/account_payment_do.pl > >diff --git a/C4/Circulation.pm b/C4/Circulation.pm >index 0a22b76..0e26358 100644 >--- a/C4/Circulation.pm >+++ b/C4/Circulation.pm >@@ -30,7 +30,7 @@ use C4::Items; > use C4::Members; > use C4::Dates; > use C4::Dates qw(format_date); >-use C4::Accounts; >+use Koha::Accounts; > use C4::ItemCirculationAlertPreference; > use C4::Message; > use C4::Debug; >@@ -48,6 +48,7 @@ use Data::Dumper; > use Koha::DateUtils; > use Koha::Calendar; > use Koha::Borrower::Debarments; >+use Koha::Database; > use Carp; > use Date::Calc qw( > Today >@@ -1275,7 +1276,7 @@ sub AddIssue { > ## If item was lost, it has now been found, reverse any list item charges if neccessary. > if ( $item->{'itemlost'} ) { > if ( C4::Context->preference('RefundLostItemFeeOnReturn' ) ) { >- _FixAccountForLostAndReturned( $item->{'itemnumber'}, undef, $item->{'barcode'} ); >+ _FixAccountForLostAndReturned( $item->{'itemnumber'} ); > } > } > >@@ -1812,9 +1813,15 @@ sub AddReturn { > if ( $amount > 0 > && C4::Context->preference('finesMode') eq 'production' ) > { >- C4::Overdues::UpdateFine( $issue->{itemnumber}, >- $issue->{borrowernumber}, >- $amount, $type, output_pref($datedue) ); >+ C4::Overdues::UpdateFine( >+ { >+ itemnumber => $issue->{itemnumber}, >+ borrowernumber => $issue->{borrowernumber}, >+ amount => $amount, >+ due => output_pref($datedue), >+ issue_id => $issue->{issue_id} >+ } >+ ); > } > } > >@@ -1864,18 +1871,23 @@ sub AddReturn { > $messages->{'WasLost'} = 1; > > if ( C4::Context->preference('RefundLostItemFeeOnReturn' ) ) { >- _FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode); # can tolerate undef $borrowernumber >+ _FixAccountForLostAndReturned( $item->{'itemnumber'} ); > $messages->{'LostItemFeeRefunded'} = 1; > } > } > > # fix up the overdues in accounts... > if ($borrowernumber) { >- my $fix = _FixOverduesOnReturn($borrowernumber, $item->{itemnumber}, $exemptfine, $dropbox); >- defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!"; # zero is OK, check defined >+ _FixOverduesOnReturn( >+ { >+ exempt_fine => $exemptfine, >+ dropbox => $dropbox, >+ issue => $issue, >+ } >+ ); > > if ( $issue->{overdue} && $issue->{date_due} ) { >-# fix fine days >+ # fix fine days > my $debardate = > _debar_user_on_return( $borrower, $item, $issue->{date_due}, $today ); > $messages->{Debarred} = $debardate if ($debardate); >@@ -2093,139 +2105,107 @@ Internal function, called only by AddReturn > =cut > > sub _FixOverduesOnReturn { >- my ($borrowernumber, $item); >- unless ($borrowernumber = shift) { >- warn "_FixOverduesOnReturn() not supplied valid borrowernumber"; >- return; >- } >- unless ($item = shift) { >- warn "_FixOverduesOnReturn() not supplied valid itemnumber"; >- return; >- } >- my ($exemptfine, $dropbox) = @_; >+ my ( $params ) = @_; >+ >+ my $exemptfine = $params->{exempt_fine}; >+ my $dropbox = $params->{dropbox}; >+ my $issue = $params->{issue}; >+ > my $dbh = C4::Context->dbh; > >- # check for overdue fine >- my $sth = $dbh->prepare( >-"SELECT * FROM accountlines WHERE (borrowernumber = ?) AND (itemnumber = ?) AND (accounttype='FU' OR accounttype='O')" >- ); >- $sth->execute( $borrowernumber, $item ); >+ my $schema = Koha::Database->new()->schema; >+ my $fine = >+ $schema->resultset('AccountDebit') >+ ->single( { issue_id => $issue->issue_id(), type => Koha::Accounts::DebitTypes::Fine() } ); > >- # alter fine to show that the book has been returned >- my $data = $sth->fetchrow_hashref; >- return 0 unless $data; # no warning, there's just nothing to fix >+ return unless ( $fine ); >+ >+ $fine->accruing(0); > >- my $uquery; >- my @bind = ($data->{'accountlines_id'}); > if ($exemptfine) { >- $uquery = "update accountlines set accounttype='FFOR', amountoutstanding=0"; >- if (C4::Context->preference("FinesLog")) { >- &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item"); >- } >- } elsif ($dropbox && $data->{lastincrement}) { >- my $outstanding = $data->{amountoutstanding} - $data->{lastincrement} ; >- my $amt = $data->{amount} - $data->{lastincrement} ; >+ AddCredit( >+ { >+ borrower => $fine->borrowernumber(), >+ amount => $fine->amount_original(), >+ debit_id => $fine->debit_id(), >+ type => Koha::Accounts::CreditTypes::Forgiven(), >+ } >+ ); > if (C4::Context->preference("FinesLog")) { >- &logaction("FINES", 'MODIFY',$borrowernumber,"Dropbox adjustment $amt, item $item"); >+ &logaction( >+ "FINES", 'MODIFY', >+ $issue->borrowernumber(), >+ "Overdue forgiven: item " . $issue->itemnumber() >+ ); > } >- $uquery = "update accountlines set accounttype='F' "; >- if($outstanding >= 0 && $amt >=0) { >- $uquery .= ", amount = ? , amountoutstanding=? "; >- unshift @bind, ($amt, $outstanding) ; >+ } elsif ($dropbox && $fine->amount_last_increment() != $fine->amount_original() ) { >+ if ( C4::Context->preference("FinesLog") ) { >+ &logaction( "FINES", 'MODIFY', $issue->borrowernumber(), >+ "Dropbox adjustment " >+ . $fine->amount_last_increment() >+ . ", item " . $issue->itemnumber() ); > } >- } else { >- $uquery = "update accountlines set accounttype='F' "; >- } >- $uquery .= " where (accountlines_id = ?)"; >- my $usth = $dbh->prepare($uquery); >- return $usth->execute(@bind); >+ $fine->amount_original( >+ $fine->amount_original() - $fine->amount_last_increment() ); >+ $fine->amount_outstanding( >+ $fine->amount_outstanding - $fine->amount_last_increment() ); >+ $schema->resultset('AccountOffset')->create( >+ { >+ debit_id => $fine->debit_id(), >+ type => Koha::Accounts::OffsetTypes::Dropbox(), >+ amount => $fine->amount_last_increment() * -1, >+ } >+ ); >+ } >+ >+ return $fine->update(); > } > > =head2 _FixAccountForLostAndReturned > >- &_FixAccountForLostAndReturned($itemnumber, [$borrowernumber, $barcode]); >+ &_FixAccountForLostAndReturned($itemnumber); > >-Calculates the charge for a book lost and returned. >- >-Internal function, not exported, called only by AddReturn. >- >-FIXME: This function reflects how inscrutable fines logic is. Fix both. >-FIXME: Give a positive return value on success. It might be the $borrowernumber who received credit, or the amount forgiven. >+ Refunds a lost item fee in necessary > > =cut > > sub _FixAccountForLostAndReturned { >- my $itemnumber = shift or return; >- my $borrowernumber = @_ ? shift : undef; >- my $item_id = @_ ? shift : $itemnumber; # Send the barcode if you want that logged in the description >- my $dbh = C4::Context->dbh; >- # check for charge made for lost book >- my $sth = $dbh->prepare("SELECT * FROM accountlines WHERE itemnumber = ? AND accounttype IN ('L', 'Rep', 'W') ORDER BY date DESC, accountno DESC"); >- $sth->execute($itemnumber); >- my $data = $sth->fetchrow_hashref; >- $data or return; # bail if there is nothing to do >- $data->{accounttype} eq 'W' and return; # Written off >- >- # writeoff this amount >- my $offset; >- my $amount = $data->{'amount'}; >- my $acctno = $data->{'accountno'}; >- my $amountleft; # Starts off undef/zero. >- if ($data->{'amountoutstanding'} == $amount) { >- $offset = $data->{'amount'}; >- $amountleft = 0; # Hey, it's zero here, too. >- } else { >- $offset = $amount - $data->{'amountoutstanding'}; # Um, isn't this the same as ZERO? We just tested those two things are == >- $amountleft = $data->{'amountoutstanding'} - $amount; # Um, isn't this the same as ZERO? We just tested those two things are == >- } >- my $usth = $dbh->prepare("UPDATE accountlines SET accounttype = 'LR',amountoutstanding='0' >- WHERE (accountlines_id = ?)"); >- $usth->execute($data->{'accountlines_id'}); # We might be adjusting an account for some OTHER borrowernumber now. Not the one we passed in. >- #check if any credit is left if so writeoff other accounts >- my $nextaccntno = getnextacctno($data->{'borrowernumber'}); >- $amountleft *= -1 if ($amountleft < 0); >- if ($amountleft > 0) { >- my $msth = $dbh->prepare("SELECT * FROM accountlines WHERE (borrowernumber = ?) >- AND (amountoutstanding >0) ORDER BY date"); # might want to order by amountoustanding ASC (pay smallest first) >- $msth->execute($data->{'borrowernumber'}); >- # offset transactions >- my $newamtos; >- my $accdata; >- while (($accdata=$msth->fetchrow_hashref) and ($amountleft>0)){ >- if ($accdata->{'amountoutstanding'} < $amountleft) { >- $newamtos = 0; >- $amountleft -= $accdata->{'amountoutstanding'}; >- } else { >- $newamtos = $accdata->{'amountoutstanding'} - $amountleft; >- $amountleft = 0; >- } >- my $thisacct = $accdata->{'accountlines_id'}; >- # FIXME: move prepares outside while loop! >- my $usth = $dbh->prepare("UPDATE accountlines SET amountoutstanding= ? >- WHERE (accountlines_id = ?)"); >- $usth->execute($newamtos,$thisacct); >- $usth = $dbh->prepare("INSERT INTO accountoffsets >- (borrowernumber, accountno, offsetaccount, offsetamount) >- VALUES >- (?,?,?,?)"); >- $usth->execute($data->{'borrowernumber'},$accdata->{'accountno'},$nextaccntno,$newamtos); >+ my ( $itemnumber ) = @_; >+ >+ my $schema = Koha::Database->new()->schema; >+ >+ # Find the last issue for this item >+ my $issue = >+ $schema->resultset('Issue')->single( { itemnumber => $itemnumber } ); >+ $issue ||= >+ $schema->resultset('OldIssue')->single( { itemnumber => $itemnumber } ); >+ >+ return unless $issue; >+ >+ # Find a lost fee for this issue >+ my $debit = $schema->resultset('AccountDebit')->single( >+ { >+ issue_id => $issue->issue_id(), >+ type => Koha::Accounts::DebitTypes::Lost() > } >- } >- $amountleft *= -1 if ($amountleft > 0); >- my $desc = "Item Returned " . $item_id; >- $usth = $dbh->prepare("INSERT INTO accountlines >- (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding) >- VALUES (?,?,now(),?,?,'CR',?)"); >- $usth->execute($data->{'borrowernumber'},$nextaccntno,0-$amount,$desc,$amountleft); >- if ($borrowernumber) { >- # FIXME: same as query above. use 1 sth for both >- $usth = $dbh->prepare("INSERT INTO accountoffsets >- (borrowernumber, accountno, offsetaccount, offsetamount) >- VALUES (?,?,?,?)"); >- $usth->execute($borrowernumber, $data->{'accountno'}, $nextaccntno, $offset); >- } >+ ); >+ >+ return unless $debit; >+ >+ # Check for an existing found credit for this debit, if there is one, the fee has already been refunded and we do nothing >+ my @credits = $debit->account_offsets->search_related('credit', { 'credit.type' => Koha::Accounts::CreditTypes::Found() }); >+ >+ return if @credits; >+ >+ # Ok, so we know we have an unrefunded lost item fee, let's refund it >+ CreditLostItem( >+ { >+ borrower => $issue->borrower(), >+ debit => $debit >+ } >+ ); >+ > ModItem({ paidfor => '' }, undef, $itemnumber); >- return; > } > > =head2 _GetCircControlBranch >@@ -2584,19 +2564,22 @@ sub AddRenewal { > # Charge a new rental fee, if applicable? > my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber ); > if ( $charge > 0 ) { >- my $accountno = getnextacctno( $borrowernumber ); > my $item = GetBiblioFromItemNumber($itemnumber); >- my $manager_id = 0; >- $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; >- $sth = $dbh->prepare( >- "INSERT INTO accountlines >- (date, borrowernumber, accountno, amount, manager_id, >- description,accounttype, amountoutstanding, itemnumber) >- VALUES (now(),?,?,?,?,?,?,?,?)" >+ >+ my $borrower = >+ Koha::Database->new()->schema->resultset('Borrower') >+ ->find($borrowernumber); >+ >+ AddDebit( >+ { >+ borrower => $borrower, >+ itemnumber => $itemnumber, >+ amount => $charge, >+ type => Koha::Accounts::DebitTypes::Rental(), >+ description => >+ "Renewal of Rental Item $item->{'title'} $item->{'barcode'}" >+ } > ); >- $sth->execute( $borrowernumber, $accountno, $charge, $manager_id, >- "Renewal of Rental Item $item->{'title'} $item->{'barcode'}", >- 'Rent', $charge, $itemnumber ); > } > > # Send a renewal slip according to checkout alert preferencei >@@ -2767,25 +2750,21 @@ sub _get_discount_from_rule { > > =head2 AddIssuingCharge > >- &AddIssuingCharge( $itemno, $borrowernumber, $charge ) >+ &AddIssuingCharge( $itemnumber, $borrowernumber, $amount ) > > =cut > > sub AddIssuingCharge { >- my ( $itemnumber, $borrowernumber, $charge ) = @_; >- my $dbh = C4::Context->dbh; >- my $nextaccntno = getnextacctno( $borrowernumber ); >- my $manager_id = 0; >- $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; >- my $query =" >- INSERT INTO accountlines >- (borrowernumber, itemnumber, accountno, >- date, amount, description, accounttype, >- amountoutstanding, manager_id) >- VALUES (?, ?, ?,now(), ?, 'Rental', 'Rent',?,?) >- "; >- my $sth = $dbh->prepare($query); >- $sth->execute( $borrowernumber, $itemnumber, $nextaccntno, $charge, $charge, $manager_id ); >+ my ( $itemnumber, $borrowernumber, $amount ) = @_; >+ >+ return AddDebit( >+ { >+ borrower => Koha::Database->new()->schema->resultset('Borrower')->find($borrowernumber), >+ itemnumber => $itemnumber, >+ amount => $amount, >+ type => Koha::Accounts::DebitTypes::Rental(), >+ } >+ ); > } > > =head2 GetTransfers >@@ -3304,30 +3283,30 @@ sub ReturnLostItem{ > sub LostItem{ > my ($itemnumber, $mark_returned) = @_; > >- my $dbh = C4::Context->dbh(); >- my $sth=$dbh->prepare("SELECT issues.*,items.*,biblio.title >- FROM issues >- JOIN items USING (itemnumber) >- JOIN biblio USING (biblionumber) >- WHERE issues.itemnumber=?"); >- $sth->execute($itemnumber); >- my $issues=$sth->fetchrow_hashref(); >+ my $schema = Koha::Database->new()->schema; > >- # If a borrower lost the item, add a replacement cost to the their record >- if ( my $borrowernumber = $issues->{borrowernumber} ){ >- my $borrower = C4::Members::GetMemberDetails( $borrowernumber ); >+ my $issue = >+ $schema->resultset('Issue')->single( { itemnumber => $itemnumber } ); > >+ my $borrower = $issue->borrower(); >+ my $item = $issue->item(); >+ >+ # If a borrower lost the item, add a replacement cost to the their record >+ if ( $borrower ){ > if (C4::Context->preference('WhenLostForgiveFine')){ >- my $fix = _FixOverduesOnReturn($borrowernumber, $itemnumber, 1, 0); # 1, 0 = exemptfine, no-dropbox >- defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!"; # zero is OK, check defined >+ _FixOverduesOnReturn( >+ { >+ exempt_fine => 1, >+ dropbox => 0, >+ issue => $issue, >+ } >+ ); > } >- if (C4::Context->preference('WhenLostChargeReplacementFee')){ >- C4::Accounts::chargelostitem($borrowernumber, $itemnumber, $issues->{'replacementprice'}, "Lost Item $issues->{'title'} $issues->{'barcode'}"); >- #FIXME : Should probably have a way to distinguish this from an item that really was returned. >- #warn " $issues->{'borrowernumber'} / $itemnumber "; >+ if ( C4::Context->preference('WhenLostChargeReplacementFee') ) { >+ DebitLostItem( { borrower => $borrower, issue => $issue } ); > } > >- MarkIssueReturned($borrowernumber,$itemnumber,undef,undef,$borrower->{'privacy'}) if $mark_returned; >+ MarkIssueReturned( $borrower->borrowernumber(), $item->itemnumber(), undef, undef, $borrower->privacy() ) if $mark_returned; > } > } > >diff --git a/C4/Members.pm b/C4/Members.pm >index b04cc64..387ee89 100644 >--- a/C4/Members.pm >+++ b/C4/Members.pm >@@ -41,6 +41,7 @@ use Koha::DateUtils; > use Koha::Borrower::Debarments qw(IsDebarred); > use Text::Unaccent qw( unac_string ); > use Koha::AuthUtils qw(hash_password); >+use Koha::Accounts::DebitTypes; > > our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug); > >@@ -338,9 +339,6 @@ sub GetMemberDetails { > return; > } > my $borrower = $sth->fetchrow_hashref; >- my ($amount) = GetMemberAccountRecords( $borrowernumber); >- $borrower->{'amountoutstanding'} = $amount; >- # FIXME - patronflags calls GetMemberAccountRecords... just have patronflags return $amount > my $flags = patronflags( $borrower); > my $accessflagshash; > >@@ -432,23 +430,20 @@ The "message" field that comes from the DB is OK. > # FIXME rename this function. > sub patronflags { > my %flags; >- my ( $patroninformation) = @_; >- my $dbh=C4::Context->dbh; >- my ($balance, $owing) = GetMemberAccountBalance( $patroninformation->{'borrowernumber'}); >- if ( $owing > 0 ) { >+ my ($patroninformation) = @_; >+ my $dbh = C4::Context->dbh; >+ if ( $patroninformation->{account_balance} > 0 ) { > my %flaginfo; > my $noissuescharge = C4::Context->preference("noissuescharge") || 5; >- $flaginfo{'message'} = sprintf 'Patron owes %.02f', $owing; >- $flaginfo{'amount'} = sprintf "%.02f", $owing; >- if ( $owing > $noissuescharge && !C4::Context->preference("AllowFineOverride") ) { >+ $flaginfo{'amount'} = $patroninformation->{account_balance}; >+ if ( $patroninformation->{account_balance} > $noissuescharge && !C4::Context->preference("AllowFineOverride") ) { > $flaginfo{'noissues'} = 1; > } > $flags{'CHARGES'} = \%flaginfo; > } >- elsif ( $balance < 0 ) { >+ elsif ( $patroninformation->{account_balance} < 0 ) { > my %flaginfo; >- $flaginfo{'message'} = sprintf 'Patron has credit of %.02f', -$balance; >- $flaginfo{'amount'} = sprintf "%.02f", $balance; >+ $flaginfo{'amount'} = $patroninformation->{account_balance}; > $flags{'CREDITS'} = \%flaginfo; > } > if ( $patroninformation->{'gonenoaddress'} >@@ -691,7 +686,7 @@ sub GetMemberIssuesAndFines { > $sth->execute($borrowernumber); > my $overdue_count = $sth->fetchrow_arrayref->[0]; > >- $sth = $dbh->prepare("SELECT SUM(amountoutstanding) FROM accountlines WHERE borrowernumber = ?"); >+ $sth = $dbh->prepare("SELECT account_balance FROM borrowers WHERE borrowernumber = ?"); > $sth->execute($borrowernumber); > my $total_fines = $sth->fetchrow_arrayref->[0]; > >@@ -1216,8 +1211,8 @@ sub GetMemberAccountRecords { > Calculates amount immediately owing by the patron - non-issue charges. > Based on GetMemberAccountRecords. > Charges exempt from non-issue are: >-* Res (reserves) >-* Rent (rental) if RentalsInNoissuesCharge syspref is set to false >+* HOLD fees (reserves) >+* RENTAL if RentalsInNoissuesCharge syspref is set to false > * Manual invoices if ManInvInNoissuesCharge syspref is set to false > > =cut >@@ -1225,24 +1220,38 @@ Charges exempt from non-issue are: > sub GetMemberAccountBalance { > my ($borrowernumber) = @_; > >- my $ACCOUNT_TYPE_LENGTH = 5; # this is plain ridiculous... >+ my $borrower = >+ Koha::Database->new()->schema->resultset('Borrower') >+ ->find($borrowernumber); >+ >+ my @not_fines; >+ >+ push( @not_fines, Koha::Accounts::DebitTypes::Hold() ); >+ >+ push( @not_fines, Koha::Accounts::DebitTypes::Rental() ) >+ unless C4::Context->preference('RentalsInNoissuesCharge'); > >- my @not_fines = ('Res'); >- push @not_fines, 'Rent' unless C4::Context->preference('RentalsInNoissuesCharge'); > unless ( C4::Context->preference('ManInvInNoissuesCharge') ) { >- my $dbh = C4::Context->dbh; >- my $man_inv_types = $dbh->selectcol_arrayref(qq{SELECT authorised_value FROM authorised_values WHERE category = 'MANUAL_INV'}); >- push @not_fines, map substr($_, 0, $ACCOUNT_TYPE_LENGTH), @$man_inv_types; >+ my $dbh = C4::Context->dbh; >+ my $man_inv_types = $dbh->selectcol_arrayref( >+ qq{SELECT authorised_value FROM authorised_values WHERE category = 'MANUAL_INV'} >+ ); >+ push( @not_fines, @$man_inv_types ); > } >- my %not_fine = map {$_ => 1} @not_fines; > >- my ($total, $acctlines) = GetMemberAccountRecords($borrowernumber); >- my $other_charges = 0; >- foreach (@$acctlines) { >- $other_charges += $_->{amountoutstanding} if $not_fine{ substr($_->{accounttype}, 0, $ACCOUNT_TYPE_LENGTH) }; >- } >+ my $other_charges = >+ Koha::Database->new()->schema->resultset('AccountDebit')->search( >+ { >+ borrowernumber => $borrowernumber, >+ type => { -not_in => \@not_fines } >+ } >+ )->get_column('amount_outstanding')->sum(); > >- return ( $total, $total - $other_charges, $other_charges); >+ return ( >+ $borrower->account_balance(), >+ $borrower->account_balance() - $other_charges, >+ $other_charges >+ ); > } > > =head2 GetBorNotifyAcctRecord >diff --git a/C4/Overdues.pm b/C4/Overdues.pm >index 33dbd98..3c55dce 100644 >--- a/C4/Overdues.pm >+++ b/C4/Overdues.pm >@@ -28,6 +28,8 @@ use C4::Context; > use C4::Accounts; > use C4::Log; # logaction > use C4::Debug; >+use Koha::Database; >+use Koha::DateUtils; > > use vars qw($VERSION @ISA @EXPORT); > >@@ -456,154 +458,112 @@ sub GetIssuesIteminfo { > > =head2 UpdateFine > >- &UpdateFine($itemnumber, $borrowernumber, $amount, $type, $description); >+ UpdateFine( >+ { >+ itemnumber => $itemnumber, >+ borrowernumber => $borrowernumber, >+ amount => $amount, >+ due => $due, >+ issue_id => $issue_id >+ } >+ ); > >-(Note: the following is mostly conjecture and guesswork.) >+Updates the fine owed on an overdue item. > >-Updates the fine owed on an overdue book. >+C<$itemnumber> is the items's id. > >-C<$itemnumber> is the book's item number. >+C<$borrowernumber> is the id of the patron who currently >+has the item on loan. > >-C<$borrowernumber> is the borrower number of the patron who currently >-has the book on loan. >+C<$amount> is the total amount of the fine owed by the patron. > >-C<$amount> is the current amount owed by the patron. >+C<&UpdateFine> updates the amount owed for a given fine if an issue_id >+is passed to it. Otherwise, a new fine will be created. > >-C<$type> will be used in the description of the fine. >+=cut > >-C<$description> is a string that must be present in the description of >-the fine. I think this is expected to be a date in DD/MM/YYYY format. >+sub UpdateFine { >+ my ($params) = @_; > >-C<&UpdateFine> looks up the amount currently owed on the given item >-and sets it to C<$amount>, creating, if necessary, a new entry in the >-accountlines table of the Koha database. >+ my $itemnumber = $params->{itemnumber}; >+ my $borrowernumber = $params->{borrowernumber}; >+ my $amount = $params->{amount}; >+ my $due = $params->{due}; >+ my $issue_id = $params->{issue_id}; > >-=cut >+ my $schema = Koha::Database->new()->schema; > >-# >-# Question: Why should the caller have to >-# specify both the item number and the borrower number? A book can't >-# be on loan to two different people, so the item number should be >-# sufficient. >-# >-# Possible Answer: You might update a fine for a damaged item, *after* it is returned. >-# >-sub UpdateFine { >- my ( $itemnum, $borrowernumber, $amount, $type, $due ) = @_; >- $debug and warn "UpdateFine($itemnum, $borrowernumber, $amount, " . ($type||'""') . ", $due) called"; >- my $dbh = C4::Context->dbh; >- # FIXME - What exactly is this query supposed to do? It looks up an >- # entry in accountlines that matches the given item and borrower >- # numbers, where the description contains $due, and where the >- # account type has one of several values, but what does this _mean_? >- # Does it look up existing fines for this item? >- # FIXME - What are these various account types? ("FU", "O", "F", "M") >- # "L" is LOST item >- # "A" is Account Management Fee >- # "N" is New Card >- # "M" is Sundry >- # "O" is Overdue ?? >- # "F" is Fine ?? >- # "FU" is Fine UPDATE?? >- # "Pay" is Payment >- # "REF" is Cash Refund >- my $sth = $dbh->prepare( >- "SELECT * FROM accountlines >- WHERE borrowernumber=? >- AND accounttype IN ('FU','O','F','M')" >- ); >- $sth->execute( $borrowernumber ); >- my $data; >- my $total_amount_other = 0.00; >- my $due_qr = qr/$due/; >- # Cycle through the fines and >- # - find line that relates to the requested $itemnum >- # - accumulate fines for other items >- # so we can update $itemnum fine taking in account fine caps >- while (my $rec = $sth->fetchrow_hashref) { >- if ($rec->{itemnumber} == $itemnum && $rec->{description} =~ /$due_qr/) { >- if ($data) { >- warn "Not a unique accountlines record for item $itemnum borrower $borrowernumber"; >- } else { >- $data = $rec; >- next; >- } >- } >- $total_amount_other += $rec->{'amountoutstanding'}; >- } >+ my $borrower = $schema->resultset('Borrower')->find($borrowernumber); > >- if (my $maxfine = C4::Context->preference('MaxFine')) { >- if ($total_amount_other + $amount > $maxfine) { >- my $new_amount = $maxfine - $total_amount_other; >- return if $new_amount <= 0.00; >- warn "Reducing fine for item $itemnum borrower $borrowernumber from $amount to $new_amount - MaxFine reached"; >+ if ( my $maxfine = C4::Context->preference('MaxFine') ) { >+ if ( $borrower->account_balance() + $amount > $maxfine ) { >+ my $new_amount = $maxfine - $borrower->account_balance(); >+ warn "Reducing fine for item $itemnumber borrower $borrowernumber from $amount to $new_amount - MaxFine reached"; >+ if ( $new_amount <= 0 ) { >+ warn "Fine reduced to a non-positive ammount. Fine not created."; >+ return; >+ } > $amount = $new_amount; > } > } > >- if ( $data ) { >- >- # we're updating an existing fine. Only modify if amount changed >- # Note that in the current implementation, you cannot pay against an accruing fine >- # (i.e. , of accounttype 'FU'). Doing so will break accrual. >- if ( $data->{'amount'} != $amount ) { >- my $diff = $amount - $data->{'amount'}; >- #3341: diff could be positive or negative! >- my $out = $data->{'amountoutstanding'} + $diff; >- my $query = " >- UPDATE accountlines >- SET date=now(), amount=?, amountoutstanding=?, >- lastincrement=?, accounttype='FU' >- WHERE borrowernumber=? >- AND itemnumber=? >- AND accounttype IN ('FU','O') >- AND description LIKE ? >- LIMIT 1 "; >- my $sth2 = $dbh->prepare($query); >- # FIXME: BOGUS query cannot ensure uniqueness w/ LIKE %x% !!! >- # LIMIT 1 added to prevent multiple affected lines >- # FIXME: accountlines table needs unique key!! Possibly a combo of borrowernumber and accountline. >- # But actually, we should just have a regular autoincrementing PK and forget accountline, >- # including the bogus getnextaccountno function (doesn't prevent conflict on simultaneous ops). >- # FIXME: Why only 2 account types here? >- $debug and print STDERR "UpdateFine query: $query\n" . >- "w/ args: $amount, $out, $diff, $data->{'borrowernumber'}, $data->{'itemnumber'}, \"\%$due\%\"\n"; >- $sth2->execute($amount, $out, $diff, $data->{'borrowernumber'}, $data->{'itemnumber'}, "%$due%"); >- } else { >- # print "no update needed $data->{'amount'}" >+ my $timestamp = get_timestamp(); >+ >+ my $fine = >+ $schema->resultset('AccountDebit')->single( { issue_id => $issue_id } ); >+ >+ my $offset = 0; >+ if ($fine) { >+ if ( >+ sprintf( "%.6f", $fine->amount_original() ) >+ ne >+ sprintf( "%.6f", $amount ) ) >+ { >+ my $difference = $amount - $fine->amount_original(); >+ >+ $fine->amount_original( $fine->amount_original() + $difference ); >+ $fine->amount_outstanding( $fine->amount_outstanding() + $difference ); >+ $fine->amount_last_increment($difference); >+ $fine->updated_on($timestamp); >+ $fine->update(); >+ >+ $offset = 1; > } >- } else { >- my $sth4 = $dbh->prepare( >- "SELECT title FROM biblio LEFT JOIN items ON biblio.biblionumber=items.biblionumber WHERE items.itemnumber=?" >+ } >+ else { >+ my $item = $schema->resultset('Item')->find($itemnumber); >+ >+ $fine = $schema->resultset('AccountDebit')->create( >+ { >+ borrowernumber => $borrowernumber, >+ itemnumber => $itemnumber, >+ issue_id => $issue_id, >+ type => Koha::Accounts::DebitTypes::Fine(), >+ accruing => 1, >+ amount_original => $amount, >+ amount_outstanding => $amount, >+ amount_last_increment => $amount, >+ description => $item->biblio()->title() . " / Due:$due", >+ created_on => $timestamp, >+ } > ); >- $sth4->execute($itemnum); >- my $title = $sth4->fetchrow; >- >-# # print "not in account"; >-# my $sth3 = $dbh->prepare("Select max(accountno) from accountlines"); >-# $sth3->execute; >-# >-# # FIXME - Make $accountno a scalar. >-# my @accountno = $sth3->fetchrow_array; >-# $sth3->finish; >-# $accountno[0]++; >-# begin transaction >- my $nextaccntno = C4::Accounts::getnextacctno($borrowernumber); >- my $desc = ($type ? "$type " : '') . "$title $due"; # FIXEDME, avoid whitespace prefix on empty $type >- my $query = "INSERT INTO accountlines >- (borrowernumber,itemnumber,date,amount,description,accounttype,amountoutstanding,lastincrement,accountno) >- VALUES (?,?,now(),?,?,'FU',?,?,?)"; >- my $sth2 = $dbh->prepare($query); >- $debug and print STDERR "UpdateFine query: $query\nw/ args: $borrowernumber, $itemnum, $amount, $desc, $amount, $amount, $nextaccntno\n"; >- $sth2->execute($borrowernumber, $itemnum, $amount, $desc, $amount, $amount, $nextaccntno); >+ >+ $offset = 1; > } >- # logging action >- &logaction( >- "FINES", >- $type, >+ >+ $schema->resultset('AccountOffset')->create( >+ { >+ debit_id => $fine->debit_id(), >+ amount => $fine->amount_last_increment(), >+ created_on => $timestamp, >+ type => Koha::Accounts::OffsetTypes::Fine(), >+ } >+ ) if $offset; >+ >+ logaction( "FINES", Koha::Accounts::DebitTypes::Fine(), > $borrowernumber, >- "due=".$due." amount=".$amount." itemnumber=".$itemnum >- ) if C4::Context->preference("FinesLog"); >+ "due=" . $due . " amount=" . $amount . " itemnumber=" . $itemnumber ) >+ if C4::Context->preference("FinesLog"); > } > > =head2 BorType >@@ -804,6 +764,7 @@ sub GetOverduesForBranch { > biblio.title, > biblio.author, > biblio.biblionumber, >+ issues.issue_id, > issues.date_due, > issues.returndate, > issues.branchcode, >diff --git a/C4/Reserves.pm b/C4/Reserves.pm >index d1bca25..3b8e77b 100644 >--- a/C4/Reserves.pm >+++ b/C4/Reserves.pm >@@ -172,19 +172,17 @@ sub AddReserve { > $waitingdate = $resdate; > } > >- #eval { >- # updates take place here > if ( $fee > 0 ) { >- my $nextacctno = &getnextacctno( $borrowernumber ); >- my $query = qq/ >- INSERT INTO accountlines >- (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding) >- VALUES >- (?,?,now(),?,?,'Res',?) >- /; >- my $usth = $dbh->prepare($query); >- $usth->execute( $borrowernumber, $nextacctno, $fee, >- "Reserve Charge - $title", $fee ); >+ AddDebit( >+ { >+ borrowernumber => $borrowernumber, >+ itemnumber => $checkitem, >+ amount => $fee, >+ type => Koha::Accounts::DebitTypes::Hold(), >+ description => "Hold fee - $title", >+ notes => "Record ID: $biblionumber", >+ } >+ ); > } > > #if ($const eq 'a'){ >diff --git a/Koha/Accounts.pm b/Koha/Accounts.pm >new file mode 100644 >index 0000000..56b57ed >--- /dev/null >+++ b/Koha/Accounts.pm >@@ -0,0 +1,515 @@ >+package Koha::Accounts; >+ >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use Carp; >+use Data::Dumper qw(Dumper); >+ >+use C4::Context; >+use C4::Log qw(logaction); >+use Koha::DateUtils qw(get_timestamp); >+ >+use Koha::Accounts::CreditTypes; >+use Koha::Accounts::DebitTypes; >+ >+use vars qw($VERSION @ISA @EXPORT); >+ >+BEGIN { >+ require Exporter; >+ @ISA = qw(Exporter); >+ @EXPORT = qw( >+ AddDebit >+ AddCredit >+ >+ NormalizeBalances >+ >+ RecalculateAccountBalance >+ >+ DebitLostItem >+ CreditLostItem >+ ); >+} >+ >+=head1 NAME >+ >+Koha::Accounts - Functions for dealing with Koha accounts >+ >+=head1 SYNOPSIS >+ >+use Koha::Accounts; >+ >+=head1 DESCRIPTION >+ >+The functions in this module deal with the monetary aspect of Koha, >+including looking up and modifying the amount of money owed by a >+patron. >+ >+=head1 FUNCTIONS >+ >+=head2 AddDebit >+ >+my $debit = AddDebit({ >+ borrower => $borrower, >+ amount => $amount, >+ [ type => $type, ] >+ [ itemnumber => $itemnumber, ] >+ [ issue_id => $issue_id, ] >+ [ description => $description, ] >+ [ notes => $notes, ] >+ [ branchcode => $branchcode, ] >+ [ manager_id => $manager_id, ] >+ [ accruing => $accruing, ] # Default 0 if not accruing, 1 if accruing >+}); >+ >+Create a new debit for a given borrower. To standardize nomenclature, any charge >+against a borrower ( e.g. a fine, a new card charge, the cost of losing an item ) >+will be referred to as a 'debit'. >+ >+=cut >+ >+sub AddDebit { >+ my ($params) = @_; >+ >+ my $borrower = $params->{borrower}; >+ my $amount = $params->{amount}; >+ >+ my $type = $params->{type}; >+ my $itemnumber = $params->{itemnumber}; >+ my $issue_id = $params->{issue_id}; >+ my $description = $params->{description}; >+ my $notes = $params->{notes}; >+ >+ my $branchcode = $params->{branchcode}; >+ $branchcode ||= >+ defined( C4::Context->userenv ) >+ ? C4::Context->userenv->{branch} >+ : undef; >+ >+ my $manager_id = $params->{manager_id}; >+ $manager_id ||= >+ defined( C4::Context->userenv ) >+ ? C4::Context->userenv->{manager_id} >+ : undef; >+ >+ my $accruing = $params->{accruing} || 0; >+ >+ croak("Required parameter 'borrower' not passed in.") >+ unless ($borrower); >+ croak("Required parameter 'amount' not passed in.") >+ unless ($amount); >+ croak("Invalid debit type: '$type'!") >+ unless ( Koha::Accounts::DebitTypes::IsValid($type) ); >+ croak("No issue id passed in for accruing debit!") >+ if ( $accruing && !$issue_id ); >+ >+ my $debit = Koha::Database->new()->schema->resultset('AccountDebit')->create( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ itemnumber => $itemnumber, >+ issue_id => $issue_id, >+ type => $type, >+ accruing => $accruing, >+ amount_original => $amount, >+ amount_outstanding => $amount, >+ amount_last_increment => $amount, >+ description => $description, >+ notes => $notes, >+ manager_id => $manager_id, >+ created_on => get_timestamp(), >+ } >+ ); >+ >+ if ($debit) { >+ $borrower->account_balance( $borrower->account_balance() + $amount ); >+ $borrower->update(); >+ >+ NormalizeBalances( { borrower => $borrower } ); >+ >+ if ( C4::Context->preference("FinesLog") ) { >+ logaction( "FINES", "CREATE_FEE", $debit->id, >+ Dumper( { $debit->get_columns(), accruing => $accruing } ) ); >+ } >+ } >+ else { >+ carp("Something went wrong! Debit not created!"); >+ } >+ >+ return $debit; >+} >+ >+=head2 DebitLostItem >+ >+my $debit = DebitLostItem({ >+ borrower => $borrower, >+ issue => $issue, >+}); >+ >+DebitLostItem adds a replacement fee charge for the item >+of the given issue. >+ >+=cut >+ >+sub DebitLostItem { >+ my ($params) = @_; >+ >+ my $borrower = $params->{borrower}; >+ my $issue = $params->{issue}; >+ >+ croak("Required param 'borrower' not passed in!") unless ($borrower); >+ croak("Required param 'issue' not passed in!") unless ($issue); >+ >+ # Don't add lost debit if borrower has already been charged for this lost item before, >+ # for this issue. It seems reasonable that a borrower could lose an item, find and return it, >+ # check it out again, and lose it again, so we should do this based on issue_id, not itemnumber. >+ unless ( >+ Koha::Database->new()->schema->resultset('AccountDebit')->search( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ issue_id => $issue->issue_id(), >+ type => Koha::Accounts::DebitTypes::Lost >+ } >+ )->count() >+ ) >+ { >+ my $item = $issue->item(); >+ >+ $params->{accruing} = 0; >+ $params->{type} = Koha::Accounts::DebitTypes::Lost; >+ $params->{amount} = $item->replacementprice(); >+ $params->{itemnumber} = $item->itemnumber(); >+ $params->{issue_id} = $issue->issue_id(); >+ >+ #TODO: Shouldn't we have a default replacement price as a syspref? >+ if ( $params->{amount} ) { >+ return AddDebit($params); >+ } >+ else { >+ carp("Cannot add lost debit! Item has no replacement price!"); >+ } >+ } >+} >+ >+=head2 CreditLostItem >+ >+my $debit = CreditLostItem( >+ { >+ borrower => $borrower, >+ debit => $debit, >+ } >+); >+ >+CreditLostItem creates a payment in the amount equal >+to the replacement price charge created by DebitLostItem. >+ >+=cut >+ >+sub CreditLostItem { >+ my ($params) = @_; >+ >+ my $borrower = $params->{borrower}; >+ my $debit = $params->{debit}; >+ >+ croak("Required param 'borrower' not passed in!") unless ($borrower); >+ croak("Required param 'debit' not passed in!") >+ unless ($debit); >+ >+ my $item = >+ Koha::Database->new()->schema->resultset('Item') >+ ->find( $debit->itemnumber() ); >+ carp("No item found!") unless $item; >+ >+ $params->{type} = Koha::Accounts::CreditTypes::Found; >+ $params->{amount} = $debit->amount_original(); >+ $params->{debit_id} = $debit->debit_id(); >+ $params->{notes} = "Lost item found: " . $item->barcode(); >+ >+ return AddCredit($params); >+} >+ >+=head2 AddCredit >+ >+AddCredit({ >+ borrower => $borrower, >+ amount => $amount, >+ [ branchcode => $branchcode, ] >+ [ manager_id => $manager_id, ] >+ [ debit_id => $debit_id, ] # The primary debit to be paid >+ [ notes => $notes, ] >+}); >+ >+Record credit by a patron. C<$borrowernumber> is the patron's >+borrower number. C<$credit> is a floating-point number, giving the >+amount that was paid. >+ >+Amounts owed are paid off oldest first. That is, if the patron has a >+$1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a credit >+of $1.50, then the oldest fine will be paid off in full, and $0.50 >+will be credited to the next one. >+ >+debit_id can be passed as a scalar or an array ref to make the passed >+in debit or debits the first to be credited. >+ >+=cut >+ >+sub AddCredit { >+ my ($params) = @_; >+ >+ my $type = $params->{type}; >+ my $borrower = $params->{borrower}; >+ my $amount = $params->{amount}; >+ my $debit_id = $params->{debit_id}; >+ my $notes = $params->{notes}; >+ my $branchcode = $params->{branchcode}; >+ my $manager_id = $params->{manager_id}; >+ >+ my $userenv = C4::Context->userenv; >+ >+ unless ( $manager_id || $userenv ) { >+ $manager_id = $userenv->{number}; >+ } >+ >+ unless ( $branchcode || $userenv ) { >+ $branchcode = $userenv->{branch}; >+ } >+ >+ unless ($borrower) { >+ croak("Required parameter 'borrower' not passed in"); >+ } >+ unless ($amount) { >+ croak("Required parameter amount not passed in"); >+ } >+ >+ unless ( Koha::Accounts::CreditTypes::IsValid($type) ) { >+ carp("Invalid credit type! Returning without creating credit."); >+ return; >+ } >+ >+ unless ($type) { >+ carp("No type passed in, assuming Payment"); >+ $type = Koha::Accounts::CreditTypes::Payment; >+ } >+ >+ my $debit = Koha::Database->new()->schema->resultset('AccountDebit')->find($debit_id); >+ >+ # First, we make the credit. We'll worry about what we paid later on >+ my $credit = Koha::Database->new()->schema->resultset('AccountCredit')->create( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ type => $type, >+ amount_paid => $amount, >+ amount_remaining => $amount, >+ notes => $notes, >+ manager_id => $manager_id, >+ created_on => get_timestamp(), >+ } >+ ); >+ >+ $borrower->account_balance( $borrower->account_balance() - $amount ); >+ $borrower->update(); >+ >+ # If we are given specific debits, pay those ones first. >+ if ( $debit_id ) { >+ my @debit_ids = ref( $debit_id ) eq "ARRAY" ? @$debit_id : $debit_id; >+ foreach my $debit_id (@debit_ids) { >+ my $debit = >+ Koha::Database->new()->schema->resultset('AccountDebit')->find($debit_id); >+ >+ if ($debit) { >+ CreditDebit( { credit => $credit, debit => $debit } ); >+ } >+ else { >+ carp("Invalid debit_id passed in!"); >+ } >+ } >+ } >+ >+ # We still have leftover money, or we weren't given a specific debit to pay >+ if ( $credit->amount_remaining() > 0 ) { >+ my @debits = Koha::Database->new()->schema->resultset('AccountDebit')->search( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ amount_outstanding => { '>' => '0' } >+ } >+ ); >+ >+ foreach my $debit (@debits) { >+ if ( $credit->amount_remaining() > 0 ) { >+ CreditDebit( >+ { >+ credit => $credit, >+ debit => $debit, >+ borrower => $borrower, >+ type => $type, >+ } >+ ); >+ } >+ } >+ } >+ >+ return $credit; >+} >+ >+=head2 CreditDebit >+ >+$account_offset = CreditDebit({ >+ credit => $credit, >+ debit => $debit, >+}); >+ >+Given a credit and a debit, this subroutine >+will pay the appropriate amount of the debit, >+update the debit's amount outstanding, the credit's >+amout remaining, and create the appropriate account >+offset. >+ >+=cut >+ >+sub CreditDebit { >+ my ($params) = @_; >+ >+ my $credit = $params->{credit}; >+ my $debit = $params->{debit}; >+ >+ croak("Required parameter 'credit' not passed in!") >+ unless $credit; >+ croak("Required parameter 'debit' not passed in!") unless $debit; >+ >+ my $amount_to_pay = >+ ( $debit->amount_outstanding() > $credit->amount_remaining() ) >+ ? $credit->amount_remaining() >+ : $debit->amount_outstanding(); >+ >+ if ( $amount_to_pay > 0 ) { >+ $debit->amount_outstanding( >+ $debit->amount_outstanding() - $amount_to_pay ); >+ $debit->update(); >+ >+ $credit->amount_remaining( >+ $credit->amount_remaining() - $amount_to_pay ); >+ $credit->update(); >+ >+ my $offset = Koha::Database->new()->schema->resultset('AccountOffset')->create( >+ { >+ amount => $amount_to_pay * -1, >+ debit_id => $debit->id(), >+ credit_id => $credit->id(), >+ created_on => get_timestamp(), >+ } >+ ); >+ >+ return $offset; >+ } >+} >+ >+=head2 RecalculateAccountBalance >+ >+$account_balance = RecalculateAccountBalance({ >+ borrower => $borrower >+}); >+ >+Recalculates a borrower's balance based on the >+sum of the amount outstanding for the borrower's >+debits minus the sum of the amount remaining for >+the borrowers credits. >+ >+TODO: Would it be better to use af.amount_original - ap.amount_paid for any reason? >+ Or, perhaps calculate both and compare the two, for error checking purposes. >+=cut >+ >+sub RecalculateAccountBalance { >+ my ($params) = @_; >+ >+ my $borrower = $params->{borrower}; >+ croak("Requred paramter 'borrower' not passed in!") >+ unless ($borrower); >+ >+ my $debits = >+ Koha::Database->new()->schema->resultset('AccountDebit') >+ ->search( { borrowernumber => $borrower->borrowernumber() } ); >+ my $amount_outstanding = $debits->get_column('amount_outstanding')->sum(); >+ >+ my $credits = >+ Koha::Database->new()->schema->resultset('AccountCredit') >+ ->search( { borrowernumber => $borrower->borrowernumber() } ); >+ my $amount_remaining = $credits->get_column('amount_remaining')->sum(); >+ >+ my $account_balance = $amount_outstanding - $amount_remaining; >+ $borrower->account_balance($account_balance); >+ $borrower->update(); >+ >+ return $account_balance; >+} >+ >+=head2 NormalizeBalances >+ >+ $account_balance = NormalizeBalances({ borrower => $borrower }); >+ >+ For a given borrower, this subroutine will find all debits >+ with an outstanding balance and all credits with an unused >+ amount remaining and will pay those debits with those credits. >+ >+=cut >+ >+sub NormalizeBalances { >+ my ($params) = @_; >+ >+ my $borrower = $params->{borrower}; >+ >+ croak("Required param 'borrower' not passed in!") unless $borrower; >+ >+ my @credits = Koha::Database->new()->schema->resultset('AccountCredit')->search( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ amount_remaining => { '>' => '0' } >+ } >+ ); >+ >+ return unless @credits; >+ >+ my @debits = Koha::Database->new()->schema->resultset('AccountDebit')->search( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ amount_outstanding => { '>' => '0' } >+ } >+ ); >+ >+ return unless @debits; >+ >+ foreach my $credit (@credits) { >+ foreach my $debit (@debits) { >+ if ( $credit->amount_remaining() >+ && $debit->amount_outstanding() ) >+ { >+ CreditDebit( { credit => $credit, debit => $debit } ); >+ } >+ } >+ } >+ >+ return RecalculateAccountBalance( { borrower => $borrower } ); >+} >+ >+1; >+__END__ >+ >+=head1 AUTHOR >+ >+Kyle M Hall <kyle@bywatersolutions.com> >+ >+=cut >diff --git a/Koha/Accounts/CreditTypes.pm b/Koha/Accounts/CreditTypes.pm >new file mode 100644 >index 0000000..d51ec93 >--- /dev/null >+++ b/Koha/Accounts/CreditTypes.pm >@@ -0,0 +1,117 @@ >+package Koha::Accounts::CreditTypes; >+ >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+=head1 NAME >+ >+Koha::AccountsCreditTypes - Module representing the enumerated data types for account fees >+ >+=head1 SYNOPSIS >+ >+use Koha::Accounts::CreditTypes; >+ >+my $type = Koha::Accounts::CreditTypes::Payment; >+ >+=head1 DESCRIPTION >+ >+The subroutines in this modules act as enumerated data types for the >+different credit types in Koha ( i.e. payments, writeoffs, etc. ) >+ >+=head1 FUNCTIONS >+ >+=head2 IsValid >+ >+This subroutine takes a given string and returns 1 if >+the string matches one of the data types, and 0 if not. >+ >+FIXME: Perhaps we should use Class::Inspector instead of hard >+coding the subs? It seems like it would be a major trade off >+of speed just so we don't update something in two separate places >+in the same file. >+ >+=cut >+ >+sub IsValid { >+ my ($string) = @_; >+ >+ my $is_valid = >+ ( $string eq Koha::Accounts::CreditTypes::Payment() >+ || $string eq Koha::Accounts::CreditTypes::WriteOff() >+ || $string eq Koha::Accounts::CreditTypes::Found() >+ || $string eq Koha::Accounts::CreditTypes::Credit() >+ || $string eq Koha::Accounts::CreditTypes::Forgiven() ); >+ >+ unless ($is_valid) { >+ $is_valid = >+ Koha::Database->new()->schema->resultset('AuthorisedValue') >+ ->count( >+ { category => 'ACCOUNT_CREDIT', authorised_value => $string } ); >+ } >+ >+ return $is_valid; >+} >+ >+=head2 Credit >+ >+=cut >+ >+sub Credit { >+ return 'CREDIT'; >+} >+ >+=head2 Payment >+ >+=cut >+ >+sub Payment { >+ return 'PAYMENT'; >+} >+ >+=head2 Writeoff >+ >+=cut >+ >+sub WriteOff { >+ return 'WRITEOFF'; >+} >+ >+=head2 Writeoff >+ >+=cut >+ >+sub Found { >+ return 'FOUND'; >+} >+ >+=head2 Forgiven >+ >+=cut >+ >+sub Forgiven { >+ return 'FORGIVEN'; >+} >+ >+1; >+ >+=head1 AUTHOR >+ >+Kyle M Hall <kyle@bywatersolutions.com> >+ >+=cut >diff --git a/Koha/Accounts/DebitTypes.pm b/Koha/Accounts/DebitTypes.pm >new file mode 100644 >index 0000000..3f30392 >--- /dev/null >+++ b/Koha/Accounts/DebitTypes.pm >@@ -0,0 +1,160 @@ >+package Koha::Accounts::DebitTypes; >+ >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+=head1 NAME >+ >+Koha::Accounts::DebitTypes - Module representing an enumerated data type for account fees >+ >+=head1 SYNOPSIS >+ >+use Koha::Accounts::DebitTypes; >+ >+my $type = Koha::Accounts::DebitTypes::Fine; >+ >+=head1 DESCRIPTION >+ >+The subroutines in this modules act as an enumerated data type >+for debit types ( stored in account_debits.type ) in Koha. >+ >+=head1 FUNCTIONS >+ >+=head2 IsValid >+ >+This subroutine takes a given string and returns 1 if >+the string matches one of the data types, and 0 if not. >+ >+=cut >+ >+sub IsValid { >+ my ($string) = @_; >+ >+ my $is_valid = >+ ( $string eq Koha::Accounts::DebitTypes::Fine() >+ || $string eq Koha::Accounts::DebitTypes::AccountManagementFee() >+ || $string eq Koha::Accounts::DebitTypes::Sundry() >+ || $string eq Koha::Accounts::DebitTypes::Lost() >+ || $string eq Koha::Accounts::DebitTypes::Hold() >+ || $string eq Koha::Accounts::DebitTypes::Rental() >+ || $string eq Koha::Accounts::DebitTypes::NewCard() ); >+ >+ unless ($is_valid) { >+ $is_valid = >+ Koha::Database->new()->schema->resultset('AuthorisedValue') >+ ->count( { category => 'MANUAL_INV', authorised_value => $string } ); >+ } >+ >+ return $is_valid; >+} >+ >+=head2 Fine >+ >+This data type represents a standard fine within Koha. >+ >+A fine still accruing no longer needs to be differiated by type >+from a fine done accuring. Instead, that differentication is made >+by which table the fine exists in, account_fees_accruing vs account_fees_accrued. >+ >+In addition, fines can be checked for correctness based on the issue_id >+they have. A fine in account_fees_accruing should always have a matching >+issue_id in the issues table. A fine done accruing will almost always have >+a matching issue_id in the old_issues table. However, in the case of an overdue >+item with fines that has been renewed, and becomes overdue again, you may have >+a case where a given issue may have a matching fine in account_fees_accruing and >+one or more matching fines in account_fees_accrued ( one for each for the first >+checkout and one each for any subsequent renewals ) >+ >+=cut >+ >+sub Fine { >+ return 'FINE'; >+} >+ >+=head2 AccountManagementFee >+ >+This fee type is usually reserved for payments for library cards, >+in cases where a library must charge a patron for the ability to >+check out items. >+ >+=cut >+ >+sub AccountManagementFee { >+ return 'ACCOUNT_MANAGEMENT_FEE'; >+} >+ >+=head2 Sundry >+ >+This fee type is basically a 'misc' type, and should be used >+when no other fee type is more appropriate. >+ >+=cut >+ >+sub Sundry { >+ return 'SUNDRY'; >+} >+ >+=head2 Lost >+ >+This fee type is used when a library charges for lost items. >+ >+=cut >+ >+sub Lost { >+ return 'LOST'; >+} >+ >+=head2 Hold >+ >+This fee type is used when a library charges for holds. >+ >+=cut >+ >+sub Hold { >+ return 'HOLD'; >+} >+ >+=head2 Rental >+ >+This fee type is used when a library charges a rental fee for the item type. >+ >+=cut >+ >+sub Rental { >+ return 'RENTAL'; >+} >+ >+=head2 NewCard >+ >+This fee type is used when a library charges for replacement >+library cards. >+ >+=cut >+ >+sub NewCard { >+ return 'NEW_CARD'; >+} >+ >+1; >+ >+=head1 AUTHOR >+ >+Kyle M Hall <kyle@bywatersolutions.com> >+ >+=cut >diff --git a/Koha/Accounts/OffsetTypes.pm b/Koha/Accounts/OffsetTypes.pm >new file mode 100644 >index 0000000..1a5aabb >--- /dev/null >+++ b/Koha/Accounts/OffsetTypes.pm >@@ -0,0 +1,72 @@ >+package Koha::Accounts::OffsetTypes; >+ >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+=head1 NAME >+ >+Koha::AccountsOffsetTypes - Module representing the enumerated data types for account fees >+ >+=head1 SYNOPSIS >+ >+use Koha::Accounts::OffsetTypes; >+ >+my $type = Koha::Accounts::OffsetTypes::Dropbox; >+ >+=head1 DESCRIPTION >+ >+The subroutines in this modules act as enumerated data types for the >+different automatic offset types in Koha ( i.e. forgiveness, dropbox mode, etc ) >+ >+These types are used for account offsets that have no corrosponding account credit, >+e.g. automatic fine increments, dropbox mode, etc. >+ >+=head1 FUNCTIONS >+ >+=cut >+ >+=head2 Dropbox >+ >+Offset type for automatic fine reductions >+via dropbox mode. >+ >+=cut >+ >+sub Dropbox { >+ return 'DROPBOX'; >+} >+ >+=head2 Fine >+ >+Indicates this offset was an automatically >+generated fine increment/decrement. >+ >+=cut >+ >+sub Fine { >+ return 'FINE'; >+} >+ >+1; >+ >+=head1 AUTHOR >+ >+Kyle M Hall <kyle@bywatersolutions.com> >+ >+=cut >diff --git a/Koha/DateUtils.pm b/Koha/DateUtils.pm >index 4ae0d0c..6dbc979 100644 >--- a/Koha/DateUtils.pm >+++ b/Koha/DateUtils.pm >@@ -21,13 +21,14 @@ use warnings; > use 5.010; > use DateTime; > use DateTime::Format::DateParse; >+use DateTime::Format::MySQL; > use C4::Context; > > use base 'Exporter'; > use version; our $VERSION = qv('1.0.0'); > > our @EXPORT = ( >- qw( dt_from_string output_pref format_sqldatetime output_pref_due format_sqlduedatetime) >+ qw( dt_from_string output_pref format_sqldatetime output_pref_due format_sqlduedatetime get_timestamp ) > ); > > =head1 DateUtils >@@ -239,4 +240,8 @@ sub format_sqlduedatetime { > return q{}; > } > >+sub get_timestamp { >+ return DateTime::Format::MySQL->format_datetime( dt_from_string() ); >+} >+ > 1; >diff --git a/Koha/Schema/Result/AccountCredit.pm b/Koha/Schema/Result/AccountCredit.pm >new file mode 100644 >index 0000000..bf8e076 >--- /dev/null >+++ b/Koha/Schema/Result/AccountCredit.pm >@@ -0,0 +1,134 @@ >+package Koha::Schema::Result::AccountCredit; >+ >+# Created by DBIx::Class::Schema::Loader >+# DO NOT MODIFY THE FIRST PART OF THIS FILE >+ >+use strict; >+use warnings; >+ >+use base 'DBIx::Class::Core'; >+ >+ >+=head1 NAME >+ >+Koha::Schema::Result::AccountCredit >+ >+=cut >+ >+__PACKAGE__->table("account_credits"); >+ >+=head1 ACCESSORS >+ >+=head2 credit_id >+ >+ data_type: 'integer' >+ is_auto_increment: 1 >+ is_nullable: 0 >+ >+=head2 borrowernumber >+ >+ data_type: 'integer' >+ is_foreign_key: 1 >+ is_nullable: 0 >+ >+=head2 type >+ >+ data_type: 'varchar' >+ is_nullable: 0 >+ size: 255 >+ >+=head2 amount_paid >+ >+ data_type: 'decimal' >+ is_nullable: 0 >+ size: [28,6] >+ >+=head2 amount_remaining >+ >+ data_type: 'decimal' >+ is_nullable: 0 >+ size: [28,6] >+ >+=head2 notes >+ >+ data_type: 'text' >+ is_nullable: 1 >+ >+=head2 manager_id >+ >+ data_type: 'integer' >+ is_nullable: 1 >+ >+=head2 created_on >+ >+ data_type: 'timestamp' >+ is_nullable: 1 >+ >+=head2 updated_on >+ >+ data_type: 'timestamp' >+ is_nullable: 1 >+ >+=cut >+ >+__PACKAGE__->add_columns( >+ "credit_id", >+ { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, >+ "borrowernumber", >+ { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, >+ "type", >+ { data_type => "varchar", is_nullable => 0, size => 255 }, >+ "amount_paid", >+ { data_type => "decimal", is_nullable => 0, size => [28, 6] }, >+ "amount_remaining", >+ { data_type => "decimal", is_nullable => 0, size => [28, 6] }, >+ "notes", >+ { data_type => "text", is_nullable => 1 }, >+ "manager_id", >+ { data_type => "integer", is_nullable => 1 }, >+ "created_on", >+ { data_type => "timestamp", is_nullable => 1 }, >+ "updated_on", >+ { data_type => "timestamp", is_nullable => 1 }, >+); >+__PACKAGE__->set_primary_key("credit_id"); >+ >+=head1 RELATIONS >+ >+=head2 borrowernumber >+ >+Type: belongs_to >+ >+Related object: L<Koha::Schema::Result::Borrower> >+ >+=cut >+ >+__PACKAGE__->belongs_to( >+ "borrowernumber", >+ "Koha::Schema::Result::Borrower", >+ { borrowernumber => "borrowernumber" }, >+ { on_delete => "CASCADE", on_update => "CASCADE" }, >+); >+ >+=head2 account_offsets >+ >+Type: has_many >+ >+Related object: L<Koha::Schema::Result::AccountOffset> >+ >+=cut >+ >+__PACKAGE__->has_many( >+ "account_offsets", >+ "Koha::Schema::Result::AccountOffset", >+ { "foreign.credit_id" => "self.credit_id" }, >+ { cascade_copy => 0, cascade_delete => 0 }, >+); >+ >+ >+# Created by DBIx::Class::Schema::Loader v0.07000 @ 2013-10-09 10:37:23 >+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:uvt4OuaJxv4jk08zJsKouw >+ >+ >+# You can replace this text with custom content, and it will be preserved on regeneration >+1; >diff --git a/Koha/Schema/Result/AccountDebit.pm b/Koha/Schema/Result/AccountDebit.pm >new file mode 100644 >index 0000000..8206c2b >--- /dev/null >+++ b/Koha/Schema/Result/AccountDebit.pm >@@ -0,0 +1,177 @@ >+package Koha::Schema::Result::AccountDebit; >+ >+# Created by DBIx::Class::Schema::Loader >+# DO NOT MODIFY THE FIRST PART OF THIS FILE >+ >+use strict; >+use warnings; >+ >+use base 'DBIx::Class::Core'; >+ >+ >+=head1 NAME >+ >+Koha::Schema::Result::AccountDebit >+ >+=cut >+ >+__PACKAGE__->table("account_debits"); >+ >+=head1 ACCESSORS >+ >+=head2 debit_id >+ >+ data_type: 'integer' >+ is_auto_increment: 1 >+ is_nullable: 0 >+ >+=head2 borrowernumber >+ >+ data_type: 'integer' >+ default_value: 0 >+ is_foreign_key: 1 >+ is_nullable: 0 >+ >+=head2 itemnumber >+ >+ data_type: 'integer' >+ is_nullable: 1 >+ >+=head2 issue_id >+ >+ data_type: 'integer' >+ is_nullable: 1 >+ >+=head2 type >+ >+ data_type: 'varchar' >+ is_nullable: 0 >+ size: 255 >+ >+=head2 accruing >+ >+ data_type: 'tinyint' >+ default_value: 0 >+ is_nullable: 0 >+ >+=head2 amount_original >+ >+ data_type: 'decimal' >+ is_nullable: 1 >+ size: [28,6] >+ >+=head2 amount_outstanding >+ >+ data_type: 'decimal' >+ is_nullable: 1 >+ size: [28,6] >+ >+=head2 amount_last_increment >+ >+ data_type: 'decimal' >+ is_nullable: 1 >+ size: [28,6] >+ >+=head2 description >+ >+ data_type: 'mediumtext' >+ is_nullable: 1 >+ >+=head2 notes >+ >+ data_type: 'text' >+ is_nullable: 1 >+ >+=head2 manager_id >+ >+ data_type: 'integer' >+ is_nullable: 1 >+ >+=head2 created_on >+ >+ data_type: 'timestamp' >+ is_nullable: 1 >+ >+=head2 updated_on >+ >+ data_type: 'timestamp' >+ is_nullable: 1 >+ >+=cut >+ >+__PACKAGE__->add_columns( >+ "debit_id", >+ { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, >+ "borrowernumber", >+ { >+ data_type => "integer", >+ default_value => 0, >+ is_foreign_key => 1, >+ is_nullable => 0, >+ }, >+ "itemnumber", >+ { data_type => "integer", is_nullable => 1 }, >+ "issue_id", >+ { data_type => "integer", is_nullable => 1 }, >+ "type", >+ { data_type => "varchar", is_nullable => 0, size => 255 }, >+ "accruing", >+ { data_type => "tinyint", default_value => 0, is_nullable => 0 }, >+ "amount_original", >+ { data_type => "decimal", is_nullable => 1, size => [28, 6] }, >+ "amount_outstanding", >+ { data_type => "decimal", is_nullable => 1, size => [28, 6] }, >+ "amount_last_increment", >+ { data_type => "decimal", is_nullable => 1, size => [28, 6] }, >+ "description", >+ { data_type => "mediumtext", is_nullable => 1 }, >+ "notes", >+ { data_type => "text", is_nullable => 1 }, >+ "manager_id", >+ { data_type => "integer", is_nullable => 1 }, >+ "created_on", >+ { data_type => "timestamp", is_nullable => 1 }, >+ "updated_on", >+ { data_type => "timestamp", is_nullable => 1 }, >+); >+__PACKAGE__->set_primary_key("debit_id"); >+ >+=head1 RELATIONS >+ >+=head2 borrowernumber >+ >+Type: belongs_to >+ >+Related object: L<Koha::Schema::Result::Borrower> >+ >+=cut >+ >+__PACKAGE__->belongs_to( >+ "borrowernumber", >+ "Koha::Schema::Result::Borrower", >+ { borrowernumber => "borrowernumber" }, >+ { on_delete => "CASCADE", on_update => "CASCADE" }, >+); >+ >+=head2 account_offsets >+ >+Type: has_many >+ >+Related object: L<Koha::Schema::Result::AccountOffset> >+ >+=cut >+ >+__PACKAGE__->has_many( >+ "account_offsets", >+ "Koha::Schema::Result::AccountOffset", >+ { "foreign.debit_id" => "self.debit_id" }, >+ { cascade_copy => 0, cascade_delete => 0 }, >+); >+ >+ >+# Created by DBIx::Class::Schema::Loader v0.07000 @ 2013-11-05 08:09:09 >+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ulQStZJSzcD4hvrPbtew4g >+ >+ >+# You can replace this text with custom content, and it will be preserved on regeneration >+1; >diff --git a/Koha/Schema/Result/AccountOffset.pm b/Koha/Schema/Result/AccountOffset.pm >new file mode 100644 >index 0000000..179392f >--- /dev/null >+++ b/Koha/Schema/Result/AccountOffset.pm >@@ -0,0 +1,118 @@ >+package Koha::Schema::Result::AccountOffset; >+ >+# Created by DBIx::Class::Schema::Loader >+# DO NOT MODIFY THE FIRST PART OF THIS FILE >+ >+use strict; >+use warnings; >+ >+use base 'DBIx::Class::Core'; >+ >+ >+=head1 NAME >+ >+Koha::Schema::Result::AccountOffset >+ >+=cut >+ >+__PACKAGE__->table("account_offsets"); >+ >+=head1 ACCESSORS >+ >+=head2 offset_id >+ >+ data_type: 'integer' >+ is_auto_increment: 1 >+ is_nullable: 0 >+ >+=head2 debit_id >+ >+ data_type: 'integer' >+ is_foreign_key: 1 >+ is_nullable: 1 >+ >+=head2 credit_id >+ >+ data_type: 'integer' >+ is_foreign_key: 1 >+ is_nullable: 1 >+ >+=head2 type >+ >+ data_type: 'varchar' >+ is_nullable: 1 >+ size: 255 >+ >+=head2 amount >+ >+ data_type: 'decimal' >+ is_nullable: 0 >+ size: [28,6] >+ >+=head2 created_on >+ >+ data_type: 'timestamp' >+ default_value: current_timestamp >+ is_nullable: 0 >+ >+=cut >+ >+__PACKAGE__->add_columns( >+ "offset_id", >+ { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, >+ "debit_id", >+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, >+ "credit_id", >+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, >+ "type", >+ { data_type => "varchar", is_nullable => 1, size => 255 }, >+ "amount", >+ { data_type => "decimal", is_nullable => 0, size => [28, 6] }, >+ "created_on", >+ { >+ data_type => "timestamp", >+ default_value => \"current_timestamp", >+ is_nullable => 0, >+ }, >+); >+__PACKAGE__->set_primary_key("offset_id"); >+ >+=head1 RELATIONS >+ >+=head2 debit >+ >+Type: belongs_to >+ >+Related object: L<Koha::Schema::Result::AccountDebit> >+ >+=cut >+ >+__PACKAGE__->belongs_to( >+ "debit", >+ "Koha::Schema::Result::AccountDebit", >+ { debit_id => "debit_id" }, >+ { join_type => "LEFT", on_delete => "CASCADE", on_update => "CASCADE" }, >+); >+ >+=head2 credit >+ >+Type: belongs_to >+ >+Related object: L<Koha::Schema::Result::AccountCredit> >+ >+=cut >+ >+__PACKAGE__->belongs_to( >+ "credit", >+ "Koha::Schema::Result::AccountCredit", >+ { credit_id => "credit_id" }, >+ { join_type => "LEFT", on_delete => "CASCADE", on_update => "CASCADE" }, >+); >+ >+ >+# Created by DBIx::Class::Schema::Loader v0.07000 @ 2013-11-05 08:47:10 >+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BLjpL8skXmzxOQ/J0jzdvw >+ >+ >+# You can replace this text with custom content, and it will be preserved on regeneration >+1; >diff --git a/Koha/Schema/Result/Borrower.pm b/Koha/Schema/Result/Borrower.pm >index 3d9f9ae..a3946b4 100644 >--- a/Koha/Schema/Result/Borrower.pm >+++ b/Koha/Schema/Result/Borrower.pm >@@ -1,21 +1,17 @@ >-use utf8; > package Koha::Schema::Result::Borrower; > > # Created by DBIx::Class::Schema::Loader > # DO NOT MODIFY THE FIRST PART OF THIS FILE > >-=head1 NAME >- >-Koha::Schema::Result::Borrower >- >-=cut >- > use strict; > use warnings; > > use base 'DBIx::Class::Core'; > >-=head1 TABLE: C<borrowers> >+ >+=head1 NAME >+ >+Koha::Schema::Result::Borrower > > =cut > >@@ -191,7 +187,6 @@ __PACKAGE__->table("borrowers"); > =head2 dateofbirth > > data_type: 'date' >- datetime_undef_if_invalid: 1 > is_nullable: 1 > > =head2 branchcode >@@ -213,13 +208,11 @@ __PACKAGE__->table("borrowers"); > =head2 dateenrolled > > data_type: 'date' >- datetime_undef_if_invalid: 1 > is_nullable: 1 > > =head2 dateexpiry > > data_type: 'date' >- datetime_undef_if_invalid: 1 > is_nullable: 1 > > =head2 gonenoaddress >@@ -235,7 +228,6 @@ __PACKAGE__->table("borrowers"); > =head2 debarred > > data_type: 'date' >- datetime_undef_if_invalid: 1 > is_nullable: 1 > > =head2 debarredcomment >@@ -397,6 +389,13 @@ __PACKAGE__->table("borrowers"); > default_value: 1 > is_nullable: 0 > >+=head2 account_balance >+ >+ data_type: 'decimal' >+ default_value: 0.000000 >+ is_nullable: 0 >+ size: [28,6] >+ > =cut > > __PACKAGE__->add_columns( >@@ -463,7 +462,7 @@ __PACKAGE__->add_columns( > "b_phone", > { data_type => "mediumtext", is_nullable => 1 }, > "dateofbirth", >- { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, >+ { data_type => "date", is_nullable => 1 }, > "branchcode", > { > data_type => "varchar", >@@ -481,15 +480,15 @@ __PACKAGE__->add_columns( > size => 10, > }, > "dateenrolled", >- { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, >+ { data_type => "date", is_nullable => 1 }, > "dateexpiry", >- { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, >+ { data_type => "date", is_nullable => 1 }, > "gonenoaddress", > { data_type => "tinyint", is_nullable => 1 }, > "lost", > { data_type => "tinyint", is_nullable => 1 }, > "debarred", >- { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, >+ { data_type => "date", is_nullable => 1 }, > "debarredcomment", > { data_type => "varchar", is_nullable => 1, size => 255 }, > "contactname", >@@ -546,35 +545,48 @@ __PACKAGE__->add_columns( > { data_type => "varchar", is_nullable => 1, size => 50 }, > "privacy", > { data_type => "integer", default_value => 1, is_nullable => 0 }, >+ "account_balance", >+ { >+ data_type => "decimal", >+ default_value => "0.000000", >+ is_nullable => 0, >+ size => [28, 6], >+ }, > ); >+__PACKAGE__->set_primary_key("borrowernumber"); >+__PACKAGE__->add_unique_constraint("cardnumber", ["cardnumber"]); > >-=head1 PRIMARY KEY >+=head1 RELATIONS > >-=over 4 >+=head2 account_credits > >-=item * L</borrowernumber> >+Type: has_many > >-=back >+Related object: L<Koha::Schema::Result::AccountCredit> > > =cut > >-__PACKAGE__->set_primary_key("borrowernumber"); >- >-=head1 UNIQUE CONSTRAINTS >- >-=head2 C<cardnumber> >+__PACKAGE__->has_many( >+ "account_credits", >+ "Koha::Schema::Result::AccountCredit", >+ { "foreign.borrowernumber" => "self.borrowernumber" }, >+ { cascade_copy => 0, cascade_delete => 0 }, >+); > >-=over 4 >+=head2 account_debits > >-=item * L</cardnumber> >+Type: has_many > >-=back >+Related object: L<Koha::Schema::Result::AccountDebit> > > =cut > >-__PACKAGE__->add_unique_constraint("cardnumber", ["cardnumber"]); >- >-=head1 RELATIONS >+__PACKAGE__->has_many( >+ "account_debits", >+ "Koha::Schema::Result::AccountDebit", >+ { "foreign.borrowernumber" => "self.borrowernumber" }, >+ { cascade_copy => 0, cascade_delete => 0 }, >+); > > =head2 accountlines > >@@ -696,34 +708,34 @@ __PACKAGE__->has_many( > { cascade_copy => 0, cascade_delete => 0 }, > ); > >-=head2 branchcode >+=head2 categorycode > > Type: belongs_to > >-Related object: L<Koha::Schema::Result::Branch> >+Related object: L<Koha::Schema::Result::Category> > > =cut > > __PACKAGE__->belongs_to( >- "branchcode", >- "Koha::Schema::Result::Branch", >- { branchcode => "branchcode" }, >- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, >+ "categorycode", >+ "Koha::Schema::Result::Category", >+ { categorycode => "categorycode" }, >+ { on_delete => "CASCADE", on_update => "CASCADE" }, > ); > >-=head2 categorycode >+=head2 branchcode > > Type: belongs_to > >-Related object: L<Koha::Schema::Result::Category> >+Related object: L<Koha::Schema::Result::Branch> > > =cut > > __PACKAGE__->belongs_to( >- "categorycode", >- "Koha::Schema::Result::Category", >- { categorycode => "categorycode" }, >- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, >+ "branchcode", >+ "Koha::Schema::Result::Branch", >+ { branchcode => "branchcode" }, >+ { on_delete => "CASCADE", on_update => "CASCADE" }, > ); > > =head2 course_instructors >@@ -1041,39 +1053,9 @@ __PACKAGE__->has_many( > { cascade_copy => 0, cascade_delete => 0 }, > ); > >-=head2 basketnoes >- >-Type: many_to_many >- >-Composing rels: L</aqbasketusers> -> basketno >- >-=cut >- >-__PACKAGE__->many_to_many("basketnoes", "aqbasketusers", "basketno"); >- >-=head2 budgets >- >-Type: many_to_many >- >-Composing rels: L</aqbudgetborrowers> -> budget >- >-=cut >- >-__PACKAGE__->many_to_many("budgets", "aqbudgetborrowers", "budget"); >- >-=head2 courses >- >-Type: many_to_many >- >-Composing rels: L</course_instructors> -> course >- >-=cut >- >-__PACKAGE__->many_to_many("courses", "course_instructors", "course"); >- > >-# Created by DBIx::Class::Schema::Loader v0.07025 @ 2013-10-31 16:31:19 >-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:z4kW3xYX1CyrwvGdZu32nA >+# Created by DBIx::Class::Schema::Loader v0.07000 @ 2013-11-12 08:27:25 >+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CcXsGi7pVHQtO+YH3pY/1A > > > # You can replace this text with custom content, and it will be preserved on regeneration >diff --git a/Koha/Schema/Result/Issue.pm b/Koha/Schema/Result/Issue.pm >index 282c802..99274ea 100644 >--- a/Koha/Schema/Result/Issue.pm >+++ b/Koha/Schema/Result/Issue.pm >@@ -187,7 +187,14 @@ __PACKAGE__->belongs_to( > "borrower", > "Koha::Schema::Result::Borrower", > { borrowernumber => "borrowernumber" }, >- { join_type => "LEFT", on_delete => "CASCADE", on_update => "CASCADE" }, >+ { join_type => "LEFT" }, >+); >+ >+__PACKAGE__->belongs_to( >+ "item", >+ "Koha::Schema::Result::Item", >+ { itemnumber => "itemnumber" }, >+ { join_type => "LEFT" }, > ); > > 1; >diff --git a/Koha/Schema/Result/OldIssue.pm b/Koha/Schema/Result/OldIssue.pm >index 4050f06..e1e7e69 100644 >--- a/Koha/Schema/Result/OldIssue.pm >+++ b/Koha/Schema/Result/OldIssue.pm >@@ -183,6 +183,32 @@ __PACKAGE__->belongs_to( > # Created by DBIx::Class::Schema::Loader v0.07025 @ 2013-10-14 20:56:21 > # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:uPOxNROoMMRZ0qZsXsxEjA > >+__PACKAGE__->belongs_to( >+ "borrower", >+ "Koha::Schema::Result::Borrower", >+ { borrowernumber => "borrowernumber" }, >+ { join_type => "LEFT" }, >+); >+ >+__PACKAGE__->belongs_to( >+ "item", >+ "Koha::Schema::Result::Item", >+ { itemnumber => "itemnumber" }, >+ { join_type => "LEFT" }, >+); >+ >+__PACKAGE__->belongs_to( >+ "deletedborrower", >+ "Koha::Schema::Result::Deletedborrower", >+ { borrowernumber => "borrowernumber" }, >+ { join_type => "LEFT" }, >+); >+ >+__PACKAGE__->belongs_to( >+ "deleteditem", >+ "Koha::Schema::Result::Deleteditem", >+ { itemnumber => "itemnumber" }, >+ { join_type => "LEFT" }, >+); > >-# You can replace this text with custom content, and it will be preserved on regeneration > 1; >diff --git a/Koha/Template/Plugin/Currency.pm b/Koha/Template/Plugin/Currency.pm >new file mode 100644 >index 0000000..fb24f93 >--- /dev/null >+++ b/Koha/Template/Plugin/Currency.pm >@@ -0,0 +1,64 @@ >+package Koha::Template::Plugin::Currency; >+ >+# Copyright ByWater Solutions 2013 >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use base qw( Template::Plugin::Filter ); >+ >+use Locale::Currency::Format; >+ >+use C4::Context; >+use Koha::DateUtils; >+ >+sub init { >+ my $self = shift; >+ >+ my $active_currency = C4::Context->dbh->selectrow_hashref( >+ 'SELECT * FROM currency WHERE active = 1', {} ); >+ $self->{active_currency} = $active_currency; >+ >+ return $self; >+} >+ >+sub filter { >+ my ( $self, $amount ) = @_; >+ >+ return $self->format($amount); >+} >+ >+sub format { >+ my ( $self, $amount, $format ) = @_; >+ >+ return currency_format( $self->{active_currency}->{currency}, >+ $amount, $format || FMT_HTML ); >+} >+ >+sub format_without_symbol { >+ my ( $self, $amount ) = @_; >+ >+ return substr( $self->format( $amount, FMT_SYMBOL ), 1 ); >+} >+ >+sub symbol { >+ my ($self) = @_; >+ >+ return currency_symbol( $self->{active_currency}->{'currency'}, SYM_HTML ); >+} >+ >+1; >diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql >index fefc985..a7ddc46 100644 >--- a/installer/data/mysql/kohastructure.sql >+++ b/installer/data/mysql/kohastructure.sql >@@ -3387,6 +3387,89 @@ CREATE TABLE IF NOT EXISTS marc_modification_template_actions ( > CONSTRAINT `mmta_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `marc_modification_templates` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE > ) ENGINE=InnoDB DEFAULT CHARSET=utf8; > >+-- >+-- Table structure for table 'account_credits' >+-- >+DROP TABLE IF EXISTS account_credits; >+CREATE TABLE IF account_credits ( >+ credit_id int(11) NOT NULL AUTO_INCREMENT, >+ borrowernumber int(11) NOT NULL, >+ `type` varchar(255) NOT NULL, >+ amount_paid decimal(28,6) NOT NULL, >+ amount_remaining decimal(28,6) NOT NULL, >+ notes text, >+ manager_id int(11) DEFAULT NULL, >+ created_on timestamp NULL DEFAULT NULL, >+ updated_on timestamp NULL DEFAULT NULL, >+ PRIMARY KEY (credit_id), >+ KEY borrowernumber (borrowernumber) >+) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ >+-- >+-- Constraints for table `account_credits` >+-- >+ALTER TABLE `account_credits` >+ ADD CONSTRAINT account_credits_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; >+ >+-- >+-- Table structure for table 'account_debits' >+-- >+ >+DROP TABLE IF EXISTS account_debits; >+CREATE TABLE account_debits ( >+ debit_id int(11) NOT NULL AUTO_INCREMENT, >+ borrowernumber int(11) NOT NULL DEFAULT '0', >+ itemnumber int(11) DEFAULT NULL, >+ issue_id int(11) DEFAULT NULL, >+ `type` varchar(255) NOT NULL, >+ accruing tinyint(1) NOT NULL DEFAULT '0', >+ amount_original decimal(28,6) DEFAULT NULL, >+ amount_outstanding decimal(28,6) DEFAULT NULL, >+ amount_last_increment decimal(28,6) DEFAULT NULL, >+ description mediumtext, >+ notes text, >+ manager_id int(11) DEFAULT NULL, >+ created_on timestamp NULL DEFAULT NULL, >+ updated_on timestamp NULL DEFAULT NULL, >+ PRIMARY KEY (debit_id), >+ KEY acctsborridx (borrowernumber), >+ KEY itemnumber (itemnumber), >+ KEY borrowernumber (borrowernumber), >+ KEY issue_id (issue_id) >+) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ >+-- >+-- Constraints for table `account_debits` >+-- >+ALTER TABLE `account_debits` >+ ADD CONSTRAINT account_debits_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; >+ >+-- >+-- Table structure for table 'account_offsets' >+-- >+ >+DROP TABLE IF EXISTS account_offsets; >+CREATE TABLE account_offsets ( >+ offset_id int(11) NOT NULL AUTO_INCREMENT, >+ debit_id int(11) DEFAULT NULL, >+ credit_id int(11) DEFAULT NULL, >+ `type` varchar(255) DEFAULT NULL, >+ amount decimal(28,6) NOT NULL, >+ created_on timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, >+ PRIMARY KEY (offset_id), >+ KEY fee_id (debit_id), >+ KEY payment_id (credit_id) >+) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ >+-- >+-- Constraints for table `account_offsets` >+-- >+ALTER TABLE `account_offsets` >+ ADD CONSTRAINT account_offsets_ibfk_1 FOREIGN KEY (debit_id) REFERENCES account_debits (debit_id) ON DELETE CASCADE ON UPDATE CASCADE, >+ ADD CONSTRAINT account_offsets_ibfk_2 FOREIGN KEY (credit_id) REFERENCES account_credits (credit_id) ON DELETE CASCADE ON UPDATE CASCADE; >+ >+>>>>>>> 0c386fa... Bug 6427 - Rewrite of the accounts system - WIP >+ > /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; > /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; > /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; >diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl >index 6162bc5..d85348f 100755 >--- a/installer/data/mysql/updatedatabase.pl >+++ b/installer/data/mysql/updatedatabase.pl >@@ -7259,6 +7259,7 @@ if ( CheckVersion($DBversion) ) { > > $dbh->{AutoCommit} = 1; > $dbh->{RaiseError} = 0; >+ SetVersion ($DBversion); > } > > $DBversion = "3.13.00.031"; >@@ -7743,6 +7744,81 @@ if(CheckVersion($DBversion)) { > SetVersion($DBversion); > } > >+$DBversion = "3.15.00.XXX"; >+if ( CheckVersion($DBversion) ) { >+ $dbh->do("ALTER TABLE issues ADD issue_id INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST"); >+ $dbh->do("ALTER TABLE old_issues ADD issue_id INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST"); >+ $dbh->do(" >+ CREATE TABLE IF NOT EXISTS account_credits ( >+ credit_id int(11) NOT NULL AUTO_INCREMENT, >+ borrowernumber int(11) NOT NULL, >+ `type` varchar(255) NOT NULL, >+ amount_paid decimal(28,6) NOT NULL, >+ amount_remaining decimal(28,6) NOT NULL, >+ notes text, >+ manager_id int(11) DEFAULT NULL, >+ created_on timestamp NULL DEFAULT NULL, >+ updated_on timestamp NULL DEFAULT NULL, >+ PRIMARY KEY (credit_id), >+ KEY borrowernumber (borrowernumber) >+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ "); >+ $dbh->do(" >+ CREATE TABLE IF NOT EXISTS account_debits ( >+ debit_id int(11) NOT NULL AUTO_INCREMENT, >+ borrowernumber int(11) NOT NULL DEFAULT '0', >+ itemnumber int(11) DEFAULT NULL, >+ issue_id int(11) DEFAULT NULL, >+ `type` varchar(255) NOT NULL, >+ accruing tinyint(1) NOT NULL DEFAULT '0', >+ amount_original decimal(28,6) DEFAULT NULL, >+ amount_outstanding decimal(28,6) DEFAULT NULL, >+ amount_last_increment decimal(28,6) DEFAULT NULL, >+ description mediumtext, >+ notes text, >+ manager_id int(11) DEFAULT NULL, >+ created_on timestamp NULL DEFAULT NULL, >+ updated_on timestamp NULL DEFAULT NULL, >+ PRIMARY KEY (debit_id), >+ KEY acctsborridx (borrowernumber), >+ KEY itemnumber (itemnumber), >+ KEY borrowernumber (borrowernumber), >+ KEY issue_id (issue_id) >+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ "); >+ >+ $dbh->do(" >+ CREATE TABLE account_offsets ( >+ offset_id int(11) NOT NULL AUTO_INCREMENT, >+ debit_id int(11) DEFAULT NULL, >+ credit_id int(11) DEFAULT NULL, >+ `type` varchar(255) DEFAULT NULL, >+ amount decimal(28,6) NOT NULL COMMENT 'A positive number here represents a payment, a negative is a increase in a fine.', >+ created_on timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, >+ PRIMARY KEY (offset_id), >+ KEY fee_id (debit_id), >+ KEY payment_id (credit_id) >+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ "); >+ >+ $dbh->do(" >+ ALTER TABLE `account_credits` >+ ADD CONSTRAINT account_credits_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; >+ "); >+ $dbh->do(" >+ ALTER TABLE `account_debits` >+ ADD CONSTRAINT account_debits_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; >+ "); >+ $dbh->do(" >+ ALTER TABLE `account_offsets` >+ ADD CONSTRAINT account_offsets_ibfk_1 FOREIGN KEY (debit_id) REFERENCES account_debits (debit_id) ON DELETE CASCADE ON UPDATE CASCADE, >+ ADD CONSTRAINT account_offsets_ibfk_2 FOREIGN KEY (credit_id) REFERENCES account_credits (credit_id) ON DELETE CASCADE ON UPDATE CASCADE; >+ "); >+ >+ print "Upgrade to $DBversion done ( Bug 6427 - Rewrite of the accounts system )\n"; >+ SetVersion ($DBversion); >+} >+ > =head1 FUNCTIONS > > =head2 TableExists($table) >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >index 62db1c5..f5b2706 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >@@ -67,7 +67,7 @@ > [% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">Details</a></li> > [% END %] > [% IF ( CAN_user_updatecharges ) %] >- [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Fines</a></li> >+ [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Fines</a></li> > [% END %] > [% IF ( RoutingSerials ) %][% IF ( routinglistview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/routing-lists.pl?borrowernumber=[% borrowernumber %]">Routing lists</a></li>[% END %] > [% IF ( intranetreadinghistory ) %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt >index 7f8cb48..fbaea81 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt >@@ -70,7 +70,7 @@ in the global namespace %] > [% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrower.borrowernumber %]">Details</a></li> > [% END %] > [% IF ( CAN_user_updatecharges ) %] >- [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Fines</a></li> >+ [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrower.borrowernumber %]">Fines</a></li> > [% END %] > [% IF ( RoutingSerials ) %][% IF ( routinglistview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/routing-lists.pl?borrowernumber=[% borrower.borrowernumber %]">Routing lists</a></li>[% END %] > [% IF ( intranetreadinghistory ) %][% IF ( readingrecordview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/readingrec.pl?borrowernumber=[% borrower.borrowernumber %]">Circulation history</a></li>[% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/members-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/members-menu.inc >index 9bd5285..9208e17 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/members-menu.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/members-menu.inc >@@ -4,7 +4,7 @@ > [% IF ( circview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% borrowernumber %]">Check out</a></li> > [% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">Details</a></li> > [% IF ( CAN_user_updatecharges ) %] >- [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Fines</a></li> >+ [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Fines</a></li> > [% END %] > [% IF ( intranetreadinghistory ) %] > [% IF ( readingrecordview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/readingrec.pl?borrowernumber=[% borrowernumber %]">Circulation history</a></li> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >index 46b82a8..5bfbd58 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >@@ -1,5 +1,6 @@ > [% USE KohaBranchName %] > [% USE KohaDates %] >+[% USE Currency %] > [% IF ( export_remove_fields OR export_with_csv_profile ) %] > [% SET exports_enabled = 1 %] > [% END %] >@@ -577,16 +578,16 @@ No patron matched <span class="ex">[% message %]</span> > > [% IF ( charges ) %] > <li> >- <span class="circ-hlt">Fees & Charges:</span> Patron has <a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Outstanding fees & charges[% IF ( chargesamount ) %] of [% chargesamount %][% END %]</a>. >+ <span class="circ-hlt">Fees & Charges:</span> Patron has <a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Outstanding fees & charges[% IF ( chargesamount ) %] of [% chargesamount | $Currency %][% END %]</a>. > [% IF ( charges_is_blocker ) %] > Checkouts are <span class="circ-hlt">BLOCKED</span> because fine balance is <span class="circ-hlt">OVER THE LIMIT</span>. > [% END %] >- <a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrowernumber %]">Make payment</a></li> >+ <a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrowernumber %]">Make payment</a></li> > [% END %] > > [% IF ( credits ) %] > <li> >- <span class="circ-hlt">Credits:</span> Patron has a credit[% IF ( creditsamount ) %] of [% creditsamount %][% END %] >+ <span class="circ-hlt">Credits:</span> Patron has a credit[% IF ( creditsamount ) %] of [% creditsamount | $Currency %][% END %] > </li> > [% END %] > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >index fb30311..ffe4e0d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >@@ -74,7 +74,7 @@ $(document).ready(function () { > [% IF ( fines ) %] > <div class="dialog alert"> > <h3>Patron has outstanding fines of [% fines %].</h3> >- <p><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% fineborrowernumber %]">Make payment</a>.</p> >+ <p><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% fineborrowernumber %]">Make payment</a>.</p> > </div> > [% END %] > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/account.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account.tt >new file mode 100644 >index 0000000..a12337d >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account.tt >@@ -0,0 +1,166 @@ >+[% USE KohaDates %] >+[% USE Currency %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Patrons › Account for [% INCLUDE 'patron-title.inc' %]</title> >+[% INCLUDE 'doc-head-close.inc' %] >+<style type="text/css"> >+#account-tabs-debits, #account-tabs-credits { >+ min-height:100px; >+} >+#account-tabs { >+ position: relative; >+ padding-right: 6.5em; >+} >+#account-tabs .ui-tabs-nav { >+ position: absolute; >+ right: 0.25em; >+ top: 1em; >+ bottom: 0.25em; >+ width: 6em; >+ padding: 0.2em 0.2em 0.2em 0em; >+} >+#account-tabs .ui-tabs-nav li { >+ width: 100%; >+ border-left: none; >+ border-bottom-width: 1px !important; >+ -moz-border-radius: 0px 4px 4px 0px; >+ -webkit-border-radius: 0px 4px 4px 0px; >+ border-radius: 0px 4px 4px 0px; >+ overflow: hidden; >+} >+#account-tabs .ui-tabs-nav li.ui-tabs-selected, >+#account-tabs .ui-tabs-nav li.ui-state-active { >+ left: -1px; >+ border-left: 1px solid transparent; >+} >+#account-tabs .ui-tabs-nav li a { >+ width: 100%; >+} >+</style> >+<script> >+$(function() { >+ $( "#account-tabs" ).tabs(); >+ $( "#debits-accordion" ).accordion(); >+}); >+</script> >+</head> >+<body id="pat_borraccount" class="pat"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'patron-search.inc' %] >+ >+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Account for [% INCLUDE 'patron-title.inc' %]</div> >+ >+<div id="doc3" class="yui-t2"> >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ [% INCLUDE 'members-toolbar.inc' %] >+ >+ <div class="statictabs"> >+ <ul> >+ <li class="active"> >+ <a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Account</a> >+ </li> >+ >+ <li> >+ <a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a> >+ </li> >+ >+ <li> >+ <a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a> >+ </li> >+ >+ <li> >+ <a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a> >+ </li> >+ </ul> >+ >+ <div class="tabs-container"> >+ >+ <p> >+ <h3>Account balance: [% borrower.account_balance | $Currency %]</h3> >+ </p> >+ >+ <div> >+ <div id="account-tabs"> >+ <ul> >+ <li> >+ <a href="#account-tabs-debits">Fees</a> >+ </li> >+ <li> >+ <a href="#account-tabs-credits">Payments</a> >+ </li> >+ </ul> >+ >+ <div id="account-tabs-debits"> >+ <div id="debits-accordion"> >+ [% FOREACH d IN debits %] >+ <h3> >+ >+ [% d.amount_outstanding | $Currency %] ( [% d.amount_original | $Currency %] ) >+ [% d.created_on | $KohaDates %] >+ >+ [% d.description %] >+ </h3> >+ >+ <div> >+ [% IF d.notes %] >+ <p> >+ Notes: <i>[% d.notes %]</i> >+ </p> >+ [% END %] >+ >+ [% IF d.updated_on %] >+ <p> >+ Last modified: [% d.updated_on | $KohaDates %] >+ </p> >+ [% END %] >+ >+ [% IF d.account_offsets %] >+ <table> >+ <thead> >+ <tr> >+ <th colspan="5">Offsets</th> >+ </tr> >+ <tr> >+ <th>ID</td> >+ <th>Date applied</th> >+ <th>Amount applied</th> >+ <th>Type</th> >+ <th>Notes</th> >+ </tr> >+ </thead> >+ >+ <tbody> >+ [% FOREACH ao IN d.account_offsets %] >+ <tr> >+ <td>[% ao.credit.credit_id %]</td> >+ <td>[% ao.created_on | $KohaDates %]</td> >+ <td>[% ao.amount | $Currency %]</td> >+ <td>[% ao.credit.type %]</td> >+ <td>[% ao.credit.notes %]</td> >+ </tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% END %] >+ </div> >+ [% END %] >+ </div> >+ </div> >+ >+ <div id="account-tabs-credits"> >+ Payments >+ </div> >+ </div> >+ </div> >+ </div> >+ </div> >+ </div> >+ </div> >+ >+ <div class="yui-b"> >+ [% INCLUDE 'circ-menu.inc' %] >+ </div> >+</div> >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_credit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_credit.tt >new file mode 100644 >index 0000000..10abb1d >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_credit.tt >@@ -0,0 +1,91 @@ >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Borrowers › Create manual credit</title> >+[% INCLUDE 'doc-head-close.inc' %] >+<script type="text/javascript"> >+//<![CDATA[ >+$(document).ready(function(){ >+ $('#account_credit').preventDoubleFormSubmit(); >+ $("fieldset.rows input").addClass("noEnterSubmit"); >+}); >+//]]> >+</script> >+</head> >+<body id="pat_account_credit" class="pat"> >+ [% INCLUDE 'header.inc' %] >+ [% INCLUDE 'patron-search.inc' %] >+ >+ <div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Manual credit</div> >+ >+ <div id="doc3" class="yui-t2"> >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ [% INCLUDE 'members-toolbar.inc' %] >+ >+ <div class="statictabs"> >+ <ul> >+ <li><a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >+ <li><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >+ <li><a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >+ <li class="active"><a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> >+ </ul> >+ >+ <div class="tabs-container"> >+ >+ <form action="/cgi-bin/koha/members/account_credit_do.pl" method="post" id="account_credit"> >+ <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" /> >+ >+ <fieldset class="rows"> >+ <legend>Manual credit</legend> >+ >+ <ol> >+ <li> >+ <label for="type">Credit Type: </label> >+ <select name="type" id="type"> >+ <option value="CREDIT">Credit</option> >+ <option value="FORGIVEN">Forgiven</option> >+ [% FOREACH c IN credit_types_loop %] >+ <option value="[% c.authorised_value %]">[% c.lib %]</option> >+ [% END %] >+ </select> >+ </li> >+ >+ <li> >+ <label for="barcode">Barcode: </label> >+ <input type="text" name="barcode" id="barcode" /> >+ </li> >+ >+ <li> >+ <label for="desc">Description: </label> >+ <input type="text" name="desc" size="50" id="desc" /> >+ </li> >+ >+ <li> >+ <label for="note">Note: </label> >+ <input type="text" name="note" size="50" id="note" /> >+ </li> >+ >+ <li> >+ <label for="amount">Amount: </label> >+ <input type="text" name="amount" id="amount" /> >+ Example: 5.00 >+ </li> >+ </ol> >+ >+ </fieldset> >+ >+ <fieldset class="action"> >+ <input type="submit" name="add" value="Add credit" /> >+ <a class="cancel" href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Cancel</a> >+ </fieldset> >+ </form> >+ >+ </div> >+ </div> >+ </div> >+ </div> >+ <div class="yui-b"> >+ [% INCLUDE 'circ-menu.inc' %] >+ </div> >+ </div> >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_debit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_debit.tt >new file mode 100644 >index 0000000..6bdff70 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_debit.tt >@@ -0,0 +1,108 @@ >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Borrowers › Create manual invoice</title> >+[% INCLUDE 'doc-head-close.inc' %] >+<script type="text/javascript"> >+//<![CDATA[ >+$(document).ready(function(){ >+ $('#maninvoice').preventDoubleFormSubmit(); >+ $("fieldset.rows input").addClass("noEnterSubmit"); >+ >+ var type_fees = new Array(); >+ type_fees['L'] = ''; >+ type_fees['F'] = ''; >+ type_fees['A'] = ''; >+ type_fees['N'] = ''; >+ type_fees['M'] = ''; >+ [% FOREACH invoice_types_loo IN invoice_types_loop %] >+ type_fees['[% invoice_types_loo.authorised_value %]'] = "[% invoice_types_loo.lib %]"; >+ [% END %] >+}); >+//]]> >+</script> >+</head> >+ >+<body> >+ [% INCLUDE 'header.inc' %] >+ [% INCLUDE 'patron-search.inc' %] >+ >+ <div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Manual invoice</div> >+ >+ <div id="doc3" class="yui-t2"> >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ [% INCLUDE 'members-toolbar.inc' %] >+ >+ <div class="statictabs"> >+ <ul> >+ <li><a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >+ <li><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >+ <li class="active"><a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >+ <li><a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> >+ </ul> >+ <div class="tabs-container"> >+ >+ <form action="/cgi-bin/koha/members/account_debit_do.pl" method="post" id="account_debit"> >+ <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" /> >+ >+ <fieldset class="rows"> >+ <legend>Manual Invoice</legend> >+ >+ <ol> >+ <li> >+ <label for="type">Type: </label> >+ <select name="type" id="type"> >+ <option value="LOST">Lost item</option> >+ <option value="FINE">Fine</option> >+ <option value="ACCOUNT_MANAGEMENT_FEE">Account management fee</option> >+ <option value="NEW_CARD">New card</option> >+ <option value="SUNDRY">Sundry</option> >+ >+ [% FOREACH invoice_types_loo IN invoice_types_loop %] >+ <option value="[% invoice_types_loo.authorised_value %]">[% invoice_types_loo.lib %]</option> >+ [% END %] >+ </select> >+ </li> >+ >+ <!-- TODO: Write ajax barcode validator that appends the itemnumber for this form in a hidden input --> >+ <li> >+ <label for="barcode">Barcode: </label> >+ <input type="text" name="barcode" id="barcode" /> >+ </li> >+ >+ <li> >+ <label for="description">Description: </label> >+ <input type="text" name="description" id="description" size="50" /> >+ </li> >+ >+ <li> >+ <label for="notes">Notes: </label> >+ <input type="text" name="notes" size="50" id="notes" /> >+ </li> >+ >+ <li> >+ <label for="amount">Amount: </label> >+ <input type="text" name="amount" id="amount" /> Example: 5.00 >+ </li> >+ >+ </ol> >+ </fieldset> >+ >+ <fieldset class="action"> >+ <input type="submit" name="add" value="Save" /> >+ <a class="cancel" href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Cancel</a> >+ </fieldset> >+ >+ </form> >+ >+ </div> >+ </div> >+ </div> >+ </div> >+ >+<div class="yui-b"> >+ [% INCLUDE 'circ-menu.inc' %] >+</div> >+ >+</div> >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_payment.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_payment.tt >new file mode 100644 >index 0000000..766c001 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/account_payment.tt >@@ -0,0 +1,200 @@ >+[% USE Currency %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Patrons › Pay Fines for [% borrower.firstname %] [% borrower.surname %]</title> >+[% INCLUDE 'doc-head-close.inc' %] >+<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script> >+<script type= "text/javascript"> >+//<![CDATA[ >+$( document ).ready(function() { >+ // Show amount recieved only if the "Receive different amount" checkbox is checked >+ $("#amount-received-p").hide(); >+ $('#receive_different_amount').click(function() { >+ if( $(this).is(':checked')) { >+ $("#amount-received-p").show(); >+ } else { >+ $("#amount-received-p").hide(); >+ } >+ }); >+ >+ // Enable the "Select all/Clear all" links >+ $('#CheckAll').click(function() { >+ $("input[name='debit_id']" ).prop('checked', true); >+ }); >+ $('#ClearAll').click(function() { >+ $("input[name='debit_id']" ).prop('checked', false); >+ }); >+ >+ // Update the "amount to pay" field whenever a fee checkbox is changed >+ // Note, this is just a payment suggestion and can be changed to any amount >+ $("input[name='debit_id']" ).change(function() { >+ var sum = 0; >+ $("input[name='debit_id']:checked" ).each(function(i,n){ >+ sum += parseFloat( $( "#amount_outstanding_" + $(this).val() ).val() ); >+ }); >+ $('#amount_to_pay').val( sum ); >+ }); >+}); >+ >+function checkForm(){ >+ // If using the "amount to receive" field, make sure the librarian is recieving at >+ // least enough to pay those fees. >+ if ( $('#amount_to_receive').val() ) { >+ if ( parseFloat( $('#amount_to_receive').val() ) < parseFloat( $('#amount_to_pay').val() ) ) { >+ alert( _("Cannot pay more than receieved!") ); >+ return false; >+ } >+ } >+ >+ return true; >+} >+//]]> >+</script> >+</head> >+<body id="pat_pay" class="pat"> >+ [% INCLUDE 'header.inc' %] >+ [% INCLUDE 'patron-search.inc' %] >+ >+ <div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> >+ › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> >+ › Pay fines for [% borrower.firstname %] [% borrower.surname %] >+ </div> >+ >+ <div id="doc3" class="yui-t2"> >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ [% INCLUDE 'members-toolbar.inc' borrowernumber=borrower.borrowernumber %] >+ >+ <div class="statictabs"> >+ <ul> >+ <li><a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrower.borrowernumber %]">Account</a></li> >+ <li class="active"><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrower.borrowernumber %]" >Pay fines</a></li> >+ <li><a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual invoice</a></li> >+ <li><a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual credit</a></li> >+ </ul> >+ >+ <div class="tabs-container"> >+ >+ [% IF ( debits ) %] >+ <form action="/cgi-bin/koha/members/account_payment_do.pl" method="post" id="account-payment-form" onsubmit="return checkForm()"> >+ >+ <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrower.borrowernumber %]" /> >+ >+ <p> >+ <span class="checkall"> >+ <a id="CheckAll" href="#">Select all</a> >+ </span> >+ >+ | >+ >+ <span class="clearall"> >+ <a id="ClearAll" href="#">Clear all</a> >+ </span> >+ </p> >+ >+ <table id="finest"> >+ <thead> >+ <tr> >+ <th> </th> >+ <th>Description</th> >+ <th>Account type</th> >+ <th>Original amount</th> >+ <th>Amount outstanding</th> >+ </tr> >+ </thead> >+ >+ <tbody> >+ [% SET total_due = 0 %] >+ [% FOREACH d IN debits %] >+ [% SET total_due = total_due + d.amount_outstanding %] >+ <tr> >+ <td> >+ <input type="checkbox" checked="checked" name="debit_id" value="[% d.debit_id %]" /> >+ </td> >+ >+ <td> >+ [% d.description %] >+ >+ [% IF d.notes %] >+ ( <i>[% d.notes %]</i> ) >+ [% END %] >+ </td> >+ >+ <td> >+ [% d.type %] >+ </td> >+ >+ <td class="debit"> >+ [% d.amount_original | $Currency %] >+ <input type="hidden" id="amount_original_[% d.debit_id %]" value="[% Currency.format_without_symbol( d.amount_original ) %]" /> >+ </td> >+ >+ <td class="debit"> >+ [% d.amount_outstanding | $Currency %] >+ <input type="hidden" id="amount_outstanding_[% d.debit_id %]" value="[% Currency.format_without_symbol( d.amount_outstanding ) %]" /> >+ </td> >+ </tr> >+ [% END %] >+ </tbody> >+ >+ <tfoot> >+ <tr> >+ <td class="total" colspan="4">Total Due:</td> >+ <td>[% total_due | $Currency %]</td> >+ </tr> >+ </tfoot> >+ >+ </table> >+ >+ <fieldset> >+ <p> >+ <label for="amount_to_pay">Amount to pay: [% Currency.symbol() %]</label> >+ <input type="text" name="amount_to_pay" id="amount_to_pay" value="[% Currency.format_without_symbol( total_due ) %]" /> >+ >+ <input type="checkbox" id="receive_different_amount" /> >+ <label for="receive_different_amount"><i>Receive different amount</i></label> >+ </p> >+ >+ <p id="amount-received-p"> >+ <label for="amount_to_receive">Amount recieved: [% Currency.symbol() %]</label> >+ <input type="text" name="amount_to_receive" id="amount_to_receive" /> >+ </p> >+ >+ <p> >+ <label for="type">Type:</label> >+ <select id="type" name="type"> >+ <option value="PAYMENT">Payment</option> >+ <option value="WRITEOFF">Write-off</option> >+ </select> >+ </p> >+ >+ <p> >+ <label for="notes">Payment notes:</label> >+ <input type="textbox" name="notes" id="notes" /> >+ <p> >+ </fieldset> >+ >+ <fieldset class="action"> >+ <input type="submit" value="Process" class="submit" /> >+ <a class="cancel" href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a> >+ </fieldset> >+ >+ </form> >+ >+ [% ELSE %] >+ <p> >+ [% borrower.firstname %] [% borrower.surname %] has no outstanding fines. >+ </p> >+ [% END %] >+ >+ </div> >+ </div> >+ </div> >+ </div> >+ >+ <div class="yui-b"> >+ [% INCLUDE 'circ-menu.tt' %] >+ </div> >+ </div> >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt >index d64c63b..48730b5 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt >@@ -14,15 +14,15 @@ > <div id="yui-main"> > <div class="yui-b"> > [% INCLUDE 'members-toolbar.inc' %] >-<form action="/cgi-bin/koha/members/boraccount.pl" method="get"><input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" /></form> >+<form action="/cgi-bin/koha/members/account.pl" method="get"><input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" /></form> > > <!-- The manual invoice and credit buttons --> > <div class="statictabs"> > <ul> >- <li class="active"><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >- <li><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >- <li><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >- <li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> >+ <li class="active"><a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >+ <li><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >+ <li><a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >+ <li><a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> > </ul> > <div class="tabs-container"> > <!-- The table with the account items --> >@@ -51,7 +51,7 @@ > [% IF ( reverse_col ) %] > <td> > [% IF ( account.payment ) %] >- <a href="boraccount.pl?action=reverse&accountlines_id=[% account.accountlines_id %]&borrowernumber=[% account.borrowernumber %]">Reverse</a> >+ <a href="account.pl?action=reverse&accountlines_id=[% account.accountlines_id %]&borrowernumber=[% account.borrowernumber %]">Reverse</a> > [% ELSE %] > > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/mancredit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/mancredit.tt >index ff2b6b6..b7e4396 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/mancredit.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/mancredit.tt >@@ -26,14 +26,14 @@ $(document).ready(function(){ > <!-- The manual invoice and credit buttons --> > <div class="statictabs"> > <ul> >- <li><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >- <li><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >- <li><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >- <li class="active"><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> >+ <li><a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >+ <li><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >+ <li><a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >+ <li class="active"><a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> > </ul> > <div class="tabs-container"> > >-<form action="/cgi-bin/koha/members/mancredit.pl" method="post" id="mancredit"> >+<form action="/cgi-bin/koha/members/account_credit.pl" method="post" id="mancredit"> > <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" /> > > <fieldset class="rows"> >@@ -48,7 +48,7 @@ $(document).ready(function(){ > <li><label for="amount">Amount: </label><input type="text" name="amount" id="amount" /> Example: 5.00</li> > </ol></fieldset> > >-<fieldset class="action"><input type="submit" name="add" value="Add credit" /> <a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Cancel</a></fieldset> >+<fieldset class="action"><input type="submit" name="add" value="Add credit" /> <a class="cancel" href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Cancel</a></fieldset> > </form> > > </div></div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/maninvoice.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/maninvoice.tt >index 30a4e20..d9ef1f7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/maninvoice.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/maninvoice.tt >@@ -26,10 +26,10 @@ $(document).ready(function(){ > <!-- The manual invoice and credit buttons --> > <div class="statictabs"> > <ul> >- <li><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >- <li><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >- <li class="active"><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >- <li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> >+ <li><a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Account</a></li> >+ <li><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li> >+ <li class="active"><a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrowernumber %]" >Create manual invoice</a></li> >+ <li><a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrowernumber %]" >Create manual credit</a></li> > </ul> > <div class="tabs-container"> > >@@ -38,7 +38,7 @@ $(document).ready(function(){ > ERROR an invalid itemnumber was entered, please hit back and try again > [% END %] > [% ELSE %] >-<form action="/cgi-bin/koha/members/maninvoice.pl" method="post" id="maninvoice"><input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" /> >+<form action="/cgi-bin/koha/members/account_debit.pl" method="post" id="maninvoice"><input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" /> > <fieldset class="rows"> > <legend>Manual Invoice</legend> > <ol> >@@ -71,7 +71,7 @@ type_fees['[% invoice_types_loo.authorised_value %]'] = "[% invoice_types_loo.li > <li><label for="note">Note: </label><input type="text" name="note" size="50" id="note" /></li> > <li><label for="amount">Amount: </label><input type="text" name="amount" id="amount" /> Example: 5.00</li> > </ol></fieldset> >-<fieldset class="action"><input type="submit" name="add" value="Save" /> <a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Cancel</a></fieldset> >+<fieldset class="action"><input type="submit" name="add" value="Save" /> <a class="cancel" href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrowernumber %]">Cancel</a></fieldset> > </form> > > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt >index 91f1609..96202df 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt >@@ -55,15 +55,15 @@ function enableCheckboxActions(){ > <!-- The manual invoice and credit buttons --> > <div class="statictabs"> > <ul> >- <li><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Account</a></li> >- <li class="active"><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]" >Pay fines</a></li> >- <li><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual invoice</a></li> >- <li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual credit</a></li> >+ <li><a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrower.borrowernumber %]">Account</a></li> >+ <li class="active"><a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrower.borrowernumber %]" >Pay fines</a></li> >+ <li><a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual invoice</a></li> >+ <li><a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual credit</a></li> > </ul> > <div class="tabs-container"> > > [% IF ( accounts ) %] >- <form action="/cgi-bin/koha/members/pay.pl" method="post" id="pay-fines-form"> >+ <form action="/cgi-bin/koha/members/account_payment.pl" method="post" id="pay-fines-form"> > <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrower.borrowernumber %]" /> > <p><span class="checkall"><a id="CheckAll" href="#">Select all</a></span> | <span class="clearall"><a id="CheckNone" href="#">Clear all</a></span></p> > <table id="finest"> >@@ -135,7 +135,7 @@ function enableCheckboxActions(){ > <input type="submit" id="paycollect" name="paycollect" value="Pay amount" class="submit" /> > <input type="submit" name="woall" id="woall" value="Write off all" class="submit" /> > <input type="submit" id="payselected" name="payselected" value="Pay selected" class="submit" /> >-<a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a> >+<a class="cancel" href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a> > </fieldset> > </form> > [% ELSE %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt >index 9cec275..369b9ec 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt >@@ -64,7 +64,7 @@ function moneyFormat(textObj) { > <body id="pat_paycollect" class="pat"> > [% INCLUDE 'header.inc' %] > [% INCLUDE 'patron-search.inc' %] >-<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › <a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]">Pay fines for [% borrower.firstname %] [% borrower.surname %]</a> › [% IF ( pay_individual ) %]Pay an individual fine[% ELSIF ( writeoff_individual ) %]Write off an individual fine[% ELSE %][% IF ( selected_accts ) %]Pay an amount toward selected fines[% ELSE %]Pay an amount toward all fines[% END %][% END %]</div> >+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › <a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrower.borrowernumber %]">Pay fines for [% borrower.firstname %] [% borrower.surname %]</a> › [% IF ( pay_individual ) %]Pay an individual fine[% ELSIF ( writeoff_individual ) %]Write off an individual fine[% ELSE %][% IF ( selected_accts ) %]Pay an amount toward selected fines[% ELSE %]Pay an amount toward all fines[% END %][% END %]</div> > > <div id="doc3" class="yui-t2"> > >@@ -78,16 +78,16 @@ function moneyFormat(textObj) { > <div class="statictabs"> > <ul> > <li> >- <a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Account</a> >+ <a href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrower.borrowernumber %]">Account</a> > </li> > <li class="active"> >- <a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]" >Pay fines</a> >+ <a href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrower.borrowernumber %]" >Pay fines</a> > </li> > <li> >- <a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual invoice</a> >+ <a href="/cgi-bin/koha/members/account_debit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual invoice</a> > </li> > <li> >- <a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual credit</a> >+ <a href="/cgi-bin/koha/members/account_credit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create manual credit</a> > </li> > </ul> > <div class="tabs-container"> >@@ -150,10 +150,10 @@ function moneyFormat(textObj) { > </fieldset> > > <div class="action"><input type="submit" name="submitbutton" value="Confirm" /> >- <a class="cancel" href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a></div> >+ <a class="cancel" href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a></div> > </form> > [% ELSIF ( writeoff_individual ) %] >- <form name="woindivfine" id="woindivfine" action="/cgi-bin/koha/members/pay.pl" method="post" > >+ <form name="woindivfine" id="woindivfine" action="/cgi-bin/koha/members/account_payment.pl" method="post" > > <fieldset class="rows"> > <legend>Write off an individual fine</legend> > <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrower.borrowernumber %]" /> >@@ -190,7 +190,7 @@ function moneyFormat(textObj) { > </table> > </fieldset> > <div class="action"><input type="submit" name="confirm_writeoff" id="confirm_writeoff" value="Write off this charge" /> >- <a class="cancel" href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a></div> >+ <a class="cancel" href="/cgi-bin/koha/members/account_payment.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a></div> > </form> > [% ELSE %] > >@@ -218,7 +218,7 @@ function moneyFormat(textObj) { > </ol> > </fieldset> > <div class="action"><input type="submit" name="submitbutton" value="Confirm" /> >- <a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a></div> >+ <a class="cancel" href="/cgi-bin/koha/members/account.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a></div> > </form> > [% END %] > </div></div> >diff --git a/members/account.pl b/members/account.pl >new file mode 100755 >index 0000000..87507dc >--- /dev/null >+++ b/members/account.pl >@@ -0,0 +1,111 @@ >+#!/usr/bin/perl >+ >+# Copyright 2000-2002 Katipo Communications >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use CGI; >+ >+use C4::Auth; >+use C4::Output; >+use C4::Dates qw/format_date/; >+use C4::Members; >+use C4::Branch; >+use C4::Accounts; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use Koha::Database; >+ >+my $cgi = new CGI; >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => "members/account.tt", >+ query => $cgi, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { borrowers => 1, updatecharges => 1 }, >+ debug => 1, >+ } >+); >+ >+my $borrowernumber = $cgi->param('borrowernumber'); >+ >+my $borrower = GetMember( 'borrowernumber' => $borrowernumber ); >+ >+my @debits = Koha::Database->new()->schema->resultset('AccountDebit')->search( >+ { 'me.borrowernumber' => $borrowernumber }, >+ { prefetch => { account_offsets => 'credit' } } >+); >+ >+my @credits => Koha::Database->new()->schema->resultset('AccountCredit') >+ ->search( { borrowernumber => $borrowernumber } ); >+ >+$template->param( >+ debits => \@debits, >+ credits => \@credits, >+ borrower => $borrower, >+); >+ >+# Standard /members/ borrower details data >+## FIXME: This code is in every /members/ script and should be unified >+ >+if ( $borrower->{'category_type'} eq 'C' ) { >+ my ( $catcodes, $labels ) = >+ GetborCatFromCatType( 'A', 'WHERE category_type = ?' ); >+ my $cnt = scalar(@$catcodes); >+ $template->param( 'CATCODE_MULTI' => 1 ) if $cnt > 1; >+ $template->param( 'catcode' => $catcodes->[0] ) if $cnt == 1; >+} >+ >+my ( $picture, $dberror ) = GetPatronImage( $borrower->{'borrowernumber'} ); >+$template->param( picture => 1 ) if $picture; >+ >+if ( C4::Context->preference('ExtendedPatronAttributes') ) { >+ my $attributes = GetBorrowerAttributes($borrowernumber); >+ $template->param( >+ ExtendedPatronAttributes => 1, >+ extendedattributes => $attributes >+ ); >+} >+ >+$template->param( >+ borrowernumber => $borrowernumber, >+ firstname => $borrower->{'firstname'}, >+ surname => $borrower->{'surname'}, >+ cardnumber => $borrower->{'cardnumber'}, >+ categorycode => $borrower->{'categorycode'}, >+ category_type => $borrower->{'category_type'}, >+ categoryname => $borrower->{'description'}, >+ address => $borrower->{'address'}, >+ address2 => $borrower->{'address2'}, >+ city => $borrower->{'city'}, >+ state => $borrower->{'state'}, >+ zipcode => $borrower->{'zipcode'}, >+ country => $borrower->{'country'}, >+ phone => $borrower->{'phone'}, >+ email => $borrower->{'email'}, >+ branchcode => $borrower->{'branchcode'}, >+ branchname => GetBranchName( $borrower->{'branchcode'} ), >+ is_child => ( $borrower->{'category_type'} eq 'C' ), >+ activeBorrowerRelationship => >+ ( C4::Context->preference('borrowerRelationship') ne '' ), >+ RoutingSerials => C4::Context->preference('RoutingSerials'), >+); >+ >+output_html_with_http_headers $cgi, $cookie, $template->output; >diff --git a/members/account_credit.pl b/members/account_credit.pl >new file mode 100755 >index 0000000..976232a >--- /dev/null >+++ b/members/account_credit.pl >@@ -0,0 +1,104 @@ >+#!/usr/bin/perl >+ >+#written 11/1/2000 by chris@katipo.oc.nz >+#script to display borrowers account details >+ >+# Copyright 2000-2002 Katipo Communications >+# Copyright 2010 BibLibre >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use strict; >+use warnings; >+ >+use C4::Auth; >+use C4::Output; >+use CGI; >+ >+use C4::Koha; >+use C4::Members; >+use C4::Branch; >+use C4::Accounts; >+use C4::Items; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use Koha::Database; >+ >+my $cgi = new CGI; >+ >+my $borrowernumber = $cgi->param('borrowernumber'); >+ >+my $borrower = GetMember( 'borrowernumber' => $borrowernumber ); >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => "members/account_credit.tt", >+ query => $cgi, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { borrowers => 1, updatecharges => 1 }, >+ debug => 1, >+ } >+); >+ >+$template->param( credit_types_loop => GetAuthorisedValues('ACCOUNT_CREDIT') ); >+ >+# Standard /members/ borrower details data >+## FIXME: This code is in every /members/ script and should be unified >+ >+if ( $borrower->{'category_type'} eq 'C' ) { >+ my ( $catcodes, $labels ) = >+ GetborCatFromCatType( 'A', 'WHERE category_type = ?' ); >+ my $cnt = scalar(@$catcodes); >+ $template->param( 'CATCODE_MULTI' => 1 ) if $cnt > 1; >+ $template->param( 'catcode' => $catcodes->[0] ) if $cnt == 1; >+} >+ >+my ( $picture, $dberror ) = GetPatronImage( $borrower->{'borrowernumber'} ); >+$template->param( picture => 1 ) if $picture; >+ >+if ( C4::Context->preference('ExtendedPatronAttributes') ) { >+ my $attributes = GetBorrowerAttributes($borrowernumber); >+ $template->param( >+ ExtendedPatronAttributes => 1, >+ extendedattributes => $attributes >+ ); >+} >+ >+$template->param( >+ borrowernumber => $borrowernumber, >+ firstname => $borrower->{'firstname'}, >+ surname => $borrower->{'surname'}, >+ cardnumber => $borrower->{'cardnumber'}, >+ categorycode => $borrower->{'categorycode'}, >+ category_type => $borrower->{'category_type'}, >+ categoryname => $borrower->{'description'}, >+ address => $borrower->{'address'}, >+ address2 => $borrower->{'address2'}, >+ city => $borrower->{'city'}, >+ state => $borrower->{'state'}, >+ zipcode => $borrower->{'zipcode'}, >+ country => $borrower->{'country'}, >+ phone => $borrower->{'phone'}, >+ email => $borrower->{'email'}, >+ branchcode => $borrower->{'branchcode'}, >+ branchname => GetBranchName( $borrower->{'branchcode'} ), >+ is_child => ( $borrower->{'category_type'} eq 'C' ), >+ activeBorrowerRelationship => >+ ( C4::Context->preference('borrowerRelationship') ne '' ), >+ RoutingSerials => C4::Context->preference('RoutingSerials'), >+); >+ >+output_html_with_http_headers $cgi, $cookie, $template->output; >diff --git a/members/account_credit_do.pl b/members/account_credit_do.pl >new file mode 100755 >index 0000000..c1979e8 >--- /dev/null >+++ b/members/account_credit_do.pl >@@ -0,0 +1,68 @@ >+#!/usr/bin/perl >+ >+# Copyright 2000-2002 Katipo Communications >+# Copyright 2010 BibLibre >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use CGI; >+ >+use C4::Auth; >+use C4::Output; >+use C4::Members; >+use C4::Items; >+use C4::Branch; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use Koha::Accounts; >+use Koha::Database; >+ >+my $cgi = new CGI; >+ >+my $borrowernumber = $cgi->param('borrowernumber'); >+my $borrower = >+ Koha::Database->new()->schema->resultset('Borrower')->find($borrowernumber); >+ >+if ( checkauth( $cgi, 0, { borrowers => 1 }, 'intranet' ) ) { >+ >+ my $barcode = $cgi->param('barcode'); >+ my $itemnumber = $cgi->param('itemnumber'); >+ my $description = $cgi->param('description'); >+ my $amount = $cgi->param('amount'); >+ my $type = $cgi->param('type'); >+ my $notes = $cgi->param('notes'); >+ >+ if ( !$itemnumber && $barcode ) { >+ $itemnumber = GetItemnumberFromBarcode($barcode); >+ } >+ >+ my $debit = AddCredit( >+ { >+ borrower => $borrower, >+ amount => $amount, >+ type => $type, >+ itemnumber => $itemnumber, >+ description => $description, >+ notes => $notes, >+ >+ } >+ ); >+ >+ print $cgi->redirect( >+ "/cgi-bin/koha/members/account.pl?borrowernumber=$borrowernumber"); >+} >diff --git a/members/account_debit.pl b/members/account_debit.pl >new file mode 100755 >index 0000000..41d78c6 >--- /dev/null >+++ b/members/account_debit.pl >@@ -0,0 +1,104 @@ >+#!/usr/bin/perl >+ >+#written 11/1/2000 by chris@katipo.oc.nz >+#script to display borrowers account details >+ >+# Copyright 2000-2002 Katipo Communications >+# Copyright 2010 BibLibre >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use strict; >+use warnings; >+ >+use CGI; >+ >+use C4::Auth; >+use C4::Output; >+use C4::Members; >+use C4::Items; >+use C4::Branch; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use C4::Koha; >+use Koha::Accounts; >+use Koha::Database; >+ >+my $input = new CGI; >+ >+my $borrowernumber = $input->param('borrowernumber'); >+ >+my $borrower = GetMember( 'borrowernumber' => $borrowernumber ); >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => "members/account_debit.tt", >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { borrowers => 1, updatecharges => 1 }, >+ debug => 1, >+ } >+); >+ >+$template->param( invoice_types_loop => GetAuthorisedValues('MANUAL_INV') ); >+ >+# Standard /members/ borrower details data >+## FIXME: This code is in every /members/ script and should be unified >+ >+if ( $borrower->{'category_type'} eq 'C' ) { >+ my ( $catcodes, $labels ) = >+ GetborCatFromCatType( 'A', 'WHERE category_type = ?' ); >+ my $cnt = scalar(@$catcodes); >+ $template->param( 'CATCODE_MULTI' => 1 ) if $cnt > 1; >+ $template->param( 'catcode' => $catcodes->[0] ) if $cnt == 1; >+} >+ >+my ( $picture, $dberror ) = GetPatronImage( $borrower->{'borrowernumber'} ); >+$template->param( picture => 1 ) if $picture; >+ >+if ( C4::Context->preference('ExtendedPatronAttributes') ) { >+ my $attributes = GetBorrowerAttributes($borrowernumber); >+ $template->param( >+ ExtendedPatronAttributes => 1, >+ extendedattributes => $attributes >+ ); >+} >+ >+$template->param( >+ borrowernumber => $borrowernumber, >+ firstname => $borrower->{'firstname'}, >+ surname => $borrower->{'surname'}, >+ cardnumber => $borrower->{'cardnumber'}, >+ categorycode => $borrower->{'categorycode'}, >+ category_type => $borrower->{'category_type'}, >+ categoryname => $borrower->{'description'}, >+ address => $borrower->{'address'}, >+ address2 => $borrower->{'address2'}, >+ city => $borrower->{'city'}, >+ state => $borrower->{'state'}, >+ zipcode => $borrower->{'zipcode'}, >+ country => $borrower->{'country'}, >+ phone => $borrower->{'phone'}, >+ email => $borrower->{'email'}, >+ branchcode => $borrower->{'branchcode'}, >+ branchname => GetBranchName( $borrower->{'branchcode'} ), >+ is_child => ( $borrower->{'category_type'} eq 'C' ), >+ activeBorrowerRelationship => >+ ( C4::Context->preference('borrowerRelationship') ne '' ), >+ RoutingSerials => C4::Context->preference('RoutingSerials'), >+); >+ >+output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/members/account_debit_do.pl b/members/account_debit_do.pl >new file mode 100755 >index 0000000..c9878fa >--- /dev/null >+++ b/members/account_debit_do.pl >@@ -0,0 +1,69 @@ >+#!/usr/bin/perl >+ >+# Copyright 2000-2002 Katipo Communications >+# Copyright 2010 BibLibre >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use CGI; >+ >+use C4::Auth; >+use C4::Output; >+use C4::Members; >+use C4::Items; >+use C4::Branch; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use Koha::Accounts; >+use Koha::Database; >+ >+my $cgi = new CGI; >+ >+my $borrowernumber = $cgi->param('borrowernumber'); >+my $borrower = >+ Koha::Database->new()->schema->resultset('Borrower')->find($borrowernumber); >+ >+if ( checkauth( $cgi, 0, { borrowers => 1 }, 'intranet' ) ) { >+ >+ # print $cgi->header; >+ my $barcode = $cgi->param('barcode'); >+ my $itemnumber = $cgi->param('itemnumber'); >+ my $description = $cgi->param('description'); >+ my $amount = $cgi->param('amount'); >+ my $type = $cgi->param('type'); >+ my $notes = $cgi->param('notes'); >+ >+ if ( !$itemnumber && $barcode ) { >+ $itemnumber = GetItemnumberFromBarcode($barcode); >+ } >+ >+ my $debit = AddDebit( >+ { >+ borrower => $borrower, >+ amount => $amount, >+ type => $type, >+ itemnumber => $itemnumber, >+ description => $description, >+ notes => $notes, >+ >+ } >+ ); >+ >+ print $cgi->redirect( >+ "/cgi-bin/koha/members/account.pl?borrowernumber=$borrowernumber"); >+} >diff --git a/members/account_payment.pl b/members/account_payment.pl >new file mode 100755 >index 0000000..32fec34 >--- /dev/null >+++ b/members/account_payment.pl >@@ -0,0 +1,123 @@ >+#!/usr/bin/perl >+ >+# Copyright 2000-2002 Katipo Communications >+# Copyright 2010 BibLibre >+# Copyright 2010,2011 PTFS-Europe Ltd >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+=head1 account_payment.pl >+ >+ written 11/1/2000 by chris@katipo.oc.nz >+ part of the koha library system, script to facilitate paying off fines >+ >+=cut >+ >+use Modern::Perl; >+ >+use CGI; >+ >+use URI::Escape; >+ >+use C4::Context; >+use C4::Auth; >+use C4::Output; >+use C4::Members; >+use C4::Accounts; >+use C4::Stats; >+use C4::Koha; >+use C4::Overdues; >+use C4::Branch; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use Koha::Database; >+ >+our $cgi = CGI->new; >+ >+our ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => 'members/account_payment.tt', >+ query => $cgi, >+ type => 'intranet', >+ authnotrequired => 0, >+ flagsrequired => { borrowers => 1, updatecharges => 1 }, >+ debug => 1, >+ } >+); >+ >+my $borrowernumber = $cgi->param('borrowernumber'); >+ >+my $borrower = GetMember( borrowernumber => $borrowernumber ); >+ >+my @debits = Koha::Database->new()->schema->resultset('AccountDebit')->search( >+ { >+ 'me.borrowernumber' => $borrowernumber, >+ amount_outstanding => { '>' => 0 } >+ } >+); >+ >+$template->param( >+ debits => \@debits, >+ borrower => $borrower, >+); >+ >+# Standard /members/ borrower details data >+## FIXME: This code is in every /members/ script and should be unified >+ >+if ( $borrower->{'category_type'} eq 'C' ) { >+ my ( $catcodes, $labels ) = >+ GetborCatFromCatType( 'A', 'WHERE category_type = ?' ); >+ my $cnt = scalar(@$catcodes); >+ $template->param( 'CATCODE_MULTI' => 1 ) if $cnt > 1; >+ $template->param( 'catcode' => $catcodes->[0] ) if $cnt == 1; >+} >+ >+my ( $picture, $dberror ) = GetPatronImage( $borrower->{'borrowernumber'} ); >+$template->param( picture => 1 ) if $picture; >+ >+if ( C4::Context->preference('ExtendedPatronAttributes') ) { >+ my $attributes = GetBorrowerAttributes($borrowernumber); >+ $template->param( >+ ExtendedPatronAttributes => 1, >+ extendedattributes => $attributes >+ ); >+} >+ >+$template->param( >+ borrowernumber => $borrowernumber, >+ firstname => $borrower->{'firstname'}, >+ surname => $borrower->{'surname'}, >+ cardnumber => $borrower->{'cardnumber'}, >+ categorycode => $borrower->{'categorycode'}, >+ category_type => $borrower->{'category_type'}, >+ categoryname => $borrower->{'description'}, >+ address => $borrower->{'address'}, >+ address2 => $borrower->{'address2'}, >+ city => $borrower->{'city'}, >+ state => $borrower->{'state'}, >+ zipcode => $borrower->{'zipcode'}, >+ country => $borrower->{'country'}, >+ phone => $borrower->{'phone'}, >+ email => $borrower->{'email'}, >+ branchcode => $borrower->{'branchcode'}, >+ branchname => GetBranchName( $borrower->{'branchcode'} ), >+ is_child => ( $borrower->{'category_type'} eq 'C' ), >+ activeBorrowerRelationship => >+ ( C4::Context->preference('borrowerRelationship') ne '' ), >+ RoutingSerials => C4::Context->preference('RoutingSerials'), >+); >+ >+output_html_with_http_headers $cgi, $cookie, $template->output; >diff --git a/members/account_payment_do.pl b/members/account_payment_do.pl >new file mode 100755 >index 0000000..cc60099 >--- /dev/null >+++ b/members/account_payment_do.pl >@@ -0,0 +1,62 @@ >+#!/usr/bin/perl >+ >+# Copyright 2000-2002 Katipo Communications >+# Copyright 2010 BibLibre >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use CGI; >+ >+use C4::Auth; >+use C4::Members; >+use C4::Items; >+use C4::Branch; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use Koha::Accounts; >+use Koha::Database; >+ >+my $cgi = new CGI; >+ >+if ( checkauth( $cgi, 0, { borrowers => 1 }, 'intranet' ) ) { >+ my $borrowernumber = $cgi->param('borrowernumber'); >+ >+ my $borrower = >+ Koha::Database->new()->schema->resultset('Borrower') >+ ->find($borrowernumber); >+ >+ my $amount_to_pay = $cgi->param('amount_to_pay'); >+ my $amount_received = $cgi->param('amount_received'); >+ my $type = $cgi->param('type'); >+ my $notes = $cgi->param('notes'); >+ my @debit_id = $cgi->param('debit_id'); >+ >+ my $debit = AddCredit( >+ { >+ borrower => $borrower, >+ amount => $amount_to_pay, >+ type => $type, >+ notes => $notes, >+ debit_id => \@debit_id, >+ >+ } >+ ); >+ >+ print $cgi->redirect( >+ "/cgi-bin/koha/members/account.pl?borrowernumber=$borrowernumber"); >+} >diff --git a/members/mancredit.pl b/members/mancredit.pl >index a2c2258..03079ae 100755 >--- a/members/mancredit.pl >+++ b/members/mancredit.pl >@@ -57,7 +57,7 @@ if ($add){ > $amount = -$amount; > my $type = $input->param('type'); > manualinvoice( $borrowernumber, $itemnum, $desc, $type, $amount, $note ); >- print $input->redirect("/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber"); >+ print $input->redirect("/cgi-bin/koha/members/account.pl?borrowernumber=$borrowernumber"); > } > } else { > my ($template, $loggedinuser, $cookie) >diff --git a/members/maninvoice.pl b/members/maninvoice.pl >index c4a9294..4a7cce5 100755 >--- a/members/maninvoice.pl >+++ b/members/maninvoice.pl >@@ -72,7 +72,7 @@ if ($add){ > $template->param( 'ERROR' => $error ); > output_html_with_http_headers $input, $cookie, $template->output; > } else { >- print $input->redirect("/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber"); >+ print $input->redirect("/cgi-bin/koha/members/account.pl?borrowernumber=$borrowernumber"); > exit; > } > } >diff --git a/members/pay.pl b/members/pay.pl >index 8a8e902..5c95c5e 100755 >--- a/members/pay.pl >+++ b/members/pay.pl >@@ -19,7 +19,7 @@ > # with Koha; if not, write to the Free Software Foundation, Inc., > # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > >-=head1 pay.pl >+=head1 account_payment.pl > > written 11/1/2000 by chris@katipo.oc.nz > part of the koha library system, script to facilitate paying off fines >@@ -197,7 +197,7 @@ sub writeoff_all { > > $borrowernumber = $input->param('borrowernumber'); > print $input->redirect( >- "/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber"); >+ "/cgi-bin/koha/members/account.pl?borrowernumber=$borrowernumber"); > return; > } > >diff --git a/members/paycollect.pl b/members/paycollect.pl >index 96ca0fb..48f1d0a 100755 >--- a/members/paycollect.pl >+++ b/members/paycollect.pl >@@ -114,7 +114,7 @@ if ( $total_paid and $total_paid ne '0.00' ) { > $user, $branch, $payment_note ); > } > print $input->redirect( >- "/cgi-bin/koha/members/pay.pl?borrowernumber=$borrowernumber"); >+ "/cgi-bin/koha/members/account_payment.pl?borrowernumber=$borrowernumber"); > } else { > if ($select) { > if ( $select =~ /^([\d,]*).*/ ) { >@@ -130,7 +130,7 @@ if ( $total_paid and $total_paid ne '0.00' ) { > # recordpayment does not return success or failure so lets redisplay the boraccount > > print $input->redirect( >-"/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber" >+"/cgi-bin/koha/members/account.pl?borrowernumber=$borrowernumber" > ); > } > } >diff --git a/members/printfeercpt.pl b/members/printfeercpt.pl >index 6a86bc3..8410944 100755 >--- a/members/printfeercpt.pl >+++ b/members/printfeercpt.pl >@@ -1,7 +1,7 @@ > #!/usr/bin/perl > > >-#writen 3rd May 2010 by kmkale@anantcorp.com adapted from boraccount.pl by chris@katipo.oc.nz >+#writen 3rd May 2010 by kmkale@anantcorp.com adapted from account.pl by chris@katipo.oc.nz > #script to print fee receipts > > >diff --git a/members/printinvoice.pl b/members/printinvoice.pl >index 10ae114..cdbaa14 100755 >--- a/members/printinvoice.pl >+++ b/members/printinvoice.pl >@@ -1,6 +1,6 @@ > #!/usr/bin/perl > >-#writen 3rd May 2010 by kmkale@anantcorp.com adapted from boraccount.pl by chris@katipo.oc.nz >+#writen 3rd May 2010 by kmkale@anantcorp.com adapted from account.pl by chris@katipo.oc.nz > #script to print fee receipts > > # Copyright Koustubha Kale >diff --git a/misc/cronjobs/create_koc_db.pl b/misc/cronjobs/create_koc_db.pl >index ccc4a5b..f49519e 100755 >--- a/misc/cronjobs/create_koc_db.pl >+++ b/misc/cronjobs/create_koc_db.pl >@@ -256,10 +256,8 @@ SELECT borrowernumber, > city, > phone, > dateofbirth, >- sum( accountlines.amountoutstanding ) as total_fines >+ account_balance as total_fines > FROM borrowers >-LEFT JOIN accountlines USING (borrowernumber) >-GROUP BY borrowernumber; > END_SQL > > my $fields_count = $sth_mysql->execute(); >@@ -278,43 +276,6 @@ END_SQL > } > $dbh_sqlite->commit(); > print "inserted $count borrowers\n" if $verbose; >- # add_fines_to_borrowers_table(); >-} >- >-=head2 add_fines_to_borrowers_table >- >-Import the fines from koha.accountlines into the sqlite db >- >-=cut >- >-sub add_fines_to_borrowers_table { >- >- print "preparing to update borrowers\n" if $verbose; >- my $sth_mysql = $dbh_mysql->prepare( >- "SELECT DISTINCT borrowernumber, SUM( amountoutstanding ) AS total_fines >- FROM accountlines >- GROUP BY borrowernumber" >- ); >- $sth_mysql->execute(); >- my $count; >- while ( my $result = $sth_mysql->fetchrow_hashref() ) { >- $count++; >- if ( $verbose ) { >- print '.' unless ( $count % 10 ); >- print "$count\n" unless ( $count % 1000 ); >- } >- >- my $borrowernumber = $result->{'borrowernumber'}; >- my $total_fines = $result->{'total_fines'}; >- >- # warn "Fines for Borrower # $borrowernumber are \$ $total_fines \n" if $verbose; >- my $sql = "UPDATE borrowers SET total_fines = ? WHERE borrowernumber = ?"; >- >- my $sth_sqlite = $dbh_sqlite->prepare($sql); >- $sth_sqlite->execute( $total_fines, $borrowernumber ); >- $sth_sqlite->finish(); >- } >- print "updated $count borrowers\n" if ( $verbose && $count ); > } > > =head2 create_issue_table >diff --git a/misc/cronjobs/fines.pl b/misc/cronjobs/fines.pl >index 02bde14..f85b898 100755 >--- a/misc/cronjobs/fines.pl >+++ b/misc/cronjobs/fines.pl >@@ -127,9 +127,13 @@ for my $overdue ( @{$overdues} ) { > if ( $mode eq 'production' && !$is_holiday{$branchcode} ) { > if ( $amount > 0 ) { > UpdateFine( >- $overdue->{itemnumber}, >- $overdue->{borrowernumber}, >- $amount, $type, output_pref($datedue) >+ { >+ itemnumber => $overdue->{itemnumber}, >+ borrowernumber => $overdue->{borrowernumber}, >+ amount => $amount, >+ due => output_pref($datedue), >+ issue_id => $overdue->{issue_id} >+ } > ); > } > } >diff --git a/misc/release_notes/release_notes_3_10_0.txt b/misc/release_notes/release_notes_3_10_0.txt >index a1ebdef..2f36dd2 100644 >--- a/misc/release_notes/release_notes_3_10_0.txt >+++ b/misc/release_notes/release_notes_3_10_0.txt >@@ -1762,7 +1762,7 @@ Staff Client > 8996 normal In result page items with negative notforloan are available > 9017 normal Quote of the day: Table footer not translated > 5312 minor XHTML correction in authority summary >- 8009 minor Item descriptive data not populated on pay.pl >+ 8009 minor Item descriptive data not populated on account_payment.pl > 8593 minor Add unique IDs to pending approval markup on staff client home page > 8646 minor Certain search terms cause browser "script taking too long" error > 8793 minor Fix materialTypeCode/typeOf008 icons for NORMARC XSLT >diff --git a/misc/release_notes/release_notes_3_12_0.txt b/misc/release_notes/release_notes_3_12_0.txt >index 68d19e5..f8be9b8 100644 >--- a/misc/release_notes/release_notes_3_12_0.txt >+++ b/misc/release_notes/release_notes_3_12_0.txt >@@ -579,7 +579,7 @@ Architecture, internals, and plumbing > 8429 minor Unnecessary use of Exporter in SIP/ILS objects > 9292 minor Remove dead code related to 'publictype' > 9401 minor Javascript used for tags handling wants access to CGISESSID cookie >- 9582 minor Unused code in members/pay.pl >+ 9582 minor Unused code in members/account_payment.pl > 10054 minor When SingleBranchMode is enabled, allow superlibrarians to set logged in library > 10143 minor Fix FSF address in license headers > 9609 trivial Rebuild zebra reports double numbers for exported records with -z option >diff --git a/t/db_dependent/Accounts.t b/t/db_dependent/Accounts.t >index 1c2dd5a..7957cbe 100644 >--- a/t/db_dependent/Accounts.t >+++ b/t/db_dependent/Accounts.t >@@ -1,16 +1,199 @@ > #!/usr/bin/perl > # >-# This Koha test module is a stub! >+# This Koha test module is a stub! > # Add more tests here!!! > > use strict; > use warnings; > >-use Test::More tests => 1; >+use Test::More tests => 19; >+ >+use C4::Context; > > BEGIN { >- use_ok('C4::Accounts'); >+ use_ok('Koha::Database'); >+ use_ok('Koha::Accounts'); >+ use_ok('Koha::Accounts::DebitTypes'); >+ use_ok('Koha::Accounts::CreditTypes'); > } > >+## Intial Setup ## >+my $borrower = Koha::Database->new()->schema->resultset('Borrower')->create( >+ { >+ surname => 'Test', >+ categorycode => 'S', >+ branchcode => 'MPL', >+ account_balance => 0, >+ } >+); >+ >+my $biblio = >+ Koha::Database->new()->schema->resultset('Biblio') >+ ->create( { title => "Test Record" } ); >+my $biblioitem = >+ Koha::Database->new()->schema->resultset('Biblioitem') >+ ->create( { biblionumber => $biblio->biblionumber() } ); >+my $item = Koha::Database->new()->schema->resultset('Item')->create( >+ { >+ biblionumber => $biblio->biblionumber(), >+ biblioitemnumber => $biblioitem->biblioitemnumber(), >+ replacementprice => 25.00, >+ barcode => q{TEST_ITEM_BARCODE} >+ } >+); >+ >+my $issue = Koha::Database->new()->schema->resultset('Issue')->create( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ itemnumber => $item->itemnumber(), >+ } >+); >+## END initial setup >+ >+ok( Koha::Accounts::DebitTypes::Fine eq 'FINE', 'Test DebitTypes::Fine' ); >+ok( Koha::Accounts::DebitTypes::Lost eq 'LOST', 'Test DebitTypes::Lost' ); >+ok( >+ Koha::Accounts::DebitTypes::IsValid('FINE'), >+ 'Test DebitTypes::IsValid with valid debit type' >+); >+ok( >+ !Koha::Accounts::DebitTypes::IsValid('Not A Valid Fee Type'), >+ 'Test DebitTypes::IsValid with an invalid debit type' >+); >+my $authorised_value = >+ Koha::Database->new()->schema->resultset('AuthorisedValue')->create( >+ { >+ category => 'MANUAL_INV', >+ authorised_value => 'TEST', >+ lib => 'Test', >+ } >+ ); >+ok( Koha::Accounts::DebitTypes::IsValid('TEST'), >+ 'Test DebitTypes::IsValid with valid authorised value debit type' ); >+$authorised_value->delete(); >+ >+my $debit = AddDebit( >+ { >+ borrower => $borrower, >+ amount => 5.00, >+ type => Koha::Accounts::DebitTypes::Fine, >+ branchcode => 'MPL', >+ } >+); >+ok( $debit, "AddDebit returned a valid debit id " . $debit->id() ); >+ >+ok( >+ $borrower->account_balance() == 5.00, >+ "Borrower's account balance updated correctly" >+); >+ >+my $debit2 = AddDebit( >+ { >+ borrower => $borrower, >+ amount => 7.00, >+ type => Koha::Accounts::DebitTypes::Fine, >+ branchcode => 'MPL', >+ } >+); >+ >+my $credit = AddCredit( >+ { >+ borrower => $borrower, >+ type => Koha::Accounts::CreditTypes::Payment, >+ amount => 9.00, >+ branchcode => 'MPL', >+ } >+); >+ >+RecalculateAccountBalance( { borrower => $borrower } ); >+ok( >+ sprintf( "%.2f", $borrower->account_balance() ) eq "3.00", >+ "RecalculateAccountBalance updated balance correctly." >+); >+ >+Koha::Database->new()->schema->resultset('AccountCredit')->create( >+ { >+ borrowernumber => $borrower->borrowernumber(), >+ type => Koha::Accounts::CreditTypes::Payment, >+ amount_paid => 3.00, >+ amount_remaining => 3.00, >+ } >+); >+NormalizeBalances( { borrower => $borrower } ); >+ok( >+ $borrower->account_balance() == 0.00, >+ "NormalizeBalances updated balance correctly." >+); >+ >+# Adding advance credit with no balance due >+$credit = AddCredit( >+ { >+ borrower => $borrower, >+ type => Koha::Accounts::CreditTypes::Payment, >+ amount => 9.00, >+ branchcode => 'MPL', >+ } >+); >+ok( >+ $borrower->account_balance() == -9, >+'Adding a $9 credit for borrower with 0 balance results in a -9 dollar account balance' >+); >+ >+my $debit3 = AddDebit( >+ { >+ borrower => $borrower, >+ amount => 5.00, >+ type => Koha::Accounts::DebitTypes::Fine, >+ branchcode => 'MPL', >+ } >+); >+ok( >+ $borrower->account_balance() == -4, >+'Adding a $5 debit when the balance is negative results in the debit being automatically paid, resulting in a balance of -4' >+); >+ >+my $debit4 = AddDebit( >+ { >+ borrower => $borrower, >+ amount => 6.00, >+ type => Koha::Accounts::DebitTypes::Fine, >+ branchcode => 'MPL', >+ } >+); >+ok( >+ $borrower->account_balance() == 2, >+'Adding another debit ( 6.00 ) more than the negative account balance results in a partial credit and a balance due of 2.00' >+); >+$credit = AddCredit( >+ { >+ borrower => $borrower, >+ type => Koha::Accounts::CreditTypes::WriteOff, >+ amount => 2.00, >+ branchcode => 'MPL', >+ debit_id => $debit4->debit_id(), >+ } >+); >+ok( $borrower->account_balance() == 0, >+ 'WriteOff of remaining 2.00 balance succeeds' ); >+ >+my $debit5 = DebitLostItem( >+ { >+ borrower => $borrower, >+ issue => $issue, >+ } >+); >+ok( $borrower->account_balance() == 25, >+ 'DebitLostItem adds debit for replacement price of item' ); > >+my $lost_credit = >+ CreditLostItem( { borrower => $borrower, debit => $debit5 } ); >+ok( >+ $borrower->account_balance() == 0, >+ 'CreditLostItem adds credit for same about as the debit for the lost tiem' >+); > >+## Post test cleanup ## >+$issue->delete(); >+$item->delete(); >+$biblio->delete(); >+$borrower->delete(); >diff --git a/t/db_dependent/Circulation.t b/t/db_dependent/Circulation.t >index aa2a969..f60145b 100755 >--- a/t/db_dependent/Circulation.t >+++ b/t/db_dependent/Circulation.t >@@ -302,8 +302,15 @@ C4::Context->dbh->do("DELETE FROM accountlines"); > C4::Context->set_preference('WhenLostForgiveFine','1'); > C4::Context->set_preference('WhenLostChargeReplacementFee','1'); > >- C4::Overdues::UpdateFine( $itemnumber, $renewing_borrower->{borrowernumber}, >- 15.00, q{}, Koha::DateUtils::output_pref($datedue) ); >+ C4::Overdues::UpdateFine( >+ { >+ itemnumber => $itemnumber, >+ borrowernumber => $renewing_borrower->{borrowernumber}, >+ amount => 15.00, >+ due => Koha::DateUtils::output_pref($datedue), >+ issue_id => GetItemIssue($itemnumber)->{issue_id} >+ } >+ ); > > LostItem( $itemnumber, 1 ); > >@@ -319,8 +326,15 @@ C4::Context->dbh->do("DELETE FROM accountlines"); > C4::Context->set_preference('WhenLostForgiveFine','0'); > C4::Context->set_preference('WhenLostChargeReplacementFee','0'); > >- C4::Overdues::UpdateFine( $itemnumber2, $renewing_borrower->{borrowernumber}, >- 15.00, q{}, Koha::DateUtils::output_pref($datedue) ); >+ C4::Overdues::UpdateFine( >+ { >+ itemnumber => $itemnumber2, >+ borrowernumber => $renewing_borrower->{borrowernumber}, >+ amount => 15.00, >+ due => Koha::DateUtils::output_pref($datedue), >+ issue_id => GetItemIssue($itemnumber2)->{issue_id}, >+ } >+ ); > > LostItem( $itemnumber2, 1 ); > >-- >1.7.2.5
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 6427
:
21922
|
22704
|
22705
|
22708
|
22709
|
22710
|
22741
|
22870
|
22871
|
22872
|
22873
|
22874
|
22875
|
22876
|
22881
|
22889
|
22940
|
22948
|
22949
|
22995
|
23000
|
23137
|
23158
|
23161
|
23171
|
23186
|
23269
|
23275
|
23276
|
23391
|
23392
|
23400
|
23401
|
23402
|
23403
|
23404
|
23405
|
23406
|
23407
|
23408
|
23409
|
23410
|
23411
|
23412
|
23413
|
23420
|
23421
|
23422
|
23423
|
23424
|
23425
|
23426
|
23427
|
23428
|
23429
|
23430
|
23431
|
23432
|
23433
|
23440
|
23441
|
23442
|
23443
|
23444
|
23445
|
23446
|
23447
|
23448
|
23449
|
23450
|
23451
|
23452
|
23453
|
23454
|
23458
|
23459
|
23460
|
23461
|
23462
|
23463
|
23464
|
23465
|
23466
|
23467
|
23468
|
23469
|
23470
|
23471
|
23603
|
23643
|
23644
|
23645
|
23646
|
23647
|
23648
|
23649
|
23650
|
23651
|
23652
|
23653
|
23654
|
23655
|
23656
|
23657
|
23937
|
23938
|
23939
|
23940
|
23941
|
23942
|
23943
|
23944
|
23945
|
23946
|
23947
|
23948
|
23949
|
23950
|
23951
|
24612
|
24613
|
24614
|
24615
|
24616
|
24617
|
24618
|
24619
|
24620
|
24621
|
24622
|
24623
|
24624
|
24625
|
24626
|
24627
|
24628
|
24757
|
24758
|
24759
|
24760
|
24761
|
24762
|
24763
|
24764
|
24765
|
24766
|
24767
|
24768
|
24769
|
24770
|
24771
|
24772
|
24777
|
24792
|
24793
|
24794
|
24795
|
24796
|
24797
|
24798
|
24799
|
24800
|
24801
|
24802
|
24803
|
24804
|
24805
|
24806
|
24807
|
24808
|
24809
|
24810
|
24811
|
24812
|
24813
|
24814
|
24815
|
24816
|
24817
|
24818
|
24819
|
24820
|
24821
|
24822
|
24823
|
24824
|
24825
|
24826
|
24827
|
24828
|
24829
|
24830
|
24831
|
24832
|
24833
|
24834
|
24835
|
24836
|
24837
|
24838
|
24839
|
24840
|
24841
|
24842
|
24843
|
24844
|
25777
|
25778
|
25779
|
25780
|
25781
|
25782
|
25783
|
25784
|
25785
|
25786
|
25787
|
25788
|
25789
|
25790
|
25791
|
25792
|
25793
|
25794
|
25795
|
25796
|
25797
|
25798
|
25799
|
25800
|
25801
|
25802
|
25803
|
25804
|
25805
|
25806
|
25807
|
25808
|
25809
|
25810
|
25811
|
25812
|
25813
|
25814
|
25815
|
25816
|
25930
|
25932
|
25933
|
25934
|
26033
|
26034
|
26035
|
26036
|
26107
|
27167
|
27168
|
27169
|
27170
|
27171
|
27172
|
27173
|
27174
|
27175
|
27176
|
27177
|
27178
|
27179
|
27180
|
27181
|
27182
|
27183
|
27184
|
27185
|
27186
|
27187
|
27189
|
27190
|
27197
|
28067
|
28068
|
28069
|
28070
|
28071
|
28072
|
28073
|
28074
|
28075
|
28076
|
28077
|
28078
|
28079
|
28080
|
28081
|
28082
|
28083
|
28084
|
28085
|
28086
|
28087
|
28088
|
28089
|
28090
|
28091
|
28527
|
28528
|
28529
|
28530
|
28531
|
28532
|
28533
|
28534
|
28535
|
28536
|
28537
|
28538
|
28539
|
28540
|
28541
|
28542
|
28543
|
28544
|
28545
|
28546
|
28547
|
28548
|
28549
|
28550
|
28551
|
28552
|
28553
|
28555
|
28556
|
28561
|
28563
|
28564
|
28795
|
28796
|
28797
|
28798
|
28799
|
28800
|
28801
|
28802
|
28803
|
28804
|
28805
|
28806
|
28807
|
28808
|
28809
|
28810
|
28811
|
28812
|
28813
|
28814
|
28815
|
28816
|
28817
|
28818
|
28819
|
28820
|
28821
|
28822
|
28887
|
28888
|
28889
|
28890
|
28909
|
29176
|
29230
|
29231
|
29232
|
29233
|
29234
|
29235
|
29236
|
29237
|
29238
|
29239
|
29240
|
29241
|
29242
|
29243
|
29244
|
29245
|
29246
|
29247
|
29248
|
29249
|
29250
|
29251
|
29252
|
29253
|
29254
|
29255
|
29256
|
29257
|
29258
|
29259
|
29260
|
29261
|
29262
|
29263
|
29264
|
29265
|
29706
|
29707
|
29708
|
29709
|
29710
|
29711
|
29712
|
29713
|
29714
|
29715
|
29716
|
29717
|
29719
|
29720
|
29721
|
29722
|
29723
|
29724
|
29725
|
29726
|
29727
|
29728
|
29729
|
29730
|
30271
|
30272
|
30273
|
30274
|
30275
|
30276
|
30277
|
30278
|
30279
|
30280
|
30281
|
30282
|
30320
|
30321
|
30322
|
30323
|
30324
|
30325
|
30326
|
30327
|
30328
|
30329
|
30330
|
30331
|
30416
|
30417
|
30418
|
30419
|
30420
|
30421
|
30422
|
30423
|
30424
|
30425
|
30426
|
30427
|
31477
|
31478
|
31479
|
31480
|
31481
|
31482
|
31483
|
31484
|
31485
|
31486
|
31487
|
31488
|
31754
|
31755
|
31756
|
31757
|
31758
|
31759
|
31760
|
31761
|
31762
|
31763
|
31764
|
31765
|
31766
|
31767
|
31768
|
31769
|
31770
|
31771
|
31772
|
31773
|
31774
|
31775
|
31776
|
31777
|
32478
|
32479
|
32480
|
32481
|
32482
|
32483
|
32484
|
32485
|
32486
|
32487
|
32488
|
32489
|
32591
|
32592
|
32593
|
32594
|
32595
|
32596
|
32597
|
32598
|
32599
|
32600
|
32601
|
32602
|
32827
|
32828
|
32829
|
32830
|
32831
|
32832
|
32833
|
32834
|
32835
|
32836
|
32837
|
32838
|
33251
|
33252
|
33253
|
33254
|
33255
|
33256
|
33257
|
33258
|
33259
|
33260
|
33261
|
33262
|
34096
|
34097
|
34098
|
34099
|
34100
|
34101
|
34102
|
34103
|
34104
|
34105
|
34106
|
34107
|
34204
|
34205
|
34206
|
34207
|
34208
|
34209
|
34210
|
34211
|
34212
|
34213
|
34214
|
34215
|
35196
|
35197
|
35198
|
35199
|
35200
|
35201
|
35202
|
35203
|
35204
|
35205
|
35206
|
35207
|
35208
|
35302
|
36324
|
36326
|
36327
|
36328
|
36329
|
36330
|
36331
|
36332
|
36333
|
36334
|
36335
|
36337
|
36338
|
36340
|
36380
|
36391
|
36393
|
37127
|
37128
|
37129
|
37130
|
37131
|
37133
|
37134
|
37135
|
37136
|
37137
|
37138
|
37139
|
37140
|
37141
|
37142
|
37143
|
37147
|
37148
|
37149
|
37150
|
37151
|
37152
|
37153
|
37154
|
37155
|
37156
|
37157
|
37158
|
37159
|
37160
|
37161
|
37162
|
37229
|
37230
|
37231
|
37232
|
37233
|
37234
|
37235
|
37236
|
37237
|
37238
|
37239
|
37240
|
37241
|
37242
|
37243
|
37244
|
38247
|
38248
|
38249
|
38250
|
38251
|
38252
|
38253
|
38254
|
38255
|
38256
|
38257
|
38258
|
38259
|
38260
|
38261
|
38262
|
39063
|
39064
|
39065
|
39066
|
39067
|
39069
|
39070
|
39071
|
39072
|
39073
|
39074
|
39075
|
39076
|
39077
|
39078
|
39079
|
39671
|
39672
|
39673
|
39674
|
39675
|
39676
|
39677
|
39678
|
39679
|
39680
|
39681
|
39682
|
39683
|
39684
|
39685
|
39686