One comment:  $type should be user-definable, not hardcoded values.  More extensible that way, since libraries are always good at coming up with new ways of doing things.  This would allow for statistical reports on Accounts to a library-specific level of granularity; I just know if we do it hard-coded, someone is going to complain that they can't differentiate fine types at all get lumped into 'M'.

Otherwise, looks good.  If I have any more comments after re-reading, I'll post.  Thanks, Robin!


-Ian

2011/3/31 Robin Sheat <robin@catalyst.net.nz>
I'm in the process of rewriting the accounts system to improve its
flexibility, and getting rid of some cruft. Also to make it easier to
work with from a developer point of view. The ability to do things like
partial payments (which I know have been implemented about three other
times, but as more putty on the existing system) and other useful things
is what's aiming to come out of this, as well as having a nicely
maintainable subsystem.

I'm attaching the perldoc of what I have so far, I'm interested in
seeing if anyone has any ideas on problems that this design might have
that I should work around before it gets too much further along. I also
note that the accounts system seems to handle the returning of lost
items, which strikes me as the wrong place to put it, so I'll try to
pull that out to somewhere more sensible, or at the least isolate it.

Mostly I'm just making sure that it'll be able to reproduce all the
existing functionality, which seems to have accreted in that module, but
if you have any ideas for other things that can be fitted in naturally
as part of this, they may be considered too.

$ perldoc -t -T Accounts.pm
NAME
   C4::Accounts - Functions for dealing with borrower accounts in Koha

SYNOPSIS
   use C4::Accounts;

DESCRIPTION
   The functions here handle the account for a borrower. Adding fines and
   other charges, paying them off, looking up the information, and keeping
   it all in sync.

   The account system works by adding every transaction (a fine added, a
   payment made, a rental charge, etc.) to the "accountlines" table. Once
   added, this is never modified except to change certain flags (dispute
   and zeroed in particular.)

   To indicate charges being paid off, a record is added to the
   "accountoffsets" table that links a payment transaction to a charge
   transaction, along with the amount that payment contributes to the
   charge. If a payment is completely consumed, or a charge completely paid
   off, the 'zeroed' flag on that transaction is set. This is purely to
   save time when looking for outstanding charges or payments.

   Additionally to this, an "accounttotals" table is maintained that tracks
   the total outstanding. This is the difference between the payments put
   in and the charges added. It is used simply to get a quick lookup of how
   much a borrower owes or is in credit.

   This structure is intended to allow partial payments in particular, but
   also allows flexibility that will make other things possible, such as
   tracking what a particular payment is for and providing a clear audit
   trail of what has happened.

FUNCTIONS
 charge_borrower
     $trans_num = charge_borrower($borrowernumber, $itemnumber, $amount, $type, $description, $user)

   This is the fundamental function for charging a borrower for something.
   It will add a record to the accountlines table. If the person is in
   credit, it may also apply that credit to this charge, if allowed to by
   the rules for this charge type.

   If this relates to an item, say a rental or fine, that should go into
   $itemnumber.

   $type is a text flag that indicates what this charge is for:

   N: New card
   F: Fine
   A: Account management
   L: Lost item
   R: Rental
   M: Sundry (anything else)

   $user should be the user ID that applied the charge, to aid in auditing.
   It may also be a text string if an ID doesn't make sense (e.g. cron
   jobs.)

   In general, this function will be called by something else that handles
   setting up the specifics but may be called directly if that's all you
   need.

  RETURNS
   The transaction number of the newly created transaction.

 add_payment
      ($trans_num, $credit) = add_payment($borrowernumber, $amount, $type, $description, $user, @transactions)

   This adds a payment for a borrower, indicating that they've given you
   money.

   $type is a text flag that indicates the nature of the payment. Currently
   this is only 'C' for 'credit'.

   $description is a human-readable description of the payment.

   $user is the borrower ID of the person putting through this payment, to
   aid in auditing. It may also be a text string if an ID doesn't make
   sense (e.g. cron jobs.)

   @transactions is a list of transactions that this payment will be used
   to pay off. It will pay off as many of these as it can. If there is
   money in the payment left over, then it will be credit for the user. It
   will not automatically pay off other charges.

   Often this will be called by another accounts function that handles
   adjusting other values in the system, but it may be called directly for
   simple cases.

  NOTES
   The $amount value is the amount that is being paid off. It should be a
   positive value, but will be converted to a negative value when written
   to the database.

  RETURNS
   If called in a scalar context, this returns the transaction number for
   the added payment. If called in a list context it returns that, and the
   amount of credit left over from this payment.

 should_use_credit_for
     should_use_credit_for($type)

   If the type of the charge is one that the system preferences say should
   be paid off using credit, then we say so by returning true.

 pay_from_credit
     $credit_left = pay_from_credit($transaction_number, $borrowernumber)

   This takes a particular transaction (that should be a charge), finds all
   the unused payments in the system for the borrower, and pays off this
   transaction using them, or as close to that as possible.

   Note: at the moment, $borrowernumber should be the same as the borrower
   that accrued the charge.

  RETURNS
   The amount of credit left for this borrower.

 pay
     $money_left = pay($charge_number, $payment_number)

   This links a charge to a payment, paying off some or all of the charge.
   It does this by writing an entry to the accountoffsets table that links
   them together.

   This doesn't support using just part of the payment, that's hopefully
   not going to happen. The exception to this is if the payment was part
   used earlier, or if the payment is larger than the charge. So really I'm
   just saying that it doesn't let you specify the amount.

   $charge_number and $payment_number may be scalars or arrayrefs (or a
   mix.) If they are arrayrefs, this will use each payment to pay of as
   much of the charges as it can, basically what you'd expect.

   Every charge that is paid off, or payment that is used up, will get its
   "zeroed" flag set to true.

   This will update the totals table also.

  RETURNS
   The amount of the payment(s) left over (from the provided list of
   payments only), or zero if it was all used up.

 get_transaction_info
     ($outstanding, $borrowernumber, $amount, $transactionnumber) = get_transaction_info($transaction_number)

   This gets information about a transaction, and returns either a scalar
   with just the amount outstanding on it, or a list containing: amount
   outstanding, borrowernumber, amount, transactionnumber.

 get_transactions
     @transactions = get_transactions(%filter_rules)

   This gets a list of transactions that match the supplied filter rules.
   The rules implmented are:

   "borrowernumber": restrict to a particular borrower number
   "zeroed": 0/1 - restrict to a particular zeroed status
   "paymentonly": if 1, this will restrict to entries that are only payment
   types.

  RETURNS
   A list of hashes that contain the database fields from the accountlines
   table.

 update_users_balance
     update_users_balance($borrowernumber, $adjustment)

   This updates a user's balance in the 'totals' table.

   $borrowernumber is the number of the borrower, $adjustment is the amount
   to change the total by. Keep in mind that we are tracking debt, so if
   they incur a fine, then it should be adjusted by a positive amount, and
   if they make a payment it should be negative.

   This is internal and not exported.


--
Robin Sheat
Catalyst IT Ltd.
✆ +64 4 803 2204
GPG: 5957 6D23 8B16 EFAB FEF8  7175 14D3 6485 A99C EB6D

_______________________________________________
Koha-devel mailing list
Koha-devel@lists.koha-community.org
http://lists.koha-community.org/cgi-bin/mailman/listinfo/koha-devel
website : http://www.koha-community.org/
git : http://git.koha-community.org/
bugs : http://bugs.koha-community.org/



--
Ian Walls
Lead Development Specialist
ByWater Solutions
Phone # (888) 900-8944
http://bywatersolutions.com
ian.walls@bywatersolutions.com
Twitter: @sekjal