Index: main/waeup.uniben/branches/uli-payments/CHANGES.txt
===================================================================
--- main/waeup.uniben/branches/uli-payments/CHANGES.txt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/CHANGES.txt	(revision 8249)
@@ -0,0 +1,47 @@
+Changes
+*******
+
+0.2 (unreleased)
+================
+
+Feature changes
+---------------
+
+* Started switch to groktoolkit (grok 1.1) based
+  application. `waeup.kofa` is not compatible with grok 1.0 anymore.
+
+* Added first rudimentary support for application plugins. Plugins are
+  looked up by the main app on creation time and created afterwards.
+
+* Added first rudimentary support for RSS2.0 feeds.
+
+* Generated filenames now have a filename extension that indicates
+  mode of processing. So fred.csv becomes fred.create.pending.csv when
+  being batch processed and something fails.
+
+* Coverage reports are now generated in ``coverage-report`` subdir of
+  build-directory.
+
+Bug fixes
+---------
+
+* Removed all references to stuff in university submodule into the
+  module itself or replaced it with proper code. This way the
+  university submodule could be factored out of the waeup.kofa
+  package. Fixed bug #23.
+
+* Fixed default obj updater in batchprocessing. Fixed bug #17.
+
+* Fixed handling of pending file names, fixed bug #16.
+
+* Removed quick importer and all related components.
+
+* Removed TestData folder. It was too heavy and test data can be
+  created on-the-fly.
+
+
+0.1 (2010-01-31)
+================
+
+Initial version. (Incomplete) rewrite from the former CPS-based
+application.
Index: main/waeup.uniben/branches/uli-payments/LICENSE
===================================================================
--- main/waeup.uniben/branches/uli-payments/LICENSE	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/LICENSE	(revision 8249)
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program 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 3 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
Index: main/waeup.uniben/branches/uli-payments/README-zeo.txt
===================================================================
--- main/waeup.uniben/branches/uli-payments/README-zeo.txt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/README-zeo.txt	(revision 8249)
@@ -0,0 +1,156 @@
+Deploying waeup.uniben as ZEO-install
+*************************************
+
+Each ZEO install consists of at least one ZEO server and normally two
+or more ZEO clients. While the ZEO server is meant to manage the ZODB
+database for clients, the clients connect to the outside world, listen
+for request and do the real dataprocessing.
+
+We prepared a `buildout` configuration that sets up one server
+configuration and two client configs. This configuration is in
+``buildout-zeo.cfg``.
+
+Generating the ZEO setup
+========================
+
+To install waeup.uniben ZEO-based you can run `buildout` with the given
+(or your own) configuration file like this::
+
+  $ ./bin/buildout -c buildout-zeo.cfg
+
+This should generate all scripts necessary to run servers, clients,
+etc.
+
+Starting ZEO servers and clients
+================================
+
+First start the server::
+
+  $ ./bin/zeo_server start
+
+Clients can be started by doing::
+
+  $ ./bin/zeo_client1 start
+  $ ./bin/zeo_client2 start
+
+This will start both clients in daemon mode.
+
+Instead of ``start`` you can, as usually, start an instance in
+foreground (``fg``), etc. You know the drill.
+
+Manually starting ZEO clients
+-----------------------------
+
+This is normally not neccessary.
+
+``zeo_clientN`` scripts are basically wrappers around calls to
+``bin/paster``. You can bypass this wrapper and start a client
+'manually' like this::
+
+  $ ./bin/paster serve --pid-file var/zeo1.pid --daemon \
+        pars/etc/zeo1.ini
+
+It is important to give a pid-file as paster otherwise can not start
+different clients (they would all refer to the same pid file
+`paster.pid` and refuse to start after the first client was started).
+
+
+Setup (paramters, ports, etc.)
+==============================
+
+By default the server will listen on port 8100 for requests from
+localhost (not: from the outside world).
+
+You can change ZEO server settings in the ``[zeo_server]`` section
+of ``buildout-zeo.conf``. Run `buildout` afterwards.
+
+The clients will listen on port 8081 and 8082. You can change settings
+in ``etc/zeo1.ini.in`` and ``etc/zeo2.ini.in`` respectively. Run
+buildout after any change.
+
+If you want to change the paster wrapper for any zeo client, you can
+edit ``etc/zeo1.conf`` and/or ``etc/zeo2.conf``. Run buildout
+afterwards.
+
+Creating new clients
+====================
+
+You want more clients to be created by buildout? Easy. Three steps are
+neccessary.
+
+1. Create config files in etc/
+------------------------------
+
+Each client needs two configuration files:
+
+  - ``etc/zeoN.conf``
+       configuring the paster wrapper
+
+  - ``etc/zeoN.ini``
+       configuring the runtime config, ports, etc.
+
+Just copy over these files from the already existing zeo1/zeo2 files
+and replace ``zeo1`` or ``zeo2`` with your new name.
+
+2. Update buildout-zeo.cfg
+--------------------------
+
+Here, inside ``buildourt-zeo.cfg`` also three steps are needed.
+
+* 2.1. Create new .ini and .conf entries
+
+  The .conf and .ini files in etc/ are only templates that have to be
+  generated in their really used final location. In buildout-zeo.cfg
+  you can care for this by creating a new ``[zeoN_ini]`` and
+  ``[zeoN_conf]`` option (replacing ``N`` with a number, of course).
+
+  Just copy over existing entries and replace the mentions of ``zeo1``
+  or ``zeo2`` by your ``zeoN``.
+
+* 2.2. Create a new ``zeo_clientN`` entry
+
+  Then you have to create an entry that will generate the
+  ``zeo_clientN`` script. Again, just copy over an existing
+  ``[zeo_client1]`` entry and replace ``1`` withg your client number.
+
+* 2.3. Register the new sections in ``[buildout]`` section
+
+  When done with the above: add the new section in ``[buildout]``::
+
+    [buildout]
+      ...
+      <old entries...>
+      ...
+      zope_conf_zeo_5
+      zeo5_ini
+      zeo_client5
+
+  depending on how you named your new sections.
+
+3. Rerun ``buildout``
+---------------------
+
+When adding or removing client/server instances, make sure to stop all
+running servers/clients before rerunning buildout.
+
+To activate the new setup, rerun buildout::
+
+  $ bin/buildout -c buildout-zeo.cfg
+
+This should generate any new clients and remove older ones or just
+update configuration files.
+
+
+Considerations
+==============
+
+There are some things in the current buildout-zeo.cfg we might do not
+want. It extends the regular ``buildout.cfg`` so that we do not have
+to repeat most sections but the ``parts`` in ``[buildout]`` have to be
+listed.
+
+We need, however, not everything with a ZEO-deploy that is listed in a
+default buildout. We might do not need docs, no profiling, etc. Also a
+regular non-ZEO kofactl might not make to much sense. Therefore all
+this might be subject to changes.
+
Index: main/waeup.uniben/branches/uli-payments/README.txt
===================================================================
--- main/waeup.uniben/branches/uli-payments/README.txt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/README.txt	(revision 8249)
@@ -0,0 +1,10 @@
+What is `waeup.kofa`?
+*********************
+
+The WAeUP Student Information and Registration Portal. `waeup.kofa` is
+a web-based management tool for managing universities and schools.
+
+The package was created as an effort of the WAeUP group. See
+http://www.waeup.org to learn more about WAeUP.
+
+Installation instructions can be found in the User Documentation (docs folder in the file system).
Index: main/waeup.uniben/branches/uli-payments/buildout-windows.cfg
===================================================================
--- main/waeup.uniben/branches/uli-payments/buildout-windows.cfg	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/buildout-windows.cfg	(revision 8249)
@@ -0,0 +1,114 @@
+[buildout]
+develop = .
+parts =
+    eggbasket
+    app
+    mkdirs
+    zope_conf
+    site_zcml
+    zdaemon_conf
+    deploy_ini
+    debug_ini
+# For backward compatibility, telling buildout not to throw away
+# the data and log subdirectories from the parts directory.
+    data
+    log
+# newest = false
+
+#extends = versions.cfg
+extends= http://grok.zope.org/releaseinfo/grok-1.1.cfg
+# eggs will be installed in the default buildout location
+# (see .buildout/default.cfg in your home directory)
+# unless you specify an eggs-directory option here.
+
+versions = versions
+
+[versions]
+collective.recipe.sphinxbuilder = 0.7.0
+hurry.workflow = 0.11
+# Pinned to circumvent breakage in 0.4.x
+hurry.zoperesource = 0.6
+# Pinned to prevent buildout svn-error.
+lovely.recipe = 1.0.0
+megrok.layout = 1.0.2
+reportlab = 2.5
+transaction = 1.1.0
+z3c.testsetup = 0.6.1
+zc.buildout = 1.5.0
+zc.recipe.egg = 1.3.0
+zc.recipe.testrunner = 1.4.0
+zope.app.testing = 3.8.1
+# for support of @provider directive
+zope.interface = 3.6.3
+# for support of contextual default values
+zope.schema = 3.8.0
+zope.testing = 3.10.2
+zope.xmlpickle = 3.4.0
+# Require latest version...
+Sphinx =
+ZODB3 = 3.10.3
+
+[app]
+# This creates only the paster script in bin/.
+recipe = zc.recipe.egg
+eggs = waeup.uniben
+       z3c.evalexception>=2.0
+       Paste
+       PasteScript
+       PasteDeploy
+interpreter = python-console
+scripts = paster=paster
+
+[mkdirs]
+recipe = z3c.recipe.mkdir
+paths =
+    ${zope_conf:filestorage}
+    ${zope_conf:logfiles}
+    ${zope_conf:blobstorage}
+    ${buildout:directory}/var/datacenter/media
+
+[zope_conf]
+recipe = collective.recipe.template
+input = etc/zope.conf.in
+output = ${buildout:parts-directory}/etc/zope.conf
+filestorage = ${buildout:directory}/var/filestorage
+blobstorage = ${buildout:directory}/var/blobstorage
+logfiles = ${buildout:directory}/var/log
+extra =
+# extra = <grokwarnings>True</grokwarnings>
+# 'extra' is copied verbatim. Use it for product config sections and so.
+
+# The [data] and [log] parts are still in here to instruct buildout to not
+# unintentionally throw away the parts/data and parts/log subdirectories
+# that contain the Data.fs and the log files. These files should be
+# copied to the new locations. See the upgrade notes for more information.
+[data]
+recipe = zc.recipe.filestorage
+
+[log]
+recipe = zc.recipe.filestorage
+
+[site_zcml]
+recipe = collective.recipe.template
+input = etc/site.zcml.in
+output = ${buildout:parts-directory}/etc/site.zcml
+
+[zdaemon_conf]
+recipe = collective.recipe.template
+input = etc/zdaemon.conf.in
+output = ${buildout:parts-directory}/etc/zdaemon.conf
+
+[deploy_ini]
+recipe = collective.recipe.template
+input = etc/deploy.ini.in
+output = ${buildout:parts-directory}/etc/deploy.ini
+
+[debug_ini]
+recipe = collective.recipe.template
+input = etc/debug.ini.in
+output = ${buildout:parts-directory}/etc/debug.ini
+
+[eggbasket]
+recipe = z3c.recipe.eggbasket
+eggs = grok
+url = http://grok.zope.org/releaseinfo/grok-eggs-1.1.tgz
Index: main/waeup.uniben/branches/uli-payments/buildout-zeo.cfg
===================================================================
--- main/waeup.uniben/branches/uli-payments/buildout-zeo.cfg	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/buildout-zeo.cfg	(revision 8249)
@@ -0,0 +1,124 @@
+# A buildout configuration for a ZEO server and two ZEO clients.
+#
+[buildout]
+extends = buildout.cfg
+parts =
+    eggbasket
+    app
+    i18n
+    test
+    mkdirs
+    zpasswd
+    zope_conf
+    site_zcml
+    zdaemon_conf
+    deploy_ini
+    debug_ini
+    profile_ini
+    zeo1_ini
+    zeo2_ini
+    waeupdocs
+    coverage-detect
+    coverage-report
+# kofactl creation must be _after_ app!
+    kofactl
+# For backward compatibility, telling buildout not to throw away
+# the data and log subdirectories from the parts directory.
+    data
+    log
+
+    zeo_server
+    zope_conf_zeo_1
+    zope_conf_zeo_2
+    zeo1_ini
+    zeo2_ini
+    zeo1_conf
+    zeo2_conf
+    zeo_client1
+    zeo_client2
+
+[zeo_server]
+recipe = zc.zodbrecipes:server
+zeo.conf =
+  <zeo>
+    address 7010
+  </zeo>
+  <blobstorage 1>
+    blob-dir ${zope_conf:blobstorage}
+    <filestorage 1>
+      path ${zope_conf:filestorage}/Data.fs
+    </filestorage>
+  </blobstorage>
+  <eventlog>
+    # This sets up logging to a file.
+    # The "path" setting can be a relative or absolute
+    # filesystem path.
+    <logfile>
+      path ${zope_conf:logfiles}/z3.log
+      formatter zope.exceptions.log.Formatter
+    </logfile>
+    # This sets up logging to to standard output.
+    # The "path" setting can be the tokens STDOUT or STDERR
+    #  <logfile>
+    #    path STDOUT
+    #    formatter zope.exceptions.log.Formatter
+    #  </logfile>
+  </eventlog>
+
+[zope_conf_zeo_1]
+recipe = collective.recipe.template
+input = etc/zope_zeo1.conf.in
+output = ${buildout:parts-directory}/etc/zope_zeo1.conf
+filestorage = ${buildout:directory}/var/filestorage
+blobstorage = ${buildout:directory}/var/blobstorage
+logfiles = ${buildout:directory}/var/log
+extra =
+# extra = <grokwarnings>True</grokwarnings>
+# 'extra' is copied verbatim. Use it for product config sections and so.
+
+[zope_conf_zeo_2]
+recipe = collective.recipe.template
+input = etc/zope_zeo2.conf.in
+output = ${buildout:parts-directory}/etc/zope_zeo2.conf
+filestorage = ${buildout:directory}/var/filestorage
+blobstorage = ${buildout:directory}/var/blobstorage
+logfiles = ${buildout:directory}/var/log
+extra =
+# extra = <grokwarnings>True</grokwarnings>
+# 'extra' is copied verbatim. Use it for product config sections and so.
+
+[zeo1_ini]
+recipe = collective.recipe.template
+input = etc/zeo1.ini.in
+output = ${buildout:parts-directory}/etc/zeo1.ini
+
+[zeo2_ini]
+recipe = collective.recipe.template
+input = etc/zeo2.ini.in
+output = ${buildout:parts-directory}/etc/zeo2.ini
+
+[zeo1_conf]
+recipe = collective.recipe.template
+input = etc/zeo1.conf.in
+output = ${buildout:parts-directory}/etc/zeo1.conf
+
+[zeo2_conf]
+recipe = collective.recipe.template
+input = etc/zeo2.conf.in
+output = ${buildout:parts-directory}/etc/zeo2.conf
+
+
+[zeo_client1]
+# See http://pypi.python.org/pypi/zc.recipe.egg for details...
+recipe = zc.recipe.egg
+eggs = waeup.uniben [beaker]
+arguments = "${buildout:parts-directory}/etc/zeo1.conf"
+scripts = kofactl=zeo_client1
+
+[zeo_client2]
+# See http://pypi.python.org/pypi/zc.recipe.egg for details...
+recipe = zc.recipe.egg
+eggs = waeup.uniben [beaker]
+arguments = "${buildout:parts-directory}/etc/zeo2.conf"
+scripts = kofactl=zeo_client2
+
Index: main/waeup.uniben/branches/uli-payments/buildout.cfg
===================================================================
--- main/waeup.uniben/branches/uli-payments/buildout.cfg	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/buildout.cfg	(revision 8249)
@@ -0,0 +1,184 @@
+[buildout]
+develop = . waeup.kofa
+parts =
+    eggbasket
+    app
+    i18n
+    test
+    mkdirs
+    zpasswd
+    zope_conf
+    site_zcml
+    zdaemon_conf
+    deploy_ini
+    debug_ini
+    profile_ini
+    waeupdocs
+    coverage-detect
+    coverage-report
+# kofactl creation must be _after_ app!
+    kofactl
+# For backward compatibility, telling buildout not to throw away
+# the data and log subdirectories from the parts directory.
+    data
+    log
+# newest = false
+
+#extends = versions.cfg
+extends= http://grok.zope.org/releaseinfo/grok-1.1.cfg
+# eggs will be installed in the default buildout location
+# (see .buildout/default.cfg in your home directory)
+# unless you specify an eggs-directory option here.
+
+versions = versions
+
+[versions]
+collective.recipe.sphinxbuilder = 0.7.0
+hurry.workflow = 0.11
+# Pinned to circumvent breakage in 0.4.x
+hurry.zoperesource = 0.6
+# Pinned to prevent buildout svn-error.
+lovely.recipe = 1.0.0
+megrok.layout = 1.0.2
+reportlab = 2.5
+transaction = 1.1.0
+z3c.testsetup = 0.6.1
+zc.buildout = 1.5.0
+zc.recipe.egg = 1.3.0
+zc.recipe.testrunner = 1.4.0
+zope.app.testing = 3.8.1
+# for support of @provider directive
+zope.interface = 3.6.3
+# for support of contextual default values
+zope.schema = 3.8.0
+zope.testing = 3.10.2
+zope.xmlpickle = 3.4.0
+# Require latest version...
+Sphinx = 1.0.7
+ZODB3 = 3.10.3
+docutils = 0.7
+Jinja2 = 2.3
+
+[app]
+# This creates all scripts in bin/. The kofactl created here is 'faulty'.
+recipe = zc.recipe.egg
+eggs = waeup.uniben [beaker]
+       z3c.evalexception>=2.0
+       Paste
+       PasteScript
+       PasteDeploy
+       repoze.profile
+       ZODB3
+interpreter = python-console
+
+[kofactl]
+# See http://pypi.python.org/pypi/zc.recipe.egg for details...
+# Here we create the kofactl script again, this time with a
+# fixed path to zdaemon.conf as argument.
+recipe = zc.recipe.egg
+eggs = waeup.uniben [beaker]
+arguments = "${buildout:parts-directory}/etc/zdaemon.conf"
+scripts = kofactl=kofactl
+
+[mkdirs]
+recipe = z3c.recipe.mkdir
+paths =
+    ${zope_conf:filestorage}
+    ${zope_conf:logfiles}
+    ${zope_conf:blobstorage}
+    ${buildout:directory}/var/datacenter/media
+    ${buildout:directory}/parts/test/datacenter
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = waeup.uniben [beaker, test]
+defaults = ['--tests-pattern', '^f?tests$', '-v']
+
+# This section named so that the i18n scripts are called bin/i18n...
+[i18n]
+recipe = z3c.recipe.i18n:i18n
+packages = waeup.uniben
+eggs = waeup.uniben
+domain = waeup.uniben
+output = src/waeup/uniben/locales
+zcml =
+
+# This section is named so that the zpasswd utility is
+# called `zpasswd`
+[zpasswd]
+recipe = z3c.recipe.dev:script
+eggs = waeup.uniben
+module = zope.app.server.zpasswd
+method = main
+
+[zope_conf]
+recipe = collective.recipe.template
+input = etc/zope.conf.in
+output = ${buildout:parts-directory}/etc/zope.conf
+filestorage = ${buildout:directory}/var/filestorage
+blobstorage = ${buildout:directory}/var/blobstorage
+logfiles = ${buildout:directory}/var/log
+extra =
+# extra = <grokwarnings>True</grokwarnings>
+# 'extra' is copied verbatim. Use it for product config sections and so.
+
+# The [data] and [log] parts are still in here to instruct buildout to not
+# unintentionally throw away the parts/data and parts/log subdirectories
+# that contain the Data.fs and the log files. These files should be
+# copied to the new locations. See the upgrade notes for more information.
+[data]
+recipe = zc.recipe.filestorage
+
+[log]
+recipe = zc.recipe.filestorage
+
+[site_zcml]
+recipe = collective.recipe.template
+input = etc/site.zcml.in
+output = ${buildout:parts-directory}/etc/site.zcml
+
+[zdaemon_conf]
+recipe = collective.recipe.template
+input = etc/zdaemon.conf.in
+output = ${buildout:parts-directory}/etc/zdaemon.conf
+
+[deploy_ini]
+recipe = collective.recipe.template
+input = etc/deploy.ini.in
+output = ${buildout:parts-directory}/etc/deploy.ini
+
+[debug_ini]
+recipe = collective.recipe.template
+input = etc/debug.ini.in
+output = ${buildout:parts-directory}/etc/debug.ini
+
+[profile_ini]
+recipe = collective.recipe.template
+input = etc/profile.ini.in
+output = ${buildout:parts-directory}/etc/profile.ini
+
+[eggbasket]
+recipe = z3c.recipe.eggbasket
+eggs = grok
+url = http://grok.zope.org/releaseinfo/grok-eggs-1.1.tgz
+
+[waeupdocs]
+recipe = collective.recipe.sphinxbuilder
+eggs = waeup.uniben[docs]
+source = ${buildout:directory}/docs/source
+build = ${buildout:directory}/docs/build
+
+# Collect test coverage data.
+[coverage-detect]
+recipe = zc.recipe.testrunner
+eggs = waeup.uniben[beaker]
+defaults = ['--tests-pattern', '^f?tests$', '-v', '--coverage', 'coverage']
+
+# Create a coverage report.
+# Make sure to run bin/coverage-detect to collect the data for the report
+# first!
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coveragereport
+arguments = ('${buildout:parts-directory}/coverage-detect/working-directory/coverage', '${buildout:directory}/coverage-report')
Index: main/waeup.uniben/branches/uli-payments/docs/INSTALL.txt
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/INSTALL.txt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/INSTALL.txt	(revision 8249)
@@ -0,0 +1,84 @@
+Installation on Linux production system
+***************************************
+
+.. note:: `waeup.kofa` might not work with Python > 2.6
+          currently. Use of Python 2.6 is recommended.
+
+Prerequisites
+=============
+
+The `waeup.kofa` package is based on `Grok`_, which is a Python
+framework for agile webapplication development. Grok itself is based
+on `Zope`_.
+
+.. _Grok: http://grok.zope.org/
+
+.. _Zope: http://www.zope.org/
+
+Both, Grok and Zope, are written in Python (with parts written in
+C). You therefore need `Python`_ installed.
+
+.. _Python: http://www.python.org/
+
+Note, that you also need the Python header files and a compiler to
+compile the parts written in C.
+
+To deploy `waeup.kofa` most easily, we use `zc.buildout`_
+
+.. _zc.buildout: http://cheeseshop.python.org/pypi/zc.buildout
+
+You may have setuptools already installed for your system Python. In
+that case, you may need to upgrade it first because buildout requires
+a very recent version::
+
+    $ sudo easy_install -U setuptools
+
+If this command fails because easy_install is not available, there is
+a good chance you do not have setuptools available for your system
+Python. If so, there is no problem because setuptools will be
+installed locally by buildout.
+
+Bootstrap the buildout environment::
+
+    $ python2.6 bootstrap/bootstrap.py
+
+and run the buildout command::
+
+    $ bin/buildout
+    [lots of stuff will be downloaded and installed here]
+
+Note that if you have more than one sandbox for a Zope-based web
+application, it will probably make sense to share the eggs between the
+different sandboxes.  You can tell ``zc.buildout`` to use a central
+eggs directory by creating ``~/.buildout/default.cfg`` with the
+following contents::
+
+    [buildout]
+    eggs-directory = /home/bruno/buildout-eggs
+
+Running the `waeup.kofa` application
+======================================
+
+You can start Zope with the with the following command::
+
+    $ bin/kofactl fg
+    
+Alternatively you can do:
+
+    $ bin/paster serve parts/etc/deploy.ini    
+
+If you now connect to port 8080 and log in with username 'grok',
+password 'grok', you should be able to add the grok-based applications
+(such as ``University``) from the menu.
+
+Add an instance of ``University`` and click on the link next to the
+then visible entry in the list of installed applications.
+
+Running the tests
+=================
+
+The tests are easily run by executing the test runner that's
+installed in the ``bin`` directory::
+
+    $ bin/test
+
Index: main/waeup.uniben/branches/uli-payments/docs/INSTALLWIN.txt
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/INSTALLWIN.txt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/INSTALLWIN.txt	(revision 8249)
@@ -0,0 +1,87 @@
+Installation on Windows (XP, 2000, Vista, 7)
+********************************************
+
+.. note:: `waeup.kofa` has been developed to run on Linux servers,
+          preferarbly with an Ubuntu OS. The installation on Windows computers
+          is for demonstration purposes only.
+
+Install Python
+==============
+
+**Step 1.** Install Python. Currently, version 2.6.x is supported.
+Note that these links point to installers for the ordinary x86 processor architecture.
+We recommend to download the follwoing software and install into ``C:\Python26``:
+
+| http://www.python.org/ftp/python/2.6.0/python-2.6.0.msi
+| http://sourceforge.net/project/downloading.php?group_id=78018&filename=pywin32-213.win32-py2.6.exe
+| http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11.win32-py2.6.exe
+
+**Step 2**. Add ``C:\Python26\Scripts\`` to your system path:
+
+- Right-click on the My Computer icon. (Under Windows XP, Vista, or Windows 7, the My Computer Icon may be located in the start menu.)
+
+- Choose Properties from the context menu. Alternatively, you can double-click on the System icon in the Control Panel.
+
+- Click the Advanced tab or "Advanced system settings" on Windows Vista or Windows 7
+
+- Click the Environment Variables button.
+
+- Click on the variable called 'Path' and then click on Edit. Now add ``C:\Python26\Scripts\`` to the value of the variable, using a semi-colon as a separator.
+
+- Reboot Windows
+
+Install a Virtual Python Environment
+====================================
+
+**Step 3**. Open up a command window and change to the folder where you want to place the sandbox
+that will contain your Kofa project. In this HowTo we will assume and recommend this folder is ``C:\`` ::
+
+  C:\[any_path]> cd c:\
+
+**Step 4**. Install virtualenv by using the command::
+
+ C:\> easy_install virtualenv
+
+**Step 5**. Create an isolated environment (sandbox) using the command::
+
+ C:\> virtualenv winkofa
+
+**Step 6**. Activate the environment::
+
+ C:\> cd winkofa
+ C:\winkofa> Scripts\activate
+
+Note that the system prompt has changed.
+
+Run Kofa
+========
+
+**Step 7**. Copy the ``waeup.kofa`` folder into ``C:\winkofa``.
+
+**Step 8**. Run the bootstrap script::
+
+ (winkofa) C:\winkofa\waeup.kofa> cd waeup.kofa
+ (winkofa) C:\winkofa\waeup.kofa> python bootstrap\bootstrap.py -c buildout-windows.cfg
+
+**Step 9**. Run buildout (this takes a while)::
+
+ C:\winkofa\waeup.kofa> bin\buildout.exe -c buildout-windows.cfg
+
+**Step 10**. You can deactivate your environment again::
+
+ (winkofa) C:\winkofa\waeup.kofa> ..\Scripts\deactivate
+
+**Step 11**. Start your Kofa::
+
+ C:\winkofa\waeup.kofa> bin\paster serve parts\etc\deploy.ini
+
+or from anywhere in your system::
+
+ C:\[any_path]> C:\winkofa\trunk\bin\paster serve C:\winkofa\trunk\parts\etc\deploy.ini
+
+**Step 12**. Visit the Kofa website and create your university instance:
+
+| http://localhost:8080
+| user name: grok
+| password: grok
+
Index: main/waeup.uniben/branches/uli-payments/docs/Makefile
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/Makefile	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/Makefile	(revision 8249)
@@ -0,0 +1,89 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html      to make standalone HTML files"
+	@echo "  dirhtml   to make HTML files named index.html in directories"
+	@echo "  pickle    to make pickle files"
+	@echo "  json      to make JSON files"
+	@echo "  htmlhelp  to make HTML files and a HTML help project"
+	@echo "  qthelp    to make HTML files and a qthelp project"
+	@echo "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  changes   to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck to check all external links for integrity"
+	@echo "  doctest   to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/WAeUPStudentInformationandRegistrationPortalKofa.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WAeUPStudentInformationandRegistrationPortalKofa.qhc"
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+	      "run these through (pdf)latex."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
Index: main/waeup.uniben/branches/uli-payments/docs/make.bat
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/make.bat	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/make.bat	(revision 8249)
@@ -0,0 +1,113 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+set SPHINXBUILD=sphinx-build
+set BUILDDIR=build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html      to make standalone HTML files
+	echo.  dirhtml   to make HTML files named index.html in directories
+	echo.  pickle    to make pickle files
+	echo.  json      to make JSON files
+	echo.  htmlhelp  to make HTML files and a HTML help project
+	echo.  qthelp    to make HTML files and a qthelp project
+	echo.  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  changes   to make an overview over all changed/added/deprecated items
+	echo.  linkcheck to check all external links for integrity
+	echo.  doctest   to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\WAeUPStudentInformationandRegistrationPortalKofa.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\WAeUPStudentInformationandRegistrationPortalKofa.ghc
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end
Index: main/waeup.uniben/branches/uli-payments/docs/source/_templates/mainpage.template
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/_templates/mainpage.template	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/_templates/mainpage.template	(revision 8249)
@@ -0,0 +1,94 @@
+{% extends "layout.html" %}
+{% set title = 'Overview' %}
+{% block body %}
+
+<h1>{{ docstitle }}</h1>
+<p>
+  This is official documentation for waeup.sirp {{ release }}.
+  {% if last_updated %}Last modifed on {{ last_updated }}.{% endif %}
+</p>
+
+<p><strong>Sections</strong></p>
+<table class="contentstable" align="center"><tr>
+  <td width="50%">
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("intro") }}">Introduction</a><br />
+      <span class="linkdescr">Get started with waeup.sirp.</span>
+    </p>
+      
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("userdocs/index") }}">User documentation</a><br />
+    <span class="linkdescr">
+      Documentation for users and admins using waeup.sirp.
+    </span></p>
+
+    </td><td width="50%">
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("changes") }}">What's new?</a><br />
+      <span class="linkdescr">Changes made in each release.</span>
+    </p>
+
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("developerdocs/index") }}">Developer documentation</a><br />
+      <span class="linkdescr">
+        <a href="{{ pathto("developerdocs/api/index") }}">API</a> and other pieces
+        relevant for developers.
+      </span>
+    </p>
+          
+  </td></tr>
+</table>
+
+<p><strong>Indices and tables</strong></p>
+<table class="contentstable" align="center"><tr>
+  <td width="50%">
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("contents") }}">Table of Contents</a><br />
+      <span class="linkdescr">Lists all sections and subsections.</span>
+    </p>
+    </td><td width="50%">
+
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("genindex") }}">Index</a><br />
+      <span class="linkdescr">All functions, classes, terms.</span>
+    </p>
+  </td></tr>
+</table>
+
+<p><strong>Further information</strong></p>
+<table class="contentstable" align="center"><tr>
+  <td width="50%">
+
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("bugs") }}">Reporting bugs</a><br />
+    </p>
+
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("documentation") }}">About the documentation</a><br />
+    </p>
+
+    </td><td width="50%">
+              
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("license") }}">License</a><br />
+    </p>
+
+    <p class="biglink">
+      <a class="biglink" 
+         href="{{ pathto("copyright") }}">Copyright</a><br />
+    </p>
+
+    </td></tr>
+</table>
+
+
+{% endblock %}
Index: main/waeup.uniben/branches/uli-payments/docs/source/bugs.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/bugs.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/bugs.rst	(revision 8249)
@@ -0,0 +1,18 @@
+.. _reporting-bugs:
+
+Reporting Bugs in `waeup.kofa`
+******************************
+
+The developers would like to know of any deficiencies you find in
+`waeup.kofa`.
+
+Also telling about errors and shortcomings in the documentation are
+welcome. Please write to ``henrik at waeup dot org`` if you find any.
+
+.. seealso::
+
+   `How to Report Bugs Effectively
+   <http://www.chiark.greenend.org.uk/~sgtatham/bugs.html>`_ Article
+   which goes into some detail about how to create a useful bug
+   report. This describes what kind of information is useful and why
+   it is useful.
Index: main/waeup.uniben/branches/uli-payments/docs/source/changes.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/changes.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/changes.rst	(revision 8249)
@@ -0,0 +1,1 @@
+.. include:: ../../CHANGES.txt
Index: main/waeup.uniben/branches/uli-payments/docs/source/conf.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/conf.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/conf.py	(revision 8249)
@@ -0,0 +1,213 @@
+# -*- coding: utf-8 -*-
+#
+# WAeUP Student Information and Registration Portal (Kofa) documentation build configuration file, created by
+# sphinx-quickstart on Thu Jul 29 10:41:59 2010.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+import pkg_resources
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.doctest',
+    'sphinx.ext.intersphinx',
+    'sphinx.ext.todo',
+    'sphinx.ext.coverage',
+    'sphinx.ext.ifconfig',
+    'sphinx.ext.viewcode',
+    'repoze.sphinx.autointerface'
+    ]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'WAeUP Kofa'
+copyright = u'2011, WAeUP Team'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = pkg_resources.get_distribution('waeup.kofa').version
+#version = '0.2dev'
+# The full version, including alpha/beta/rc tags.
+#release = '0.2dev'
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+html_favicon = "favicon.ico"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+#html_additional_pages = {
+#    'index': os.path.join(os.path.dirname(__file__), 'docindex.template')}
+html_additional_pages = { 'index': 'mainpage.template'}
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'WAeUPStudentInformationandRegistrationPortalKofadoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'WAeUPStudentInformationandRegistrationPortalKofa.tex', u'WAeUP Student Information and Registration Portal (Kofa) Documentation',
+   u'WAeUP Team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'http://docs.python.org/': None}
Index: main/waeup.uniben/branches/uli-payments/docs/source/contents.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/contents.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/contents.rst	(revision 8249)
@@ -0,0 +1,25 @@
+.. _contents:
+
+`waeup.kofa` documentation contents
+===================================
+
+.. toctree::
+   :maxdepth: 2
+
+   intro
+   userdocs/index
+   developerdocs/index
+   changes
+   license
+   copyright
+   glossary
+   bugs
+   documentation
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+* :ref:`glossary`
Index: main/waeup.uniben/branches/uli-payments/docs/source/copyright.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/copyright.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/copyright.rst	(revision 8249)
@@ -0,0 +1,10 @@
+Copyright
+*********
+
+`waeup.kofa` and this documentation is:
+
+Copyright © 2009-2010 The WAeUP Group. All rights reserved.
+
+----------
+
+See :ref:`license` for complete license and permissions information.
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_accesscode.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_accesscode.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_accesscode.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`accesscodes.accesscode` -- AC Components
+*****************************************
+
+.. automodule:: waeup.sirp.accesscodes.accesscode
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_browser.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_browser.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_browser.rst	(revision 8249)
@@ -0,0 +1,12 @@
+`accesscodes.browser` -- AC UI Components
+*****************************************
+
+Probably due to a bug in Sphinx autodoc couldn't import/find some classes and
+reported error: "grokcore, please check your spelling and sys.path".
+Thus, automodule has been temporarily disabled.
+
+
+..
+  .. automodule:: waeup.sirp.accesscodes.browser
+     :members:
+     :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_catalog.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_catalog.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_catalog.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`accesscodes.catalog` -- AC Catalog Components
+**********************************************
+
+.. automodule:: waeup.sirp.accesscodes.catalog
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_interfaces.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_interfaces.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_interfaces.rst	(revision 8249)
@@ -0,0 +1,14 @@
+`accesscodes.interfaces` -- AC Interfaces
+*****************************************
+
+.. automodule:: waeup.sirp.accesscodes.interfaces
+   :members:
+   :undoc-members:
+
+
+   .. autointerface:: IAccessCode
+      :members:
+   .. autointerface:: IAccessCodeBatch
+      :members:
+   .. autointerface:: IAccessCodeBatchContainer
+      :members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_workflow.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_workflow.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/accesscodes/api_workflow.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`accesscodes.workflow` - AC Workflow Components
+***********************************************
+
+.. automodule:: waeup.sirp.accesscodes.workflow
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_accesscodes.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_accesscodes.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_accesscodes.rst	(revision 8249)
@@ -0,0 +1,24 @@
+`accesscodes` -- Access Codes Package
+*************************************
+
+(see also: :ref:`api-accesscodes-modules`)
+
+.. automodule:: waeup.sirp.accesscodes
+   :members:
+   :undoc-members:
+
+.. _api-accesscodes-modules:
+
+Submodules
+===========
+
+This package contains the following modules:
+
+.. toctree::
+   :maxdepth: 1
+
+   accesscodes/api_accesscode
+   accesscodes/api_browser
+   accesscodes/api_catalog
+   accesscodes/api_interfaces
+   accesscodes/api_workflow
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_app.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_app.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_app.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`app` -- University Root (Site) Module
+**************************************
+
+.. automodule:: waeup.sirp.app
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_applicants.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_applicants.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_applicants.rst	(revision 8249)
@@ -0,0 +1,30 @@
+`applicants` - Application Components Package
+*********************************************
+
+(see also: :ref:`api-applicants-modules`)
+
+.. automodule:: waeup.sirp.applicants
+   :members:
+   :undoc-members:
+
+.. _api-applicants-modules:
+
+Submodules
+----------
+
+This package bundles the following submodules:
+
+.. toctree::
+   :maxdepth: 1
+
+   applicants/api_interfaces
+   applicants/api_root
+   applicants/api_container
+   applicants/api_applicant
+   applicants/api_authentication
+   applicants/api_batching
+   applicants/api_browser
+   applicants/api_permissions
+   applicants/api_vocabularies
+   applicants/api_workflow
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_authentication.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_authentication.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_authentication.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`authentication` -- Authentication Components Module
+****************************************************
+
+.. automodule:: waeup.sirp.authentication
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_browser.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_browser.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_browser.rst	(revision 8249)
@@ -0,0 +1,27 @@
+`browser` -- Viewing Components Package
+***************************************
+
+(see also: :ref:`api-browser-modules`)
+
+.. automodule:: waeup.sirp.browser
+   :members:
+   :undoc-members:
+
+.. _api-browser-modules:
+
+Submodules
+----------
+
+This package bundles the following modules:
+
+.. toctree::
+   :maxdepth: 1
+
+   browser/api_interfaces.rst
+   browser/api_pages.rst
+   browser/api_viewlets.rst
+   browser/api_layout.rst
+   browser/api_breadcrumbs.rst
+   browser/api_theming.rst
+   browser/api_resources.rst
+   browser/api_exceptions.rst
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_catalog.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_catalog.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_catalog.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`catalog` -- Cataloging Components Module
+*****************************************
+
+.. automodule:: waeup.sirp.catalog
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_datacenter.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_datacenter.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_datacenter.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`datacenter` -- Datacenter Module
+*********************************
+
+.. automodule:: waeup.sirp.datacenter
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_interfaces.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_interfaces.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_interfaces.rst	(revision 8249)
@@ -0,0 +1,10 @@
+`interfaces` - Main Interfaces Module
+*************************************
+
+.. automodule:: waeup.sirp.interfaces
+   :members:
+   :undoc-members:
+
+.. autointerface:: waeup.sirp.interfaces.IUniversity
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_permissions.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_permissions.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_permissions.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`permissions` -- Permissions and Roles Components Module
+********************************************************
+
+.. automodule:: waeup.sirp.permissions
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_university.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_university.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_university.rst	(revision 8249)
@@ -0,0 +1,30 @@
+`university` -- University Components Package
+*********************************************
+
+(see also: :ref:`api-university-modules`)
+
+.. automodule:: waeup.sirp.university
+   :members:
+   :undoc-members:
+
+.. _api-university-modules:
+
+Submodules
+----------
+
+This package bundles the following modules:
+
+.. toctree::
+   :maxdepth: 1
+
+   university/api_interfaces
+   university/api_catalog
+   university/api_vocabularies
+   university/api_batching
+   university/api_facultycontainer
+   university/api_faculty
+   university/api_department
+   university/api_certificatecontainer
+   university/api_coursecontainer
+   university/api_course
+   university/api_certificate
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_users.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_users.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_users.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`users` -- Users (Principals) Module
+************************************
+
+.. automodule:: waeup.sirp.users
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_utils.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_utils.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_utils.rst	(revision 8249)
@@ -0,0 +1,19 @@
+`utils` -- Utilities Package
+****************************
+
+(see also: :ref:`api-utils-modules`)
+
+.. automodule:: waeup.sirp.utils
+   :members:
+   :undoc-members:
+
+.. _api-utils-modules:
+
+Submodules
+----------
+
+This package bundles the following modules:
+
+.. toctree::
+   :maxdepth: 1
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_workflow.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_workflow.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/api_workflow.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`workflow` -- Workflow Components Module
+****************************************
+
+.. automodule:: waeup.sirp.workflow
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_applicant.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_applicant.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_applicant.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.applicant` - Applicant Components
+*********************************************
+
+.. automodule:: waeup.sirp.applicants.applicant
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_authentication.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_authentication.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_authentication.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.authentication` - Applicants Authentication Components
+******************************************************************
+
+.. automodule:: waeup.sirp.applicants.authentication
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_batching.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_batching.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_batching.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.batching` - Batch Importer for Applicants
+*****************************************************
+
+.. automodule:: waeup.sirp.applicants.batching
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_browser.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_browser.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_browser.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.browser` - Applicants UI Components
+***********************************************
+
+.. automodule:: waeup.sirp.applicants.browser
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_container.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_container.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_container.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.container` - Container for Applicants
+*************************************************
+
+.. automodule:: waeup.sirp.applicants.container
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_interfaces.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_interfaces.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_interfaces.rst	(revision 8249)
@@ -0,0 +1,48 @@
+`applicants.interfaces` - Applicants Related Interfaces
+*******************************************************
+
+.. automodule:: waeup.sirp.applicants.interfaces
+   :members:
+   :undoc-members:
+
+   .. autointerface:: IResultEntry
+      :members:
+
+   .. autointerface:: IApplicantsRoot
+      :members:
+
+   .. autointerface:: IApplicantsContainer
+      :members:
+
+   .. autointerface:: IApplicantsContainerAdd
+      :members:
+
+   .. autointerface:: IApplicantBaseData
+      :members:
+
+   .. autointerface:: IApplicant
+      :members:
+
+   .. autointerface:: IApplicantEdit
+      :members:
+
+   .. autointerface:: IResultEntry
+      :members:
+
+   .. autointerface:: IApplicantPrincipalInfo
+      :members:
+
+   .. autointerface:: IApplicantPrincipal
+      :members:
+
+   .. autointerface:: IApplicantPrincipal
+      :members:
+
+   .. autointerface:: IApplicantsFormChallenger
+      :members:
+
+   .. autointerface:: IApplicantSessionCredentials
+      :members:
+
+   .. autointerface:: IApplicantsContainerProvider
+      :members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_permissions.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_permissions.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_permissions.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.permissions` - Applicants Permission Components
+***********************************************************
+
+.. automodule:: waeup.sirp.applicants.permissions
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_root.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_root.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_root.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.root` - Root for Applicants Containers
+**************************************************
+
+.. automodule:: waeup.sirp.applicants.root
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_vocabularies.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_vocabularies.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_vocabularies.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.vocabularies` - Vocabularies and Sources
+****************************************************
+
+.. automodule:: waeup.sirp.applicants.vocabularies
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_workflow.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_workflow.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/applicants/api_workflow.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`applicants.workflow` - Applicants Workflow Components
+******************************************************
+
+.. automodule:: waeup.sirp.applicants.workflow
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_breadcrumbs.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_breadcrumbs.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_breadcrumbs.rst	(revision 8249)
@@ -0,0 +1,7 @@
+`browser.breadcrumbs` - Browser Breadcrumbs
+*******************************************
+
+.. automodule:: waeup.sirp.browser.breadcrumbs
+   :members:
+   :undoc-members:
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_exceptions.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_exceptions.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_exceptions.rst	(revision 8249)
@@ -0,0 +1,7 @@
+`browser.exceptions` - Browser Exceptions
+*****************************************
+
+.. automodule:: waeup.sirp.browser.exceptions
+   :members:
+   :undoc-members:
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_interfaces.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_interfaces.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_interfaces.rst	(revision 8249)
@@ -0,0 +1,18 @@
+`browser.interfaces` - Browser Interfaces
+*****************************************
+
+.. automodule:: waeup.sirp.browser.interfaces
+   :members:
+   :undoc-members:
+
+   .. autointerface:: IBreadcrumb
+      :members:
+
+   .. autointerface:: IBreadcrumbIgnorable
+      :members:
+
+   .. autointerface:: IBreadcrumbContainer
+      :members:
+
+   .. autointerface:: ITheme
+      :members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_layout.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_layout.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_layout.rst	(revision 8249)
@@ -0,0 +1,7 @@
+`browser.layout` - Browser Layout
+*********************************
+
+.. automodule:: waeup.sirp.browser.layout
+   :members:
+   :undoc-members:
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_pages.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_pages.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_pages.rst	(revision 8249)
@@ -0,0 +1,7 @@
+`browser.pages` - Browser Pages (Views)
+***************************************
+
+.. automodule:: waeup.sirp.browser.pages
+   :members:
+   :undoc-members:
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_resources.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_resources.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_resources.rst	(revision 8249)
@@ -0,0 +1,7 @@
+`browser.resources` - Browser Resources
+***************************************
+
+.. automodule:: waeup.sirp.browser.resources
+   :members:
+   :undoc-members:
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_theming.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_theming.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_theming.rst	(revision 8249)
@@ -0,0 +1,7 @@
+`browser.theming` - Browser Theming
+***********************************
+
+.. automodule:: waeup.sirp.browser.theming
+   :members:
+   :undoc-members:
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_viewlets.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_viewlets.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/browser/api_viewlets.rst	(revision 8249)
@@ -0,0 +1,12 @@
+`browser.viewlets` - Browser Viewlets
+*************************************
+
+Probably due to a bug in Sphinx autodoc couldn't import/find some classes and
+reported error: "grokcore, please check your spelling and sys.path".
+Thus, automodule has been temporarily disabled.
+
+..
+  .. automodule:: waeup.sirp.browser.viewlets
+     :members:
+     :undoc-members:
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/index.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/index.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/index.rst	(revision 8249)
@@ -0,0 +1,28 @@
+API
+***
+
+.. automodule:: waeup.sirp
+   :members:
+
+Modules and Packages
+--------------------
+
+`waeup.sirp` provides the following modules and subpackages:
+
+.. toctree::
+   :maxdepth: 1
+
+   api_app
+   api_interfaces
+   api_authentication
+   api_catalog
+   api_permissions
+   api_datacenter
+   api_users
+   api_workflow
+   api_university
+   api_browser
+   api_applicants
+   api_accesscodes
+   api_utils
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_batching.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_batching.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_batching.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.batching` - Importer Components
+*******************************************
+
+.. automodule:: waeup.sirp.university.batching
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_catalog.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_catalog.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_catalog.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.catalog` - Cataloging Components
+********************************************
+
+.. automodule:: waeup.sirp.university.catalog
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_certificate.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_certificate.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_certificate.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.certificate` - Certificate Components
+*************************************************
+
+.. automodule:: waeup.sirp.university.certificate
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_certificatecontainer.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_certificatecontainer.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_certificatecontainer.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.certificatecontainer` - Certificate Container Components
+********************************************************************
+
+.. automodule:: waeup.sirp.university.certificatecontainer
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_course.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_course.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_course.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.course` - Course Components
+***************************************
+
+.. automodule:: waeup.sirp.university.course
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_coursecontainer.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_coursecontainer.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_coursecontainer.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.coursecontainer` - Course Container Components
+**********************************************************
+
+.. automodule:: waeup.sirp.university.coursecontainer
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_department.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_department.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_department.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.department` - Department Components
+***********************************************
+
+.. automodule:: waeup.sirp.university.department
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_faculty.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_faculty.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_faculty.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.faculty` - Faculty Components
+*****************************************
+
+.. automodule:: waeup.sirp.university.faculty
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_facultycontainer.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_facultycontainer.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_facultycontainer.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.facultycontainer` - Faculty Container Components
+************************************************************
+
+.. automodule:: waeup.sirp.university.facultycontainer
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_interfaces.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_interfaces.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_interfaces.rst	(revision 8249)
@@ -0,0 +1,45 @@
+`university.interfaces` - Interfaces of the University Package
+**************************************************************
+
+.. automodule:: waeup.sirp.university.interfaces
+   :members:
+   :undoc-members:
+
+.. autointerface:: waeup.sirp.university.interfaces.IFaculty
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.IFacultyAdd
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.IFacultyContainer
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.IDepartment
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.IDepartmentAdd
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICourseContainer
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICourse
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICourseAdd
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICertificate
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICertificateAdd
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICertificateContainer
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICertificateCourse
+   :members:
+
+.. autointerface:: waeup.sirp.university.interfaces.ICertificateCourseAdd
+   :members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_vocabularies.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_vocabularies.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/api/university/api_vocabularies.rst	(revision 8249)
@@ -0,0 +1,6 @@
+`university.vocabularies` - Vocabularies and Sources
+****************************************************
+
+.. automodule:: waeup.sirp.university.vocabularies
+   :members:
+   :undoc-members:
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/developernotes.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/developernotes.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/developernotes.rst	(revision 8249)
@@ -0,0 +1,344 @@
+Developer Notes
+***************
+
+How to setup a developer instance of the WAeUP Kofa, handle tests, docs
+etc.
+
+The new WAeUP Kofa is based on `Grok <http://grok.zope.org/>`_.
+
+Installing a developer copy
+===========================
+
+The installation is described for Linux-based computers.
+
+Preparing the system
+--------------------
+
+To create a working copy of the WAeUP Kofa we recommend use of
+`virtualenv`. You, however, need also some basic libraries, a C
+compiler and some things more.
+
+What you need (Debian/Ubuntu package names in brackets):
+
+* Python 2.6 (python2.6)
+
+  Currently, also Python2.5 is supported but we want to make use of
+  some of the 2.6 goodies in the future.
+
+
+* Python 2.6 development files (python2.6-dev)
+
+* A C-Compiler (gcc)
+
+* The C library development files (libc6-dev)
+
+* A subversion client (svn)
+
+* enscript (enscript) [optional]
+
+  This is only needed if you want test coverage reports.
+
+All these packages can be installed on Debian systems like this::
+
+  # apt-get install python2.6 python2.6-dev python2.6-dbg \
+                    gcc libc6-dev svn enscript
+
+Afterwards you should be able to enter::
+
+  $ python2.6
+
+at the commandline and get a Python prompt. Quit the interpreter
+pressing <CTRL-D>.
+
+Installing `virtualenv`
+-----------------------
+
+We recommend use of `virtualenv` to create Python sandboxes where you
+can run your code without touching any other installations.
+
+If you don't already have ``easy_install`` available, you can find the
+script to set it up on the `PEAK EasyInstall page`_.
+
+.. _`PEAK EasyInstall page`: http://peak.telecommunity.com/DevCenter/EasyInstall#installing-easy-install
+
+You need to download `ez_setup.py`_. Then, you run it like this to
+install ``easy_install`` into your system Python::
+
+  $ sudo python2.6 ez_setup.py
+
+.. _`ez_setup.py`: http://peak.telecommunity.com/dist/ez_setup.py
+
+This will make ``easy_install`` available to you.
+
+.. note:: Sometimes you have ``easy_install`` installed but you need a
+          newer version of the underlying setuptools infrastructure to
+          make Grok work. You can upgrade setuptools with::
+
+            $ sudo easy_install -U setuptools
+
+Now you can install `virtualenv` by doing (as root)::
+
+  # easy_install-2.6 virtualenv
+
+This step will fetch all needed sources from the internet and install
+`virtualenv` locally in your Python2.6 installation.
+
+
+Creating a sandbox
+------------------
+
+This step is only necessary (and recommended) if you installed
+`virtualenv` before.
+
+As a normal user you now can create a sandbox for your upcoming work
+by::
+
+  $ virtualenv --no-site-packages mysandbox
+
+where ``mysandbox`` is a directory in the filesystem where your
+sandbox will be created. `virtualenv` will also create this directory
+for you.
+
+By passing the ``no-site-packages`` switch we tell `virtualenv` to
+provide us a clean environment without any extra-packages installed
+systemwide.
+
+If you have a look into the freshly created sandbox, you will notice
+that in the ``bin/`` directory there is also 
+
+You now can activate the sandbox by doing::
+
+  $ source mysandbox/bin/activate
+
+You will notice that the input prompt changes.
+
+To deactivate the sandbox at any time, enter::
+
+  $ deactivate
+
+and the prompt will be the same as before the activation.
+
+For the following steps make sure the sandbox is active.
+
+
+Creating a working place
+------------------------
+
+In the sandbox (or anywhere else) we now create our real working
+environment. To do this, we change to the sandbox and checkout the
+sources of the WAeUP Kofa from the subversion server::
+
+  $ cd mysandbox/
+  $ svn co https://svn.waeup.org/repos/main/waeup.kofa/trunk waeup-trunk
+
+where ``waeup-trunk`` is only a name we've chosen here to make clear
+where the sources come from.
+
+This command should fetch the sources of the WAeUP sources for you and
+put it in the directory ``waeup-trunk/``.
+
+Now enter the new directory::
+
+  $ cd waeup-trunk
+
+
+Preparing the build
+-------------------
+
+In the sources directory (``waeup-trunk/``) you have to prepare the
+project to fetch needed components (eggs), compile C-code parts,
+etc. This steip will not touch any external projects::
+
+  $ python2.6 bootstrap.py
+
+This will generate some directories and the ``buildout`` script in
+``bin/`` for us. This step must be executed only once for each
+instance.
+
+Now we can do the real build by triggering::
+
+  $ bin/buildout
+
+If this is your first install of some Grok-related project, this step
+will need some time as lots of sources have to be fetched, many
+components must be compiled, etc.
+
+This step must be redone whenever you change something in
+``buildout.cfg`` or ``setup.py``.
+
+Afterwards we are ready to go.
+
+
+Start the instance
+------------------
+
+You should be able now to start the created instance by doing::
+
+   $ bin/zopectl fg
+
+If you now point a browser to::
+
+   localhost:8080
+
+you should get a login pop-up, where you can login as superuser with
+``grok`` and ``grok`` as username/password.
+
+If you want to change the default credentials, have a look into
+``buildout.cfg`` where the superuser password is determined.
+
+You can stop the instance by pressing <CTRL-C>.
+
+
+
+Documentation
+=============
+
+With the :mod:`waeup.kofa` package we try to reach high standards in
+both, documentation and testing.
+
+:mod:`waeup.kofa` makes extensive use of doctests, which this way also
+become both: executable (i.e. testable) examples and documentation.
+
+Generating documentation
+------------------------
+
+We use the excellent `Sphinx <http://sphinx.pocoo.org/>`_ Python
+documentation generator to generate the docs as HTML pages.
+
+The documentation of the :mod:`waeup.kofa` project can easily be
+created doing::
+
+  $ bin/waeupdocs
+
+This will create a tree of HTML pages in
+``parts/waeupdocs/waeup.kofa/build/waeup.kofa/`` which you can for
+instance browse by pointing your browser to this location.
+
+An 'official' place in internet for the whole docs is about to come
+but not yet available.
+
+
+Writing documentation
+---------------------
+
+means explaining to other developers what your code does and test it
+at the same time. See the many .txt files in the :mod:`waeup.kofa`
+package for examples.
+
+
+Testing
+=======
+
+Tests are most important to the reliability of the :mod:`waeup.kofa`
+package. We don't tell someone that our code works, if we cannot prove
+it. And we prove it by testing.
+
+Running tests
+-------------
+
+You can run all the tests for the package by doing::
+
+  $ bin/test
+
+If you like colored output (can improve readability of failure
+messages), use the ``-c`` switch::
+
+  $ bin/test -c
+
+We have many tests in the :mod:`waeup.kofa` package so that sometimes
+you only want the functional *or* the unit tests to run. This can be
+done like this::
+
+  $ bin/test -c -u
+
+if you want only unit tests or like this::
+
+  $ bin/test -c -f
+
+if you only want functional tests.
+
+
+Writing tests
+-------------
+
+Is a wiiide topic. For now, please see the numerous .txt files in the
+source. Most of the **are** tests.
+
+Generally, we use `z3c.testsetup` for finding and setting up tests.
+
+There are mainly two kinds of tests we use:
+
+* unit- or simple doctests
+
+  These are included in test runs automatically, if they provide a
+  marker like this somewhere (normally near top of file)::
+
+    .. :doctest:
+
+  Most unit tests furthermore declare that they want to be run inside
+  the `WAeUPKofaUnitTestLayer` defined in `waeup.kofa.testing`. This
+  layer groks the whole `waeup.kofa` package, so that all ZCA
+  components are already setup when you start your tests.
+  
+  To declare that a unit test testfile should be run inside this
+  layer, the testfile has to provide the following line::
+
+    .. :layer: waeup.kofa.testing.WAeUPKofaUnitTestLayer
+
+  Use it, if in your tests you make use of registered components like
+  utilities, adapters and the like.
+
+* integration or functional tests
+
+  These provide a full-blown ZODB storage, so that we can emulate
+  browser requests to the whole system. Functional tests are much more
+  expensive in terms of memory and runtime but needed, if you want to
+  test UI components.
+
+  A testfile is registered as functional test on testruns when it
+  provides a line like the following::
+
+    :Test-Layer: functional
+
+
+Code coverage
+-------------
+
+We want to make sure, that all aspects of our software are
+tested. This means, that all parts of the codes should be tested
+somewhere.
+
+To tell how good our test coverage is, we can also use the testrunner
+(``bin/test``)::
+
+  $ bin/test --coverage=coverage
+
+will run the tests but also look, which parts of code were touched by
+them. For releases we want 100% coverage. Beware: running tests with
+the ``--coverage`` switch slows down tests by factor 10 or more.
+
+The command above will output a table with percentages. Furthermore,
+in ``/parts/test/coverage`` you will (after the testrun) find your
+sources preceeded by markers which tell, how often (or none) a certain
+line was used in tests.
+
+To have a more convenient cmdline interface, we also provide some
+shortcuts::
+
+  $ bin/coverage-detect
+
+will run all the tests as shown above and put the results in
+``parts/coverage-detect/coverage``.
+
+After that you can run::
+
+  $ bin/coveragereport
+
+to get a browsable HTML representation of test coverage in
+``coverage-report/`` subdir.
+
+Both, the coverage reports and HTML documentation generated by sphinx
+can be packed and put onto a website as-is.
+
+It is also possible to generate the docs and reports nightly by a
+buildbot or something like this.
Index: main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/index.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/index.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/developerdocs/index.rst	(revision 8249)
@@ -0,0 +1,8 @@
+Developer Documentation
+***********************
+
+.. toctree::
+   :maxdepth: 2
+   
+   developernotes
+   api/index
Index: main/waeup.uniben/branches/uli-payments/docs/source/documentation.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/documentation.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/documentation.rst	(revision 8249)
@@ -0,0 +1,26 @@
+About these documents
+*********************
+
+These documents are generated from `reStructuredText
+<http://docutils.sf.net/rst.html>`_ sources by `Sphinx`_, an excellent
+document processor specifically written for the Python documentation
+by Georg Brandl and contributors.
+
+Development of this documentation is organized by Uli Fouquet (``uli
+at waeup dot org``) and Henrik Bettermann (``henrik at waeup dot
+org``). We're always looking for volunteers wanting to help with the
+docs, so feel free to send a mail there!
+
+Many thanks go to:
+
+* the `docutils <http://docutils.sf.net/>`_ project for creating
+  reStructuredText and the docutils suite;
+* Georg Brandl for his `sphinx` package.
+
+See :ref:`building_documentation` to learn how to create HTML or PDF
+versions of this docs.
+
+See :ref:`reporting-bugs` for information how to report bugs in
+`waeup.kofa` itself.
+
+.. _Sphinx: http://sphinx.org/
Index: main/waeup.uniben/branches/uli-payments/docs/source/glossary.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/glossary.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/glossary.rst	(revision 8249)
@@ -0,0 +1,16 @@
+.. _glossary:
+
+Glossary
+********
+
+.. glossary::
+
+   Kofa
+     Student Information and Registration Portal.
+
+   WAeUP
+     West African e-University Project.
+
+   waeup.kofa
+     A Python package explained in this documentation.
+
Index: main/waeup.uniben/branches/uli-payments/docs/source/index.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/index.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/index.rst	(revision 8249)
@@ -0,0 +1,11 @@
+.. WAeUP Student Information and Registration Portal (Kofa) documentation master file, created by
+   sphinx-quickstart on Thu Jul 29 10:41:59 2010.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   contents
Index: main/waeup.uniben/branches/uli-payments/docs/source/intro.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/intro.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/intro.rst	(revision 8249)
@@ -0,0 +1,1 @@
+.. include:: ../../README.txt
Index: main/waeup.uniben/branches/uli-payments/docs/source/license.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/license.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/license.rst	(revision 8249)
@@ -0,0 +1,11 @@
+.. _license:
+
+***********
+The License
+***********
+
+`waeup.kofa` is covered by the following license. If that license
+does not fit your needs and you need a copy of the software licensed
+differently, please contact ``henrik <at> waeup <dot> org``.
+
+.. literalinclude:: ../../LICENSE
Index: main/waeup.uniben/branches/uli-payments/docs/source/userdocs/buildingdocs.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/userdocs/buildingdocs.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/userdocs/buildingdocs.rst	(revision 8249)
@@ -0,0 +1,61 @@
+.. _building_documentation:
+
+Building Documentation (Linux OS only)
+**************************************
+
+To build the documentation for :mod:`waeup.kofa`, please follow these steps:
+
+Prerequisites
+=============
+
+We assume you already installed `waeup.kofa` as explained in
+:ref:`installing_linux`. You ran ``bin/buildout`` and can find a script
+``bin/waeupdocs``.
+
+Building HTML docs
+==================
+
+After successful install go to the root dir, where `waeup.kofa` is
+located.
+
+There run::
+
+   $ ./bin/waeupdocs
+
+This will (re-)generate any needed docs.
+
+The output can be found in ``docs/build/html``.
+
+Actually, ``waeupdocs`` is only a wrapper script around the real main
+script ``sphinx-build``, which should also be located in your ``bin/``
+directory.
+
+You therefore can also run ``bin/sphinx-build`` manually, which will
+give you more options, especially, if you want the output to be
+created in a different location or similar.
+
+Run::
+
+   $ ./bin/sphinx-build --help
+
+to get a list of options available.
+
+Alternatively, you can also go to ``docs/build`` and run::
+
+   $ make html
+
+Other available formats are listed, when you run only::
+
+   $ make
+
+These other formats will include ``latex``, ``doctest``, ``linkcheck``
+and more with a short explanation for each format.
+
+
+Building PDF docs
+=================
+
+We're currently not prepared for PDF, but support is already planned.
+
+Please be aware, that any PDF support will require a full TeX
+installation on your system to work.
Index: main/waeup.uniben/branches/uli-payments/docs/source/userdocs/index.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/userdocs/index.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/userdocs/index.rst	(revision 8249)
@@ -0,0 +1,9 @@
+User Documentation
+******************
+
+.. toctree::
+   :maxdepth: 2
+
+   install
+   install_on_windows
+   buildingdocs
Index: main/waeup.uniben/branches/uli-payments/docs/source/userdocs/install.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/userdocs/install.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/userdocs/install.rst	(revision 8249)
@@ -0,0 +1,3 @@
+.. _installing_linux:
+
+.. include:: ../../INSTALL.txt
Index: main/waeup.uniben/branches/uli-payments/docs/source/userdocs/install_on_windows.rst
===================================================================
--- main/waeup.uniben/branches/uli-payments/docs/source/userdocs/install_on_windows.rst	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/docs/source/userdocs/install_on_windows.rst	(revision 8249)
@@ -0,0 +1,3 @@
+.. _installing_win:
+
+.. include:: ../../INSTALLWIN.txt
Index: main/waeup.uniben/branches/uli-payments/etc/README.txt
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/README.txt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/README.txt	(revision 8249)
@@ -0,0 +1,26 @@
+In this directory you can find templates which are used by
+``zc.buildout`` to create the configuration files in the parts/etc/ subdir
+of your project.
+
+If you modify files in this directory, you have to run::
+
+  $ bin/buildout
+
+afterwards to rebuild the configuration files in parts/etc/.
+
+In the templates you can use placesholders recognized by zc.buildout
+to name local paths, etc. A zc.buildout placeholder looks like this::
+
+  ${buildout:directory}
+
+which gives you the path of the project directory and will be
+substituted with the real path when you run buildout the next
+time. The set of available placeholders depends on your
+buildout.cfg.
+
+You can also modify files in parts/etc directly, but those changes
+will be overwritten after running bin/buildout the next time.
+
+To run your project you can do::
+
+  $ bin/paster serve parts/etc/deploy.ini
Index: main/waeup.uniben/branches/uli-payments/etc/debug.ini.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/debug.ini.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/debug.ini.in	(revision 8249)
@@ -0,0 +1,67 @@
+# debug.ini
+#
+# Debugging configuration for use with paster/WSGI
+#
+
+[loggers]
+keys = root, wsgi
+
+[handlers]
+keys = console, accesslog
+
+[formatters]
+keys = generic, accesslog
+
+[formatter_generic]
+format = %(asctime)s %(levelname)s [%(name)s] %(message)s
+
+[formatter_accesslog]
+format = %(message)s
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[handler_accesslog]
+class = FileHandler
+args = (os.path.join(r'${zope_conf:logfiles}', 'access.log'),
+        'a')
+level = INFO
+formatter = accesslog
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_wsgi]
+level = INFO
+handlers = accesslog
+qualname = wsgi
+propagate = 0
+
+[filter:translogger]
+use = egg:Paste#translogger
+setup_console_handler = False
+logger_name = wsgi
+
+[filter-app:main]
+# Change the last part from 'ajax' to 'pdb' for a post-mortem debugger
+# on the console:
+use = egg:z3c.evalexception#ajax
+next = zope
+
+[app:zope]
+use = egg:waeup.uniben#debug
+filter-with = translogger
+exempt-exceptions = zope.security.interfaces.IUnauthorized
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 8080
+
+[DEFAULT]
+# set the name of the zope.conf file
+zope_conf = %(here)s/zope.conf
Index: main/waeup.uniben/branches/uli-payments/etc/deploy.ini.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/deploy.ini.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/deploy.ini.in	(revision 8249)
@@ -0,0 +1,60 @@
+# deploy.ini
+#
+# Deployment configuration for use with paster/WSGI
+#
+
+[loggers]
+keys = root, wsgi
+
+[handlers]
+keys = console, accesslog
+
+[formatters]
+keys = generic, accesslog
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_wsgi]
+level = INFO
+handlers = accesslog
+qualname = wsgi
+propagate = 0
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[handler_accesslog]
+class = FileHandler
+args = (os.path.join(r'${zope_conf:logfiles}', 'access.log'),
+        'a')
+level = INFO
+formatter = accesslog
+
+[formatter_generic]
+format = %(asctime)s %(levelname)s [%(name)s] %(message)s
+
+[formatter_accesslog]
+format = %(message)s
+
+[filter:translogger]
+use = egg:Paste#translogger
+setup_console_handler = False
+logger_name = wsgi
+
+[app:main]
+use = egg:waeup.uniben
+filter-with = translogger
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 8080
+
+[DEFAULT]
+# set the name of the zope.conf file
+zope_conf = %(here)s/zope.conf
Index: main/waeup.uniben/branches/uli-payments/etc/profile.ini.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/profile.ini.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/profile.ini.in	(revision 8249)
@@ -0,0 +1,66 @@
+# profile.ini
+#
+# Profiling configuration for use with paster/WSGI
+#
+# Call http://localhost:8080/__profile__ to see the profiler in action
+
+[loggers]
+keys = root, wsgi
+
+[handlers]
+keys = console, accesslog
+
+[formatters]
+keys = generic, accesslog
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_wsgi]
+level = INFO
+handlers = accesslog
+qualname = wsgi
+propagate = 0
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[handler_accesslog]
+class = FileHandler
+args = (os.path.join(r'${zope_conf:logfiles}', 'access.log'),
+        'a')
+level = INFO
+formatter = accesslog
+
+[formatter_generic]
+format = %(asctime)s %(levelname)s [%(name)s] %(message)s
+
+[formatter_accesslog]
+format = %(message)s
+
+[filter:translogger]
+use = egg:Paste#translogger
+setup_console_handler = False
+logger_name = wsgi
+
+[filter:profiler]
+use = egg:repoze.profile#profile
+
+[app:app]
+use = egg:waeup.uniben
+
+[pipeline:main]
+pipeline = translogger profiler app
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 8080
+
+[DEFAULT]
+# set the name of the zope.conf file
+zope_conf = %(here)s/zope.conf
Index: main/waeup.uniben/branches/uli-payments/etc/site.zcml.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/site.zcml.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/site.zcml.in	(revision 8249)
@@ -0,0 +1,49 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:kofa="http://namespaces.waeup.org/kofa"
+           i18n_domain="waeup.uniben">
+
+  <include package="waeup.uniben" />
+  <include package="waeup.uniben" file="mail.zcml" />
+
+  <!-- Where should the datacenter reside by default? -->
+  <kofa:datacenter
+      path="${buildout:directory}/var/datacenter" />
+
+    <configure i18n_domain="waeup.uniben">
+
+      <unauthenticatedPrincipal id="zope.anybody"
+                                title="Unauthenticated User" />
+      <unauthenticatedGroup id="zope.Anybody"
+                            title="Unauthenticated Users" />
+      <authenticatedGroup id="zope.Authenticated"
+                        title="Authenticated Users" />
+      <everybodyGroup id="zope.Everybody"
+                      title="All Users" />
+      <principal id="zope.manager"
+                 title="Manager"
+                 login="grok"
+                 password_manager="SHA1"
+                 password="321b9cd3739bd029629243732eb682db005a7541f7509622"
+                 />
+
+      <!-- Replace the following directive if you do not want
+           public access -->
+      <grant permission="zope.app.dublincore.view"
+             principal="zope.Anybody" />
+      <grant permission="zope.View"
+             principal="zope.Authenticated" />
+      <grant permission="zope.app.dublincore.view"
+             principal="zope.Authenticated" />
+      <grant permission="waeup.Public"
+             principal="zope.Everybody" />
+      <grant permission="waeup.Anonymous"
+             principal="zope.Anybody" />
+      <grant permission="waeup.Authenticated"
+             principal="zope.Authenticated" />
+
+      <role id="zope.Manager" title="Site Manager" />
+      <grantAll role="zope.Manager" />
+      <grant role="zope.Manager"
+             principal="zope.manager" />
+   </configure>
+</configure>
Index: main/waeup.uniben/branches/uli-payments/etc/zdaemon.conf.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zdaemon.conf.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zdaemon.conf.in	(revision 8249)
@@ -0,0 +1,8 @@
+<runner>
+  program ${buildout:directory}/bin/paster serve ${buildout:directory}/parts/etc/deploy.ini
+  daemon on
+  transcript ${zope_conf:logfiles}/zdaemon.log
+  socket-name ${zope_conf:logfiles}/zdaemonsock
+  # Enable this to run the child process as a different user
+  # user zope
+</runner>
Index: main/waeup.uniben/branches/uli-payments/etc/zeo1.conf.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zeo1.conf.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zeo1.conf.in	(revision 8249)
@@ -0,0 +1,8 @@
+<runner>
+  program ${buildout:directory}/bin/paster serve --pid-file ${buildout:directory}/var/zeo1.pid ${buildout:directory}/parts/etc/zeo1.ini
+  daemon on
+  transcript ${zope_conf:logfiles}/zdaemon-zeo1.log
+  socket-name ${zope_conf:logfiles}/zeo1.sock
+  # Enable this to run the child process as a different user
+  # user zope
+</runner>
Index: main/waeup.uniben/branches/uli-payments/etc/zeo1.ini.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zeo1.ini.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zeo1.ini.in	(revision 8249)
@@ -0,0 +1,62 @@
+# deploy.ini
+#
+# Deployment configuration for use with paster/WSGI
+#
+
+[loggers]
+keys = root, wsgi
+
+[handlers]
+keys = console, accesslog
+
+[formatters]
+keys = generic, accesslog
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_wsgi]
+level = INFO
+handlers = accesslog
+qualname = wsgi
+propagate = 0
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[handler_accesslog]
+class = FileHandler
+args = (os.path.join(r'${zope_conf:logfiles}', 'zeo1.log'),
+        'a')
+level = INFO
+formatter = accesslog
+
+[formatter_generic]
+format = %(asctime)s %(levelname)s [%(name)s] %(message)s
+
+[formatter_accesslog]
+format = %(message)s
+
+[filter:translogger]
+use = egg:Paste#translogger
+setup_console_handler = False
+logger_name = wsgi
+
+[app:main]
+use = egg:waeup.uniben
+filter-with = translogger
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 7011
+threadpool_workers = 50
+use_threadpool = True
+
+[DEFAULT]
+# set the name of the zope.conf file
+zope_conf = %(here)s/zope_zeo1.conf
Index: main/waeup.uniben/branches/uli-payments/etc/zeo2.conf.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zeo2.conf.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zeo2.conf.in	(revision 8249)
@@ -0,0 +1,8 @@
+<runner>
+  program ${buildout:directory}/bin/paster serve --pid-file ${buildout:directory}/var/zeo2.pid ${buildout:directory}/parts/etc/zeo2.ini
+  daemon on
+  transcript ${zope_conf:logfiles}/zdaemon-zeo2.log
+  socket-name ${zope_conf:logfiles}/zeo2.sock
+  # Enable this to run the child process as a different user
+  # user zope
+</runner>
Index: main/waeup.uniben/branches/uli-payments/etc/zeo2.ini.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zeo2.ini.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zeo2.ini.in	(revision 8249)
@@ -0,0 +1,62 @@
+# deploy.ini
+#
+# Deployment configuration for use with paster/WSGI
+#
+
+[loggers]
+keys = root, wsgi
+
+[handlers]
+keys = console, accesslog
+
+[formatters]
+keys = generic, accesslog
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_wsgi]
+level = INFO
+handlers = accesslog
+qualname = wsgi
+propagate = 0
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[handler_accesslog]
+class = FileHandler
+args = (os.path.join(r'${zope_conf:logfiles}', 'zeo2.log'),
+        'a')
+level = INFO
+formatter = accesslog
+
+[formatter_generic]
+format = %(asctime)s %(levelname)s [%(name)s] %(message)s
+
+[formatter_accesslog]
+format = %(message)s
+
+[filter:translogger]
+use = egg:Paste#translogger
+setup_console_handler = False
+logger_name = wsgi
+
+[app:main]
+use = egg:waeup.uniben
+filter-with = translogger
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 7012
+threadpool_workers = 50
+use_threadpool = True
+
+[DEFAULT]
+# set the name of the zope.conf file
+zope_conf = %(here)s/zope_zeo2.conf
Index: main/waeup.uniben/branches/uli-payments/etc/zope.conf.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zope.conf.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zope.conf.in	(revision 8249)
@@ -0,0 +1,55 @@
+# Identify the component configuration used to define the site:
+site-definition ${site_zcml:output}
+
+<zodb>
+  # Standard blob storage
+  <blobstorage>
+    blob-dir ${zope_conf:blobstorage}
+    <filestorage>
+      path ${zope_conf:filestorage}/Data.fs
+    </filestorage>
+  </blobstorage>
+
+# Uncomment this if you want a blob-less standard file storage instead:
+#  <filestorage>
+#       path ${zope_conf:filestorage}
+#  </filestorage>
+
+# Uncomment this if you want to connect to a ZEO server instead:
+#  <zeoclient>
+#    server localhost:8100
+#    storage 1
+#    # ZEO client cache, in bytes
+#    cache-size 20MB
+#    # Uncomment to have a persistent disk cache
+#    #client zeo1
+#  </zeoclient>
+
+</zodb>
+
+<eventlog>
+  # This sets up logging to a file.
+  # The "path" setting can be a relative or absolute
+  # filesystem path.
+
+  <logfile>
+    path ${zope_conf:logfiles}/z3.log
+    formatter zope.exceptions.log.Formatter
+  </logfile>
+
+  # This sets up logging to to standard output.
+  # The "path" setting can be the tokens STDOUT or STDERR
+  
+#  <logfile>
+#    path STDOUT
+#    formatter zope.exceptions.log.Formatter
+#  </logfile>
+</eventlog>
+
+# Comment this line to disable developer mode.  This should be done in
+# production
+devmode on
+
+# Extra configuration lines can be added to zope_conf's extra option. Put for 
+# instance productconf sections in here.
+${zope_conf:extra}
Index: main/waeup.uniben/branches/uli-payments/etc/zope_zeo1.conf.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zope_zeo1.conf.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zope_zeo1.conf.in	(revision 8249)
@@ -0,0 +1,88 @@
+# Identify the component configuration used to define the site:
+site-definition ${site_zcml:output}
+
+<zodb>
+
+  #cache-size
+
+  # num of concurrent pre-opened ZODB threads; default: 7
+  pool-size 25
+
+  # Standard blob storage
+#  <blobstorage>
+#    blob-dir ${zope_conf:blobstorage}
+#    <filestorage>
+#      path ${zope_conf:filestorage}/Data.fs
+#    </filestorage>
+#  </blobstorage>
+
+# Uncomment this if you want a blob-less standard file storage instead:
+#  <filestorage>
+#       path ${zope_conf:filestorage}
+#  </filestorage>
+
+# Uncomment this if you want to connect to a ZEO server instead:
+  <zeoclient>
+    server localhost:7010
+    storage 1
+    # ZEO client cache, in bytes
+    cache-size 20MB
+    # Uncomment to have a persistent disk cache
+    client ${zope_conf_zeo_1:filestorage}/zeo1
+  </zeoclient>
+
+# Uncomment this if you want to run a ZEO server instead:
+#  <zeo>
+#    # required; 'host:port' for TCP/IP, path to a socket file for UDP
+#    address localhost:8090
+#
+#    # optional; 'address' remarks apply
+#    #monitor-address localhost:8091
+#
+#    # optional; keep queue of last N transactions. Speeds up client cache verif.
+#    #invalidation-queue-size 10
+#
+#    # optional; is this a read-only instance? true or false
+#    #read-only false
+#
+#    # optional; seconds to wait for client to commit after acquiring lock
+#    #transaction-timeout 20
+#
+#    # optional; authentication protocol. With ZEO only 'digest' supported
+#    #authentication-protocol digest 
+#
+#    # optional; Path of the database containing authentication credentials.
+#    #authentication-database
+#
+#    # optional; the authentication realm of server
+#    #authentication-realm myrealm
+#  </zeo>
+
+</zodb>
+
+<eventlog>
+  # This sets up logging to a file.
+  # The "path" setting can be a relative or absolute
+  # filesystem path.
+
+  <logfile>
+    path ${zope_conf:logfiles}/zeo1_z3.log
+    formatter zope.exceptions.log.Formatter
+  </logfile>
+
+  # This sets up logging to to standard output.
+  # The "path" setting can be the tokens STDOUT or STDERR
+  
+#  <logfile>
+#    path STDOUT
+#    formatter zope.exceptions.log.Formatter
+#  </logfile>
+</eventlog>
+
+# Comment this line to disable developer mode.  This should be done in
+# production
+#devmode on
+
+# Extra configuration lines can be added to zope_conf's extra option. Put for 
+# instance productconf sections in here.
+${zope_conf:extra}
Index: main/waeup.uniben/branches/uli-payments/etc/zope_zeo2.conf.in
===================================================================
--- main/waeup.uniben/branches/uli-payments/etc/zope_zeo2.conf.in	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/etc/zope_zeo2.conf.in	(revision 8249)
@@ -0,0 +1,88 @@
+# Identify the component configuration used to define the site:
+site-definition ${site_zcml:output}
+
+<zodb>
+
+  #cache-size
+
+  # num of concurrent pre-opened ZODB threads; default: 7
+  pool-size 7
+
+  # Standard blob storage
+#  <blobstorage>
+#    blob-dir ${zope_conf:blobstorage}
+#    <filestorage>
+#      path ${zope_conf:filestorage}/Data.fs
+#    </filestorage>
+#  </blobstorage>
+
+# Uncomment this if you want a blob-less standard file storage instead:
+#  <filestorage>
+#       path ${zope_conf:filestorage}
+#  </filestorage>
+
+# Uncomment this if you want to connect to a ZEO server instead:
+  <zeoclient>
+    server localhost:7010
+    storage 1
+    # ZEO client cache, in bytes
+    cache-size 20MB
+    # Uncomment to have a persistent disk cache
+    client ${zope_conf_zeo_2:filestorage}/zeo2
+  </zeoclient>
+
+# Uncomment this if you want to run a ZEO server instead:
+#  <zeo>
+#    # required; 'host:port' for TCP/IP, path to a socket file for UDP
+#    address localhost:8090
+#
+#    # optional; 'address' remarks apply
+#    #monitor-address localhost:8091
+#
+#    # optional; keep queue of last N transactions. Speeds up client cache verif.
+#    #invalidation-queue-size 10
+#
+#    # optional; is this a read-only instance? true or false
+#    #read-only false
+#
+#    # optional; seconds to wait for client to commit after acquiring lock
+#    #transaction-timeout 20
+#
+#    # optional; authentication protocol. With ZEO only 'digest' supported
+#    #authentication-protocol digest 
+#
+#    # optional; Path of the database containing authentication credentials.
+#    #authentication-database
+#
+#    # optional; the authentication realm of server
+#    #authentication-realm myrealm
+#  </zeo>
+
+</zodb>
+
+<eventlog>
+  # This sets up logging to a file.
+  # The "path" setting can be a relative or absolute
+  # filesystem path.
+
+  <logfile>
+    path ${zope_conf:logfiles}/zeo2_z3.log
+    formatter zope.exceptions.log.Formatter
+  </logfile>
+
+  # This sets up logging to to standard output.
+  # The "path" setting can be the tokens STDOUT or STDERR
+  
+#  <logfile>
+#    path STDOUT
+#    formatter zope.exceptions.log.Formatter
+#  </logfile>
+</eventlog>
+
+# Comment this line to disable developer mode.  This should be done in
+# production
+#devmode on
+
+# Extra configuration lines can be added to zope_conf's extra option. Put for 
+# instance productconf sections in here.
+${zope_conf:extra}
Index: main/waeup.uniben/branches/uli-payments/setup.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/setup.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/setup.py	(revision 8249)
@@ -0,0 +1,99 @@
+import os
+from setuptools import setup, find_packages
+
+version = '0.1dev'
+
+install_requires =[
+    'setuptools',
+    'grok',
+    'grokui.admin',
+    'grokcore.startup',
+    'waeup.kofa',
+    ],
+
+# Having beaker installed additionally is a feature very recommended
+# for production use. The default buildout includes beaker for tests,
+# start scripts, and other parts that can benefit from it. The windows
+# buildout does not include it due to compiling problems with the
+# beaker package.
+beaker_require = [
+    'dolmen.beaker',
+    ]
+
+tests_require = [
+    'z3c.testsetup',
+    'zope.app.testing',
+    'zope.testbrowser',
+    'zope.testing',
+    'unittest2',
+    ]
+
+docs_require = [
+    'Sphinx',
+    'collective.recipe.sphinxbuilder',
+    'docutils',
+    'roman',
+    'repoze.sphinx.autointerface',
+    ]
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+    read('README.txt')
+    + '\n\n'
+    + read('src', 'waeup', 'uniben', 'README.txt')
+    + '\n\n'
+    + read('CHANGES.txt')
+    + '\n\n'
+    + 'Download\n'
+    + '********\n'
+    )
+
+setup(name = 'waeup.uniben',
+      version = version,
+      description = "A customized waeup.kofa",
+      long_description = long_description,
+
+      keywords = "portal waeup kofa student university registration grok zope",
+      # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      classifiers = [
+        'Development Status :: 3 - Alpha',
+        'Environment :: Web Environment',
+        'Intended Audience :: Education',
+        'License :: OSI Approved :: GNU General Public License (GPL)',
+        'Programming Language :: Python',
+        'Operating System :: POSIX',
+        'Operating System :: POSIX :: Linux',
+        'Framework :: Zope3',
+        'Topic :: Education',
+        'Topic :: Internet :: WWW/HTTP',
+        ],
+      author = "The WAeUP team.",
+      author_email = "",
+      url = "http://www.waeup.org/",
+      license = "GPL",
+      package_dir = {'': 'src'},
+      packages= find_packages('src'),
+      namespace_packages = ['waeup',],
+      include_package_data = True,
+      zip_safe = False,
+      install_requires = install_requires,
+      tests_require = tests_require,
+      extras_require = dict(
+        test = tests_require,
+        docs = docs_require,
+        beaker = beaker_require,
+        ),
+      entry_points="""
+      # Add entry points here
+      [hurry.resource.libraries]
+      waeup_uniben = waeup.uniben.browser.resources:waeup_uniben
+      [console_scripts]
+      kofa-debug = grokcore.startup:interactive_debug_prompt
+      kofactl = grokcore.startup:zdaemon_controller
+      [paste.app_factory]
+      main = grokcore.startup:application_factory
+      debug = grokcore.startup:debug_application_factory
+      """,
+      )
Index: main/waeup.uniben/branches/uli-payments/src/waeup/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/__init__.py	(revision 8249)
@@ -0,0 +1,23 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError, e:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/README.txt
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/README.txt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/README.txt	(revision 8249)
@@ -0,0 +1,4 @@
+The waeup.uniben package
+************************
+
+A customized portal software for student registration.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/applicant.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/applicant.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/applicant.py	(revision 8249)
@@ -0,0 +1,45 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+import grok
+from zope.interface import implementedBy
+from waeup.kofa.applicants.applicant import Applicant, ApplicantFactory
+from waeup.kofa.utils.helpers import attrs_to_fields
+from waeup.uniben.applicants.interfaces import(
+    ICustomApplicant, IUGApplicantEdit, IPGApplicantEdit)
+
+class CustomApplicant(Applicant):
+
+    grok.implements(ICustomApplicant, IUGApplicantEdit, IPGApplicantEdit)
+    grok.provides(ICustomApplicant)
+
+# Set all attributes of Applicant required in IApplicant as field
+# properties. Doing this, we do not have to set initial attributes
+# ourselves and as a bonus we get free validation when an attribute is
+# set.
+CustomApplicant = attrs_to_fields(CustomApplicant)
+
+class CustomApplicantFactory(ApplicantFactory):
+    """A factory for customized applicants.
+    """
+
+    def __call__(self, *args, **kw):
+        return CustomApplicant()
+
+    def getInterfaces(self):
+        return implementedBy(CustomApplicant)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/browser.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/browser.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/browser.py	(revision 8249)
@@ -0,0 +1,144 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""UI components for basic applicants and related components.
+"""
+import grok
+from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
+from waeup.kofa.applicants.interfaces import (
+    IApplicantRegisterUpdate, IApplicant, IApplicantEdit)
+from waeup.kofa.applicants.browser import (ApplicantDisplayFormPage,
+    OnlinePaymentCallbackPage, ExportPDFPage,
+    ApplicantManageFormPage, ApplicantEditFormPage,
+    ApplicantRegistrationPage, ApplicantAddFormPage,
+    OnlinePaymentDisplayFormPage, AcceptanceFeePaymentAddPage,
+    OnlinePaymentBreadcrumb)
+from waeup.kofa.applicants.viewlets import RequestCallbackActionButton
+from waeup.kofa.applicants.pdf import PDFApplicationSlip
+from waeup.uniben.applicants.interfaces import (
+    IPGApplicant, IUGApplicant, IPGApplicantEdit, IUGApplicantEdit,
+    ICustomApplicantOnlinePayment)
+from waeup.uniben.interfaces import MessageFactory as _
+
+#class RequestCallbackActionButton(RequestCallbackActionButton):
+#    """ Do not display the base package callback button in custom pages.
+#    """
+#    @property
+#    def target_url(self):
+#        return ''
+
+#class CustomOnlinePaymentCallbackPage(OnlinePaymentCallbackPage):
+#    """ Neutralize callback simulation view
+#    """
+#    def update(self):
+#        return
+
+class CustomOnlinePaymentBreadcrumb(OnlinePaymentBreadcrumb):
+    """A breadcrumb for payments.
+    """
+    grok.context(ICustomApplicantOnlinePayment)
+
+class CustomPDFApplicationSlip(PDFApplicationSlip):
+
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        if target is not None and target.startswith('pg'):
+            form_fields = grok.AutoFields(IPGApplicant).omit(
+                'locked', 'course_admitted')
+        else:
+            form_fields = grok.AutoFields(IUGApplicant).omit(
+                'locked', 'course_admitted')
+        return form_fields
+
+class CustomApplicantDisplayFormPage(ApplicantDisplayFormPage):
+    """A display view for applicant data.
+    """
+
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        if target is not None and target.startswith('pg'):
+            form_fields = grok.AutoFields(IPGApplicant).omit(
+                'locked', 'course_admitted', 'password')
+        else:
+            form_fields = grok.AutoFields(IUGApplicant).omit(
+                'locked', 'course_admitted', 'password')
+        return form_fields
+
+class CustomApplicantManageFormPage(ApplicantManageFormPage):
+    """A full edit view for applicant data.
+    """
+    
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        if target is not None and target.startswith('pg'):
+            form_fields = grok.AutoFields(IPGApplicant)
+        else:
+            form_fields = grok.AutoFields(IUGApplicant)
+        form_fields['student_id'].for_display = True
+        form_fields['applicant_id'].for_display = True
+        return form_fields
+
+class CustomApplicantEditFormPage(ApplicantEditFormPage):
+    """An applicant-centered edit view for applicant data.
+    """
+
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        if target is not None and target.startswith('pg'):
+            form_fields = grok.AutoFields(IPGApplicantEdit).omit(
+                'locked', 'course_admitted', 'student_id',
+                'screening_score', 'screening_venue'
+                )
+        else:
+            form_fields = grok.AutoFields(IUGApplicantEdit).omit(
+                'locked', 'course_admitted', 'student_id',
+                'screening_score'
+                )
+        form_fields['applicant_id'].for_display = True
+        form_fields['reg_number'].for_display = True
+        return form_fields
+
+class CustomOnlinePaymentDisplayFormPage(OnlinePaymentDisplayFormPage):
+    """ Page to view an online payment ticket
+    """
+    grok.context(ICustomApplicantOnlinePayment)
+    form_fields = grok.AutoFields(ICustomApplicantOnlinePayment)
+    form_fields[
+        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
+    form_fields[
+        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
+    grok.template('payment_view')
+
+    @property
+    def transaction_code(self):
+        tcode = self.context.p_id
+        return tcode[len(tcode)-8:len(tcode)]
+
+class CustomAcceptanceFeePaymentAddPage(AcceptanceFeePaymentAddPage):
+    """ Page to add an online payment ticket
+    """
+    factory = u'waeup.CustomApplicantOnlinePayment'
+
+    def _fillCustomFields(self, payment, session_config):
+        payment.surcharge_1 = session_config.surcharge_1
+        payment.surcharge_2 = session_config.surcharge_2
+        payment.surcharge_3 = session_config.surcharge_3
+        return payment
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/browser_templates/payment_view.pt
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/browser_templates/payment_view.pt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/browser_templates/payment_view.pt	(revision 8249)
@@ -0,0 +1,18 @@
+<table class="form-table" i18n:domain="waeup.uniben"
+  tal:define="files provider:files">
+  <tbody>
+    <tal:widgets content="structure provider:widgets" />
+    <tr tal:condition="python: files.replace('\n','')">
+      <td class="separator" colspan=2 i18n:translate="">
+        Uploaded Files
+      </td>
+    </tr>
+    <tal:files content="structure files" />
+    <tr>
+      <td class="fieldname">
+        <span i18n:translate="">Transaction Code</span>:
+      </td>
+      <td tal:content="view/transaction_code">TRANSACTIONCODE</td>
+    </tr>
+  </tbody>
+</table>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/export.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/export.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/export.py	(revision 8249)
@@ -0,0 +1,33 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Exporters for applicant-related stuff.
+"""
+import grok
+from waeup.kofa.applicants.interfaces import IApplicantBaseData
+from waeup.kofa.applicants.export import ApplicantsExporter
+from waeup.uniben.applicants.interfaces import IUGApplicant, IPGApplicant
+
+class CustomApplicantsExporter(ApplicantsExporter):
+    """Exporter for Uniben Applicants.
+    """
+
+    fields = tuple(sorted(set(
+        IUGApplicant.names() +
+        IPGApplicant.names() +
+        IApplicantBaseData.names()
+        )))
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/interfaces.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/interfaces.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/interfaces.py	(revision 8249)
@@ -0,0 +1,266 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Customized interfaces of the university application package.
+"""
+
+from zope import schema
+from waeup.kofa.applicants.interfaces import (
+    IApplicantBaseData,
+    AppCatCertificateSource, CertificateSource)
+from waeup.kofa.schoolgrades import ResultEntryField
+from waeup.kofa.interfaces import SimpleKofaVocabulary, academic_sessions_vocab
+from waeup.kofa.schema import FormattedDate
+from waeup.kofa.students.vocabularies import nats_vocab
+from waeup.uniben.interfaces import (
+    lgas_vocab, high_qual, high_grade, exam_types)
+from waeup.uniben.interfaces import MessageFactory as _
+from waeup.uniben.payments.interfaces import ICustomOnlinePayment
+
+class IUGApplicant(IApplicantBaseData):
+    """An undergraduate applicant.
+
+    """
+
+    nationality = schema.Choice(
+        source = nats_vocab,
+        title = _(u'Nationality'),
+        required = False,
+        )
+    lga = schema.Choice(
+        source = lgas_vocab,
+        title = _(u'State/LGA (Nigerians only)'),
+        required = False,
+        )
+
+# This ordering doesn't work properly.
+IUGApplicant[
+    'nationality'].order =  IApplicantBaseData['sex'].order
+IUGApplicant[
+    'lga'].order =  IUGApplicant['nationality'].order
+
+
+class IPGApplicant(IApplicantBaseData):
+    """A postgraduate applicant.
+
+    """
+
+    nationality = schema.Choice(
+        source = nats_vocab,
+        title = _(u'Nationality'),
+        required = False,
+        )
+    lga = schema.Choice(
+        source = lgas_vocab,
+        title = _(u'State/LGA (Nigerians only)'),
+        required = False,
+        )
+    perm_address = schema.Text(
+        title = _(u'Permanent Address'),
+        required = False,
+        )
+    course1 = schema.Choice(
+        title = _(u'1st Choice Course of Study'),
+        source = AppCatCertificateSource(),
+        required = True,
+        )
+    course2 = schema.Choice(
+        title = _(u'2nd Choice Course of Study'),
+        source = AppCatCertificateSource(),
+        required = False,
+        )
+    hq_type = schema.Choice(
+        title = _(u'Qualification Obtained'),
+        required = False,
+        readonly = False,
+        vocabulary = high_qual,
+        )
+    hq_matric_no = schema.TextLine(
+        title = _(u'Former Matric Number'),
+        required = False,
+        readonly = False,
+        )
+    hq_degree = schema.Choice(
+        title = _(u'Class of Degree'),
+        required = False,
+        readonly = False,
+        vocabulary = high_grade,
+        )
+    hq_school = schema.TextLine(
+        title = _(u'Institution Attended'),
+        required = False,
+        readonly = False,
+        )
+    hq_session = schema.TextLine(
+        title = _(u'Years Attended'),
+        required = False,
+        readonly = False,
+        )
+    hq_disc = schema.TextLine(
+        title = _(u'Discipline'),
+        required = False,
+        readonly = False,
+        )
+    pp_school = schema.Choice(
+        title = _(u'Qualification Obtained'),
+        required = False,
+        readonly = False,
+        vocabulary = exam_types,
+        )
+    #presently = schema.Bool(
+    #    title = _(u'Attending'),
+    #    required = False,
+    #    readonly = False,
+    #    )
+    presently_inst = schema.TextLine(
+        title = _(u'If yes, name of institution'),
+        required = False,
+        readonly = False,
+        )
+    nysc_year = schema.Int(
+        title = _(u'Nysc Year'),
+        required = False,
+        readonly = False,
+        )
+    nysc_lga = schema.Choice(
+        source = lgas_vocab,
+        title = _(u'Nysc Location'),
+        required = False,
+        )
+    employer = schema.TextLine(
+        title = _(u'Employer'),
+        required = False,
+        readonly = False,
+        )
+    emp_position = schema.TextLine(
+        title = _(u'Employer Position'),
+        required = False,
+        readonly = False,
+        )
+    emp_start = FormattedDate(
+        title = _(u'Start Date'),
+        required = False,
+        readonly = False,
+        )
+    emp_end = FormattedDate(
+        title = _(u'End Date'),
+        required = False,
+        readonly = False,
+        )
+    emp_reason = schema.TextLine(
+        title = _(u'Reason for Leaving'),
+        required = False,
+        readonly = False,
+        )
+    employer2 = schema.TextLine(
+        title = _(u'2nd Employer'),
+        required = False,
+        readonly = False,
+        )
+    emp2_position = schema.TextLine(
+        title = _(u'2nd Employer Position'),
+        required = False,
+        readonly = False,
+        )
+    emp2_start = FormattedDate(
+        title = _(u'Start Date'),
+        required = False,
+        readonly = False,
+        )
+    emp2_end = FormattedDate(
+        title = _(u'End Date'),
+        required = False,
+        readonly = False,
+        )
+    emp2_reason = schema.TextLine(
+        title = _(u'Reason for Leaving'),
+        required = False,
+        readonly = False,
+        )
+    notice = schema.Text(
+        title = _(u'Notice'),
+        required = False,
+        readonly = False,
+        )
+    screening_venue = schema.TextLine(
+        title = _(u'Screening Venue'),
+        required = False,
+        readonly = False,
+        )
+    screening_score = schema.Int(
+        title = _(u'Screening Score'),
+        required = False,
+        readonly = False,
+        )
+    course_admitted = schema.Choice(
+        title = _(u'Admitted Course of Study'),
+        source = CertificateSource(),
+        required = False,
+        readonly = False,
+        )
+
+
+# This ordering doesn't work properly.
+IPGApplicant[
+    'nationality'].order =  IApplicantBaseData['sex'].order
+IPGApplicant[
+    'lga'].order =  IPGApplicant['nationality'].order
+IPGApplicant[
+    'student_id'].order =  IPGApplicant['notice'].order
+
+
+class ICustomApplicant(IUGApplicant,IPGApplicant):
+    """An interface for both types of applicants.
+
+    """
+
+    def loggerInfo(ob_class, comment):
+        """Adds an INFO message to the log file
+        """
+
+    def createStudent():
+        """Create a student object from applicatnt data
+        and copy applicant object.
+        """
+
+class IUGApplicantEdit(IUGApplicant):
+    """An undergraduate applicant interface for editing.
+
+    Here we can repeat the fields from base data and set the
+    `required` and `readonly` attributes to True to further restrict
+    the data access. Or we can allow only certain certificates to be
+    selected by choosing the appropriate source.
+
+    We cannot omit fields here. This has to be done in the
+    respective form page.
+    """
+
+class IPGApplicantEdit(IPGApplicant):
+    """A postgraduate applicant interface for editing.
+
+    Here we can repeat the fields from base data and set the
+    `required` and `readonly` attributes to True to further restrict
+    the data access. Or we can allow only certain certificates to be
+    selected by choosing the appropriate source.
+
+    We cannot omit fields here. This has to be done in the
+    respective form page.
+    """
+class ICustomApplicantOnlinePayment(ICustomOnlinePayment):
+    """An applicant payment via payment gateways.
+
+    """
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/payment.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/payment.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/payment.py	(revision 8249)
@@ -0,0 +1,53 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Acceptance fee payment.
+"""
+import grok
+from zope.component.interfaces import IFactory
+from zope.interface import implementedBy
+from waeup.kofa.payments import OnlinePayment
+from waeup.kofa.utils.helpers import attrs_to_fields
+from waeup.uniben.applicants.interfaces import ICustomApplicantOnlinePayment
+
+class CustomApplicantOnlinePayment(OnlinePayment):
+    """This is an online payment.
+    """
+    grok.implements(ICustomApplicantOnlinePayment)
+    grok.provides(ICustomApplicantOnlinePayment)
+
+    def __init__(self):
+        super(CustomApplicantOnlinePayment, self).__init__()
+        return
+
+CustomApplicantOnlinePayment = attrs_to_fields(CustomApplicantOnlinePayment)
+
+# Applicant online payments must be importable. So we might need a factory.
+class CustomApplicantOnlinePaymentFactory(grok.GlobalUtility):
+    """A factory for applicant online payments.
+    """
+    grok.implements(IFactory)
+    grok.name(u'waeup.CustomApplicantOnlinePayment')
+    title = u"Create a new online payment.",
+    description = u"This factory instantiates new online payment instances."
+
+    def __call__(self, *args, **kw):
+        return CustomApplicantOnlinePayment()
+
+    def getInterfaces(self):
+        return implementedBy(CustomApplicantOnlinePayment)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/tests.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/tests.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/tests.py	(revision 8249)
@@ -0,0 +1,209 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import os
+import shutil
+import tempfile
+import datetime
+from zope.intid.interfaces import IIntIds
+from zope.interface.verify import verifyClass, verifyObject
+from zope.component.hooks import setSite, clearSite
+from zope.component import createObject, getUtility
+from zope.catalog.interfaces import ICatalog
+from zope.testbrowser.testing import Browser
+from waeup.kofa.app import University
+from waeup.kofa.university.faculty import Faculty
+from waeup.kofa.university.department import Department
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.kofa.applicants.container import ApplicantsContainer
+from waeup.kofa.applicants.tests.test_batching import ApplicantImportExportSetup
+from waeup.kofa.interfaces import IBatchProcessor
+from waeup.uniben.testing import FunctionalLayer
+from waeup.uniben.applicants.export import CustomApplicantsExporter
+
+
+class ApplicantUITest(FunctionalTestCase):
+    """Perform some browser tests.
+    """
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(ApplicantUITest, self).setUp()
+        # Setup a sample site for each test
+        app = University()
+        self.dc_root = tempfile.mkdtemp()
+        app['datacenter'].setStoragePath(self.dc_root)
+
+        # Prepopulate the ZODB...
+        self.getRootFolder()['app'] = app
+        # we add the site immediately after creation to the
+        # ZODB. Catalogs and other local utilities are not setup
+        # before that step.
+        self.app = self.getRootFolder()['app']
+        # Set site here. Some of the following setup code might need
+        # to access grok.getSite() and should get our new app then
+        setSite(app)
+
+        # Add an two different applicants containers
+        self.pgcontainer = ApplicantsContainer()
+        self.pgcontainer.code = u'pgft2011'
+        self.pgcontainer.prefix = u'pgft'
+        self.app['applicants']['pgft2011'] = self.pgcontainer
+        self.ugcontainer = ApplicantsContainer()
+        self.ugcontainer.code = u'app2011'
+        self.ugcontainer.prefix = u'app'
+        self.app['applicants']['app2011'] = self.ugcontainer
+
+        # Populate university
+        self.certificate = createObject('waeup.Certificate')
+        self.certificate.code = 'CERT1'
+        self.certificate.application_category = 'basic'
+        self.certificate.start_level = 100
+        self.certificate.end_level = 500
+        self.app['faculties']['fac1'] = Faculty()
+        self.app['faculties']['fac1']['dep1'] = Department()
+        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
+            self.certificate)
+
+        # Add (customized) applicants
+        pgapplicant = createObject(u'waeup.Applicant')
+        pgapplicant.firstname = u'Anna'
+        pgapplicant.lastname = u'Post'
+        self.app['applicants']['pgft2011'].addApplicant(pgapplicant)
+        self.pgapplication_number = pgapplicant.application_number
+        self.pgapplicant = self.app['applicants']['pgft2011'][
+            self.pgapplication_number]
+
+        ugapplicant = createObject(u'waeup.Applicant')
+        ugapplicant.firstname = u'Klaus'
+        ugapplicant.lastname = u'Under'
+        self.app['applicants']['app2011'].addApplicant(ugapplicant)
+        self.ugapplication_number = ugapplicant.application_number
+        self.ugapplicant = self.app['applicants']['app2011'][
+            self.ugapplication_number]
+
+        self.browser = Browser()
+        self.browser.handleErrors = False
+
+    def tearDown(self):
+        super(ApplicantUITest, self).tearDown()
+        shutil.rmtree(self.dc_root)
+        clearSite()
+        return
+
+    def test_manage_and_view_applicant(self):
+        # Managers can manage pg applicants
+        pgapplicant_path = ('http://localhost/app/applicants/pgft2011/%s'
+            % self.pgapplication_number)
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        # The IPGApplicant interface is really used in all pages
+        self.browser.open(pgapplicant_path)
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertTrue('Employer' in self.browser.contents)
+        self.browser.open(pgapplicant_path + '/manage')
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertTrue('Employer' in self.browser.contents)
+        self.browser.open(pgapplicant_path + '/edit')
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertTrue('Employer' in self.browser.contents)
+        self.browser.open(pgapplicant_path + '/application_slip.pdf')
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        # If we lool at the applicant in the ug container,
+        # the employer field doesn't appear
+        ugapplicant_path = ('http://localhost/app/applicants/app2011/%s'
+            % self.ugapplication_number)
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(ugapplicant_path)
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertFalse('Employer' in self.browser.contents)
+        self.browser.open(ugapplicant_path + '/manage')
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        # We can save the applicant
+        self.browser.getControl(name="form.reg_number").value = '1234'
+        self.browser.getControl(name="form.firstname").value = 'John'
+        self.browser.getControl(name="form.lastname").value = 'Tester'
+        self.browser.getControl(name="form.course1").value = ['CERT1']
+        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
+        self.browser.getControl(name="form.lga").value = ['foreigner']
+        self.browser.getControl(name="form.sex").value = ['m']
+        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
+        self.browser.getControl("Save").click()
+        self.assertMatches('...Form has been saved...', self.browser.contents)
+        self.assertFalse('Employer' in self.browser.contents)
+        self.browser.open(ugapplicant_path + '/edit')
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertFalse('Employer' in self.browser.contents)
+        self.browser.open(ugapplicant_path + '/application_slip.pdf')
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        return
+
+class ApplicantsExporterTest(ApplicantImportExportSetup):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(ApplicantsExporterTest, self).setUp()
+        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
+        self.cat = getUtility(ICatalog, name='applicants_catalog')
+        self.intids = getUtility(IIntIds)
+        return
+
+    def setup_applicant(self, applicant):
+        # set predictable values for `applicant`
+        applicant.reg_number = u'123456'
+        applicant.applicant_id = u'dp2011_654321'
+        applicant.firstname = u'Anna'
+        applicant.lastname = u'Tester'
+        applicant.middlename = u'M.'
+        applicant.date_of_birth = datetime.date(1981, 2, 4)
+        applicant.sex = 'f'
+        applicant.email = 'anna@sample.com'
+        applicant.phone = u'+234-123-12345'
+        applicant.course1 = self.certificate
+        applicant.course2 = self.certificate
+        applicant.course_admitted = self.certificate
+        applicant.notice = u'Some notice\nin lines.'
+        applicant.screening_score = 98
+        applicant.screening_venue = u'Exam Room'
+        applicant.password = 'any password'
+        return applicant
+
+    def test_export_all(self):
+        # we can export all applicants in a portal
+        # set values we can expect in export file
+        self.applicant = self.setup_applicant(self.applicant)
+        exporter = CustomApplicantsExporter()
+        exporter.export_all(self.app, self.outfile)
+        result = open(self.outfile, 'rb').read()
+        # The exported records do contain a real date in their
+        # history dict. We skip the date and split the comparison
+        # into two parts.
+        self.assertTrue(
+            'applicant_id,application_date,application_number,course1,course2,'
+            'course_admitted,date_of_birth,display_fullname,email,emp2_end,'
+            'emp2_position,emp2_reason,emp2_start,emp_end,emp_position,'
+            'emp_reason,emp_start,employer,employer2,firstname,history,'
+            'hq_degree,hq_disc,hq_matric_no,hq_school,hq_session,hq_type,'
+            'lastname,lga,locked,middlename,nationality,notice,nysc_lga,'
+            'nysc_year,password,perm_address,phone,pp_school,presently_inst,'
+            'reg_number,screening_score,screening_venue,sex,state,student_id'
+            in result)
+        self.assertTrue(
+            'Application initialized by system\'],,,,,,,Tester,,0,M.,,'
+            '"Some notice\nin lines.",,,any password,,+234-123-12345,,,'
+            '123456,98,Exam Room,f,initialized,' in result)
+        return
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/utils.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/utils.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/applicants/utils.py	(revision 8249)
@@ -0,0 +1,65 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""General helper functions and utilities for the application section.
+"""
+
+import sys
+import grok
+from hurry.workflow.interfaces import IWorkflowInfo, InvalidTransitionError
+from waeup.kofa.applicants.utils import ApplicantsUtils
+from waeup.uniben.interfaces import MessageFactory as _
+
+
+def actions_after_applicant_payment(applicant, view):
+    wf_info = IWorkflowInfo(applicant)
+    try:
+        wf_info.fireTransition('pay')
+    except InvalidTransitionError:
+        view.flash('Error: %s' % sys.exc_info()[1])
+        return
+
+class ApplicantsUtils(ApplicantsUtils):
+    """A collection of parameters and methods subject to customization.
+    """
+
+    APP_TYPES_DICT = {
+        'pude': ['Post UDE Screening', 'PUDE'],
+        'prence': ['Pre-NCE Programme', 'PRE'],
+        'sandwich': ['Part Time Degree in Education', 'SAND'],
+        'pt': ['Part-Time Degree Programmes', 'PTP'],
+        'pume': ['Post UME Screening Test', 'PUME'],
+        'app': ['General Studies', 'APP'],
+        'cest': ['Common Entry Screening Test', 'CEST'],
+        'ct': ['Certificate Programmes', 'CTP'],
+        'dp': ['Diploma Programmes', 'DPP'],
+        'pce': ['PCE Screening', 'PCE'],
+        'pgft': ['Postgraduate Full-Time Programmes', 'PG'],
+        'pgpt': ['Postgraduate Part-Time Programmes', 'PG']
+        }
+
+    SEPARATORS_DICT = {
+        'form.applicant_id': _(u'Base Data'),
+        'form.course1': _(u'Programmes/Courses Desired'),
+        'form.hq_type': _(u'Higher Education Record'),
+        'form.presently': _(u'Course or Programme Presently Attending'),
+        'form.nysc_year': _(u'NYSC Information'),
+        'form.employer': _(u'Employment History'),
+        'form.notice': _(u'Application Process Information'),
+        'form.pp_school': _(u'Post Primary School Qualification'),
+        'form.presently_inst': _(u'Presently attending a course or programme'),
+        }
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/pages.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/pages.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/pages.py	(revision 8249)
@@ -0,0 +1,32 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import grok
+from waeup.kofa.browser.pages import (
+    SessionConfigurationAddFormPage, SessionConfigurationManageFormPage)
+from waeup.uniben.interfaces import (
+    ICustomSessionConfiguration, ICustomSessionConfigurationAdd)
+
+class CustomSessionConfigurationAddFormPage(SessionConfigurationAddFormPage):
+    """Add a session configuration object to configuration container.
+    """
+    form_fields = grok.AutoFields(ICustomSessionConfigurationAdd)
+
+class CustomSessionConfigurationManageFormPage(SessionConfigurationManageFormPage):
+    """Manage session configuration object.
+    """
+    form_fields = grok.AutoFields(ICustomSessionConfiguration)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/pdf.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/pdf.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/pdf.py	(revision 8249)
@@ -0,0 +1,35 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+## 
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Reusable components for pdf generation.
+"""
+
+import os
+from waeup.kofa.browser.pdf import PDFCreator
+
+class CustomPDFCreator(PDFCreator):
+    """A utility to help with generating PDF docs.
+    """
+
+    header_logo_path = os.path.join(
+        os.path.dirname(__file__), 'static', 'pdf_logo.jpg')
+    watermark_path = os.path.join(
+        os.path.dirname(__file__), 'static', 'pdf_watermark.jpg')
+
+    watermark_pos = [-25, 100]
+    logo_pos = [507, 720, 40]
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/resources.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/resources.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/resources.py	(revision 8249)
@@ -0,0 +1,30 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import grok
+from waeup.kofa.browser.resources import (
+    Library, ResourceInclusion, waeup_base_css,
+    )
+
+#: All local resources are registered under the name ``waeup_custom``.
+waeup_uniben = Library('waeup_uniben', 'static')
+
+custom_theme_1 = ResourceInclusion(
+    waeup_uniben, 'custom_theme_1.css',
+    depends = [waeup_base_css])
+
+favicon = ResourceInclusion(waeup_uniben, 'favicon.ico')
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/static/custom_theme_1.css
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/static/custom_theme_1.css	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/static/custom_theme_1.css	(revision 8249)
@@ -0,0 +1,72 @@
+.topbar-inner, .topbar .fill {
+  background-color: #8A0474;
+  background-image: -moz-linear-gradient(center top , #4e0242, #8A0474);
+  background-image: -khtml-gradient(linear, left top, left bottom, from(#4e0242), to(#8A0474));
+  background-image: -moz-linear-gradient(top, #4e0242, #8A0474);
+  background-image: -ms-linear-gradient(top, #4e0242, #8A0474);
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #4e0242), color-stop(100%, #8A0474));
+  background-image: -webkit-linear-gradient(top, #4e0242, #8A0474);
+  background-image: -o-linear-gradient(top, #4e0242, #8A0474);
+  background-image: linear-gradient(top, #4e0242, #8A0474);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4e0242', endColorstr='#8A0474', GradientType=0);
+}
+
+.topbar div > ul .active > a, .nav .active > a {
+  background-color: #8A0474;
+}
+
+.topbar h3 a:hover, .topbar .brand:hover, .topbar ul .active > a {
+  background-color: #8A0474;
+}
+
+.topbar div > ul a:hover, .nav a:hover {
+  background-color: #8A0474;
+}
+
+
+.topbar div > ul .menu-dropdown,
+.nav .menu-dropdown,
+.topbar div > ul .dropdown-menu,
+.nav .dropdown-menu {
+  background-color: #8A0474;
+}
+
+.topbar div > ul a.menu:hover,
+.nav a.menu:hover,
+.topbar div > ul li.open .menu,
+.nav li.open .menu,
+.topbar div > ul .dropdown-toggle:hover,
+.nav .dropdown-toggle:hover,
+.topbar div > ul .dropdown.open .dropdown-toggle,
+.nav .dropdown.open .dropdown-toggle {
+  background: #8A0474;
+}
+
+body {
+  background-color: #f3eff2;
+}
+
+.topbar div > ul .menu-dropdown li a:hover,
+.nav .menu-dropdown li a:hover,
+.topbar div > ul .dropdown-menu li a:hover,
+.nav .dropdown-menu li a:hover {
+  background-color: #4e0242;
+  background-repeat: repeat-x;
+  background-image: -khtml-gradient(linear, left top, left bottom, from(#8A0474), to(#191919));
+  background-image: -moz-linear-gradient(top, #4e0242, #4e0242);
+  background-image: -ms-linear-gradient(top, #4e0242, #4e0242);
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #4e0242), color-stop(100%, #4e0242));
+  background-image: -webkit-linear-gradient(top, #4e0242, #4e0242);
+  background-image: -o-linear-gradient(top, #4e0242, #4e0242);
+  background-image: linear-gradient(top, #4e0242, #4e0242);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4e0242', endColorstr='#4e0242', GradientType=0);
+  color: #ffffff;
+}
+
+a {
+  color: #8A0474;
+}
+
+a:hover {
+  color: #4e0242;
+}
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/tests.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/tests.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/tests.py	(revision 8249)
@@ -0,0 +1,65 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import tempfile
+import shutil
+from zope.testbrowser.testing import Browser
+from zope.component.hooks import setSite, clearSite
+from zope.security.interfaces import Unauthorized
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.uniben.testing import FunctionalLayer
+from waeup.kofa.app import University
+
+class CustomPackageBrowserTests(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(CustomPackageBrowserTests, self).setUp()
+
+        # Setup a sample site for each test
+        app = University()
+        self.dc_root = tempfile.mkdtemp()
+        app['datacenter'].setStoragePath(self.dc_root)
+
+        # Put the prepopulated site into test ZODB and prepare test
+        # browser
+        self.getRootFolder()['app'] = app
+        setSite(app)
+        self.browser = Browser()
+        self.browser.handleErrors = False
+
+    def tearDown(self):
+        super(CustomPackageBrowserTests, self).tearDown()
+        clearSite()
+        shutil.rmtree(self.dc_root)
+
+    def test_custom_theme(self):
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open('http://localhost/app/configuration')
+        self.assertMatches('...Custom Theme 1...', self.browser.contents)
+        self.browser.getControl(name="form.skin").value = ['custom theme 1']
+        self.browser.getControl("Save").click()
+        self.browser.open('http://localhost/app/configuration')
+        return
+
+    def test_access_live_url(self):
+        # We can't access the system with basic authentication
+        self.browser.addHeader('Authorization', 'Basic grok:grok')
+        self.assertRaises(
+            Unauthorized, self.browser.open, 'https://uniben-kofa.waeup.org')
+        return
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/theming.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/theming.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/browser/theming.py	(revision 8249)
@@ -0,0 +1,33 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import grok
+from waeup.kofa.browser.interfaces import ITheme
+from waeup.uniben.browser.resources import custom_theme_1, favicon
+
+from waeup.uniben.interfaces import MessageFactory as _
+
+class CustomTheme1(grok.GlobalUtility):
+    """A custom theme based on the Kofa base theme.
+    """
+    grok.implements(ITheme)
+    grok.name('custom theme 1')
+
+    description = _(u'Custom Theme 1')
+
+    def getResources(self):
+        return [custom_theme_1, favicon]
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/configuration.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/configuration.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/configuration.py	(revision 8249)
@@ -0,0 +1,47 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Containers for session configuration objects.
+"""
+import grok
+from zope.interface import implementedBy
+from waeup.kofa.utils.helpers import attrs_to_fields
+from waeup.kofa.configuration import (
+    SessionConfigurationFactory, SessionConfiguration)
+from waeup.uniben.interfaces import (
+    ICustomSessionConfiguration, ICustomSessionConfigurationAdd)
+
+
+class CustomSessionConfiguration(SessionConfiguration):
+    """
+    Customized session configuration model
+    """
+
+    grok.implements(ICustomSessionConfiguration, ICustomSessionConfigurationAdd)
+
+CustomSessionConfiguration = attrs_to_fields(CustomSessionConfiguration)
+
+class CustomSessionConfigurationFactory(SessionConfigurationFactory):
+    """A customized factory for session configuration objects.
+    """
+
+    def __call__(self, *args, **kw):
+        return CustomSessionConfiguration(*args, **kw)
+
+    def getInterfaces(self):
+        return implementedBy(CustomSessionConfiguration)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/configure.zcml
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/configure.zcml	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/configure.zcml	(revision 8249)
@@ -0,0 +1,7 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+  <include package="waeup.uniben" file="locales.zcml" />
+  <include package="grok" />
+  <includeOverrides package="waeup.uniben" file="overrides.zcml" />
+
+</configure>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/browser.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/browser.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/browser.py	(revision 8249)
@@ -0,0 +1,167 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from datetime import datetime
+import httplib
+import urllib
+from xml.dom.minidom import parseString
+import grok
+from waeup.kofa.browser.layout import KofaPage, UtilityView
+from waeup.kofa.students.interfaces import IStudentOnlinePayment
+from waeup.kofa.applicants.interfaces import IApplicantOnlinePayment
+from waeup.kofa.applicants.viewlets import RequestCallbackActionButton as RCABApplicant
+from waeup.kofa.students.viewlets import RequestCallbackActionButton as RCABStudent
+from waeup.uniben.interfaces import MessageFactory as _
+from waeup.uniben.students.utils import actions_after_student_payment
+from waeup.uniben.applicants.utils import actions_after_applicant_payment
+
+TERMINAL_ID = '0500000003'
+QUERY_URL =   'https://www.etranzact.net/Query/queryPayoutletTransaction.jsp'
+
+
+def query_etranzact(confirmation_number, user, payment, view):
+    ob_class = view.__implemented__.__name__.replace('waeup.kofa.','')
+    postdict = {}
+    postdict['TERMINAL_ID'] = TERMINAL_ID
+    #postdict['RESPONSE_URL'] = 'http://dummy'
+    postdict['CONFIRMATION_NO'] = confirmation_number
+    data = urllib.urlencode(postdict)
+    try:
+        f = urllib.urlopen(url=QUERY_URL, data=data)
+        success = f.read()
+        user.loggerInfo(ob_class, 'callback received: %s' % success)
+        if 'COL1' not in success:
+            view.flash(_('Invalid or unsuccessful callback: ${a}',
+                mapping = {'a': success}))
+            user.loggerInfo(ob_class, 'invalid callback: %s' % payment.p_id)
+            payment.p_state = 'failed'
+            return False
+        success = success.replace('%20',' ').split('&')
+        # We expect at least two parameters
+        if len(success) < 2:
+            view.flash(_('Invalid callback: ${a}',
+                mapping = {'a': success}))
+            user.loggerInfo(ob_class, 'invalid callback: %s' % payment.p_id)
+            payment.p_state = 'failed'
+            return False
+        try:
+            success_dict = dict([tuple(i.split('=')) for i in success])
+        except ValueError:
+            view.flash(_('Invalid callback: ${a}',
+                mapping = {'a': success}))
+            user.loggerInfo(ob_class, 'invalid callback: %s' % payment.p_id)
+            payment.p_state = 'failed'
+            return False
+    except IOError:
+        view.flash(_('eTranzact IOError'))
+        return False
+    payment.r_code = u'ET'
+    payment.r_desc = u'%s' % success_dict.get('TRANS_DESCR')
+    payment.r_amount_approved = float(success_dict.get('TRANS_AMOUNT',0.0))
+    payment.r_card_num = None
+    payment.r_pay_reference = u'%s' % success_dict.get('RECEIPT_NO')
+    if payment.r_amount_approved != payment.amount_auth:
+        view.flash(_('Wrong amount'))
+        user.loggerInfo(ob_class, 'successful callback but wrong amount: %s'
+            % payment.p_id)
+        payment.p_state = 'failed'
+        return False
+    tcode = payment.p_id
+    tcode = tcode[len(tcode)-8:len(tcode)]
+    col1 = success_dict.get('COL1')
+    col1 = col1[len(col1)-8:len(col1)]
+    if tcode != col1:
+        view.flash(_('Wrong transaction code'))
+        write_log_message(
+            view,'successful callback but wrong transaction code: %s'
+            % payment.p_id)
+        user.loggerInfo(ob_class, 'successful callback wrong transaction code: %s'
+            % payment.p_id)
+        payment.p_state = 'failed'
+        return False
+    user.loggerInfo(ob_class, 'successful callback: %s' % payment.p_id)
+    payment.p_state = 'paid'
+    payment.payment_date = datetime.now()
+    return True
+
+class EtranzactEnterPinActionButtonApplicant(RCABApplicant):
+    icon = 'actionicon_call.png'
+    text = _('Query eTranzact History')
+    target = 'enterpin'
+
+class EtranzactEnterPinActionButtonStudent(RCABStudent):
+    icon = 'actionicon_call.png'
+    text = _('Query eTranzact History')
+    target = 'enterpin'
+
+class EtranzactEnterPinPageStudent(KofaPage):
+    """
+    """
+    grok.context(IStudentOnlinePayment)
+    grok.name('enterpin')
+    grok.template('enterpin')
+    grok.require('waeup.payStudent')
+
+    buttonname = _('Submit to eTranzact')
+    label = _('Requery eTranzact History')
+    action = 'query_history'
+
+class EtranzactEnterPinPageApplicant(EtranzactEnterPinPageStudent):
+    """
+    """
+    grok.require('waeup.payApplicant')
+    grok.context(IApplicantOnlinePayment)
+
+class EtranzactQueryHistoryPageStudent(UtilityView, grok.View):
+    """ Query history of eTranzact payments
+    """
+    grok.context(IStudentOnlinePayment)
+    grok.name('query_history')
+    grok.require('waeup.payStudent')
+
+    def update(self, confirmation_number=None):
+        if self.context.p_state == 'paid':
+            self.flash(_('This ticket has already been paid.'))
+            return
+        student = self.context.getStudent()
+        if query_etranzact(confirmation_number, student, self.context, self):
+            actions_after_student_payment(student, self.context, self)
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
+
+class EtranzactQueryHistoryPageApplicant(UtilityView, grok.View):
+    """ Query history of eTranzact payments
+    """
+    grok.context(IApplicantOnlinePayment)
+    grok.name('query_history')
+    grok.require('waeup.payApplicant')
+
+    def update(self, confirmation_number=None):
+        if self.context.p_state == 'paid':
+            self.flash(_('This ticket has already been paid.'))
+            return
+        applicant = self.context.__parent__
+        if query_etranzact(confirmation_number, applicant, self.context, self):
+            actions_after_applicant_payment(applicant, self)
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/browser_templates/enterpin.pt
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/browser_templates/enterpin.pt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/browser_templates/enterpin.pt	(revision 8249)
@@ -0,0 +1,22 @@
+<form tal:attributes="action view/action"
+    method="POST" i18n:domain="waeup.uniben">
+  <table class="form-table">
+    <tbody>
+      <tr>
+        <td i18n:translate="">
+        Confirmation Number (PIN):
+        </td>
+        <td>
+        <input name="confirmation_number" type="text" class="span5" maxlength=""
+               value="" />
+        </td>
+      </tr>
+      <tr>
+        <td colspan="2">
+          <input type="submit" name="SUBMIT" class="btn primary"
+                 tal:attributes="value view/buttonname" />
+        </td>
+      </tr>
+    </tbody>
+  </table>
+</form>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/tests.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/tests.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/etranzact/tests.py	(revision 8249)
@@ -0,0 +1,82 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from hurry.workflow.interfaces import IWorkflowState
+from waeup.kofa.students.tests.test_browser import StudentsFullSetup
+from waeup.uniben.testing import FunctionalLayer
+
+
+# Also run tests that send requests to external servers?
+#   If you enable this, please make sure the external services
+#   do exist really and are not bothered by being spammed by a test programme.
+EXTERNAL_TESTS = False
+
+def external_test(func):
+    if not EXTERNAL_TESTS:
+        myself = __file__
+        if myself.endswith('.pyc'):
+            myself = myself[:-2]
+        print "WARNING: external tests are skipped!"
+        print "WARNING: edit %s to enable them." % myself
+        return
+    return func
+
+class EtranzactTests(StudentsFullSetup):
+    """Tests for the eTranzact payment gateway.
+    """
+
+    layer = FunctionalLayer
+
+    CONFIRMATION_NO = '500856521315472785095'
+
+    def setUp(self):
+        super(EtranzactTests, self).setUp()
+        # Managers can add online payment tickets
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.payments_path)
+        IWorkflowState(self.student).setState('cleared')
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...ticket created...',
+                           self.browser.contents)
+        ctrl = self.browser.getControl(name='val_id')
+        value = ctrl.options[0]
+        self.browser.getLink(value).click()
+        self.assertMatches('...Amount Authorized...',
+                           self.browser.contents)
+        self.payment_url = self.browser.url
+
+    def test_enterpin(self):
+        self.browser.getLink("Query eTranzact History").click()
+        self.assertMatches(
+            '...Confirmation Number (PIN):...',
+            self.browser.contents)
+
+    @external_test
+    def test_etranzact_query_history(self):
+
+        self.browser.open(self.payment_url + '/query_history?confirmation_number=%s'
+            % self.CONFIRMATION_NO)
+        self.assertMatches('...Wrong amount...',
+                          self.browser.contents)
+
+        self.student['payments'][value].amount_auth = self.student[
+            'payments'][value].r_amount_approved
+        self.browser.open(self.payment_url + '/query_history?confirmation_number=%s'
+            % self.CONFIRMATION_NO)
+        self.assertMatches('...Wrong transaction id...',
+                          self.browser.contents)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/ftesting.zcml
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/ftesting.zcml	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/ftesting.zcml	(revision 8249)
@@ -0,0 +1,68 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   xmlns:kofa="http://namespaces.waeup.org/kofa"
+   i18n_domain="waeup.uniben"
+   package="waeup.uniben"
+   >
+
+  <include package="grok" />
+  <includeOverrides package="waeup.uniben" />
+  <includeOverrides package="waeup.uniben" file="mail.zcml"/>
+
+  <!-- Where should the datacenter reside by default? -->
+  <kofa:datacenter
+      path="../../../parts/test/datacenter" />
+
+  <!-- Typical functional testing security setup -->
+  <securityPolicy
+      component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy"
+      />
+
+  <unauthenticatedPrincipal
+      id="zope.anybody"
+      title="Unauthenticated User"
+      />
+  <unauthenticatedGroup id="zope.Anybody"
+      title="Unauthenticated Users" />
+  <authenticatedGroup id="zope.Authenticated"
+      title="Authenticated Users" />
+  <everybodyGroup id="zope.Everybody"
+      title="All Users" />
+
+  <!-- grant
+      permission="zope.View"
+      principal="zope.Anybody"
+      / -->
+  <grant
+      permission="zope.app.dublincore.view"
+      principal="zope.Anybody" />
+  <grant
+      permission="zope.View"
+      principal="zope.Authenticated"
+      />
+  <grant
+      permission="zope.app.dublincore.view"
+      principal="zope.Authenticated"
+      />
+  <grant
+      permission="waeup.Public"
+      principal="zope.Everybody"
+      />
+  <grant 
+      permission="waeup.Anonymous"
+      principal="zope.Anybody"
+      />
+
+
+  <principal
+      id="zope.mgr"
+      title="Manager"
+      login="mgr"
+      password="mgrpw"
+      />
+
+  <role id="zope.Manager" title="Site Manager" />
+  <grantAll role="zope.Manager" />
+  <grant role="zope.Manager" principal="zope.mgr" />
+
+</configure>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interfaces.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interfaces.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interfaces.py	(revision 8249)
@@ -0,0 +1,163 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+import zope.i18nmessageid
+from zope import schema
+from waeup.kofa.interfaces import (SimpleKofaVocabulary,
+    ISessionConfiguration, academic_sessions_vocab)
+from waeup.uniben.utils.lgas import LGAS
+
+_ = MessageFactory = zope.i18nmessageid.MessageFactory('waeup.uniben')
+
+high_qual = SimpleKofaVocabulary(
+    ('National Certificate of Education','nce'),
+    ('Pre Degree Programme','pre'),
+    ('Diploma Programme','dip'),
+    ('Ordinary National Diploma','ond'),
+    ('Bachelors Degree','bd'),
+    ('Masters Degree','md'),
+    ('Professional Qualification','pq'),
+    ('Other Certification','oc'),
+    ('Higher National Diploma','hnd'),
+    ('NCE AL OTH','nce_al_oth'),
+    ('National Defence Academy','nda'),
+    ('Awaiting Results','a_rslt'),
+    ('RMC','rmc'),
+    )
+
+high_grade = SimpleKofaVocabulary(
+    ('Upper Credit','upper_credit'),
+    ('Distinction','distinction'),
+    ('Credit','credit'),
+    ('Merit','merit'),
+    ('Lower Credit','lower_credit'),
+    ('First Class','first_class'),
+    ('Second Class Upper','second_class_upper'),
+    ('Second Class Lower','second_class_lower'),
+    ('Third Class','third_class'),
+    ('Pass','pass'),
+    ('Awaiting Results','a_rslt'),
+    ('A Levels','al'),
+    )
+
+exam_types = SimpleKofaVocabulary(
+    ('SSCE','ssce'),
+    ('WAEC','waec'),
+    ('GCE O\' LEVEL','gce_o_level'),
+    ('TC II','tc_ii'),
+    ('RSA','rsa'),
+    ('NABTEB','nabteb'),
+    ('NECO','neco'),
+    ('ACE','ace'),
+    ('GCE A\' LEVEL','gce_a_level'),
+    ('IGCSE','igcse'),
+    )
+
+
+lgas_vocab = SimpleKofaVocabulary(
+    *sorted([(x[1],x[0]) for x in LGAS]))
+
+# It's recommended to replicate all fields from the base package here.
+class ICustomSessionConfiguration(ISessionConfiguration):
+    """A session configuration object.
+    """
+
+    # Base fees, do not remove.
+
+    school_fee_base = schema.Float(
+        title = _(u'School Fee (ignored)'),
+        default = 0.0,
+        required = False,
+        )
+
+    surcharge_1 = schema.Float(
+        title = _(u'Surcharge Portal Provider'),
+        default = 0.0,
+        required = False,
+        )
+
+    surcharge_2 = schema.Float(
+        title = _(u'Surcharge Interswitch'),
+        default = 0.0,
+        required = False,
+        )
+
+    surcharge_3 = schema.Float(
+        title = _(u'Surcharge 3'),
+        default = 0.0,
+        required = False,
+        )
+
+    clearance_fee = schema.Float(
+        title = _(u'Clearance Fee'),
+        default = 0.0,
+        required = False,
+        )
+
+    booking_fee = schema.Float(
+        title = _(u'Booking Fee'),
+        default = 0.0,
+        required = False,
+        )
+
+    acceptance_fee = schema.Float(
+        title = _(u'Acceptance Fee'),
+        default = 0.0,
+        required = False,
+        )
+
+    # Additional fees in waeup.uniben
+
+    maint_fee = schema.Float(
+        title = _(u'Maintenance Fee'),
+        default = 0.0,
+        required = False,
+        )
+
+    gown = schema.Float(
+        title = _(u'Gown Fee'),
+        default = 0.0,
+        required = False,
+        )
+
+    transfer = schema.Float(
+        title = _(u'Transfer Fee'),
+        default = 0.0,
+        required = False,
+        )
+
+    def getSessionString():
+        """Returns the session string from the vocabulary.
+        """
+
+
+class ICustomSessionConfigurationAdd(ISessionConfiguration):
+    """A session configuration object in add mode.
+    """
+
+    academic_session = schema.Choice(
+        title = _(u'Academic Session'),
+        source = academic_sessions_vocab,
+        default = None,
+        required = True,
+        readonly = False,
+        )
+
+ICustomSessionConfigurationAdd[
+    'academic_session'].order =  ICustomSessionConfiguration[
+    'academic_session'].order
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/browser.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/browser.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/browser.py	(revision 8249)
@@ -0,0 +1,310 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from datetime import datetime
+import httplib
+import urllib
+from xml.dom.minidom import parseString
+import grok
+from waeup.kofa.browser.layout import KofaPage, UtilityView
+from waeup.kofa.accesscodes import create_accesscode
+from waeup.kofa.students.interfaces import IStudentOnlinePayment
+from waeup.kofa.students.browser import write_log_message
+from waeup.kofa.students.viewlets import RequestCallbackActionButton
+from waeup.uniben.students.utils import actions_after_student_payment
+from waeup.uniben.interfaces import MessageFactory as _
+
+PRODUCT_ID = '57'
+SITE_NAME = 'xyz.waeup.org'
+PROVIDER_ACCT = '2345'
+PROVIDER_BANK_ID = '8'
+PROVIDER_ITEM_NAME = 'Kofa Provider Fee'
+INSTITUTION_ACCT = '1234'
+INSTITUTION_BANK_ID = '9'
+INSTITUTION_NAME = 'Sample University'
+CURRENCY = '566'
+PAY_ITEM_ID = '5700'
+QUERY_URL =   'https://testwebpay.interswitchng.com/test_paydirect/services/TransactionQueryURL.aspx'
+POST_ACTION = 'https://testwebpay.interswitchng.com/test_paydirect/webpay/pay.aspx'
+
+HOST = 'testwebpay.interswitchng.com'
+URL = '/test_paydirect/services/TransactionQueryWs.asmx'
+httplib.HTTPConnection.debuglevel = 0
+
+def SOAP_post(soap_action,xml):
+    """Handles making the SOAP request.
+
+    Further reading:
+    http://testwebpay.interswitchng.com/test_paydirect/services/TransactionQueryWs.asmx?op=getTransactionData
+    """
+    h = httplib.HTTPConnection(HOST)
+    headers={
+        'Host':HOST,
+        'Content-Type':'text/xml; charset=utf-8',
+        'Content-Length':len(xml),
+        'SOAPAction':'"%s"' % soap_action,
+    }
+    h.request('POST', URL, body=xml,headers=headers)
+    r = h.getresponse()
+    d = r.read()
+    if r.status!=200:
+        raise ValueError('Error connecting: %s, %s' % (r.status, r.reason))
+    return d
+
+def get_SOAP_response(product_id, transref):
+    xml="""\
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+  <soap:Body>
+    <getTransactionData xmlns="http://tempuri.org/">
+      <product_id>%s</product_id>
+      <trans_ref>%s</trans_ref>
+    </getTransactionData>
+  </soap:Body>
+</soap:Envelope>""" % (product_id, transref)
+    result_xml=SOAP_post("http://tempuri.org/getTransactionData",xml)
+    doc=parseString(result_xml)
+    response=doc.getElementsByTagName('getTransactionDataResult')[0].firstChild.data
+    return response
+
+class InterswitchActionButton(RequestCallbackActionButton):
+    grok.order(2)
+    icon = 'actionicon_pay.png'
+    text = _('CollegePAY')
+    target = 'goto_interswitch'
+
+    @property
+    def target_url(self):
+        if self.context.p_state != 'unpaid':
+            return ''
+        return self.view.url(self.view.context, self.target)
+
+class InterswitchRequestCallbackActionButton(RequestCallbackActionButton):
+    grok.order(3)
+    icon = 'actionicon_call.png'
+    text = _('Request CollegePAY callback')
+
+    def target_url(self):
+        if self.context.p_state == 'paid':
+            return ''
+        site_redirect_url = self.view.url(self.view.context, 'isw_callback')
+        args = {
+            'transRef':self.context.p_id,
+            'prodID':PRODUCT_ID,
+            'redirectURL':site_redirect_url}
+        return QUERY_URL + '?%s' % urllib.urlencode(args)
+
+# Alternative preferred solution
+class InterswitchRequestWebserviceActionButton(RequestCallbackActionButton):
+    grok.order(4)
+    icon = 'actionicon_call.png'
+    text = _('Request CollegePAY webservice')
+    target = 'request_webservice'
+
+
+class InterswitchPage(KofaPage):
+    """ View which sends a POST request to the Interswitch
+    CollegePAY payment gateway.
+    """
+    grok.context(IStudentOnlinePayment)
+    grok.name('goto_interswitch')
+    grok.template('goto_interswitch')
+    grok.require('waeup.payStudent')
+    label = _('Submit data to CollegePAY (Interswitch Payment Gateway)')
+    submit_button = _('Submit')
+    action = POST_ACTION
+    site_name = SITE_NAME
+    currency = CURRENCY
+    pay_item_id = PAY_ITEM_ID
+    product_id = PRODUCT_ID
+
+    def update(self):
+        if self.context.p_state != 'unpaid':
+            self.flash(_("Payment ticket can't be re-send to CollegePAY."))
+            self.redirect(self.url(self.context, '@@index'))
+            return
+        self.student = self.context.getStudent()
+        self.amount = (self.context.amount_auth + self.context.surcharge_1 +
+            self.context.surcharge_2 + self.context.surcharge_3)
+        self.amount_100 = 100 * self.amount
+        self.local_date_time = str(self.context.creation_date)
+        self.site_redirect_url = self.url(self.context, 'isw_callback')
+        certificate = getattr(self.student['studycourse'],'certificate',None)
+        xmldict = {}
+        if certificate is not None:
+            xmldict['department'] = certificate.__parent__.__parent__.code
+            xmldict['faculty'] = certificate.__parent__.__parent__.__parent__.code
+        else:
+            xmldict['department'] = None
+            xmldict['faculty'] = None
+        xmldict['detail_ref'] = self.context.p_id
+        xmldict['provider_amt'] = 100 * self.context.surcharge_1
+        xmldict['provider_acct'] = PROVIDER_ACCT
+        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
+        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
+        xmldict['institution_amt'] = 100 * self.context.amount_auth
+        xmldict['institution_acct'] = INSTITUTION_ACCT
+        xmldict['institution_bank_id'] = INSTITUTION_BANK_ID
+        xmldict['institution_item_name'] = self.context.p_category
+        xmldict['institution_name'] = INSTITUTION_NAME
+        # Interswitch amount is not part of the xml data
+        xmltext = """<payment_item_detail>
+<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
+<item_detail item_id="1" item_name="%(institution_item_name)s" item_amt="%(institution_amt)d" bank_id="%(institution_bank_id)s" acct_num="%(institution_acct)s" />
+<item_detail item_id="2" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
+</item_details>
+</payment_item_detail>""" % xmldict
+        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
+        return
+
+class InterswitchPaymentCallbackPage(UtilityView, grok.View):
+    """ Callback view for the CollegePAY gateway
+    """
+    grok.context(IStudentOnlinePayment)
+    grok.name('isw_callback')
+    grok.require('waeup.payStudent')
+
+    # This view is not yet working for offline querying transactions
+    # since the query string differs from the query string sent after
+    # posting transactions. This Interswitch bug must be removed first.
+    # Alternatively, we could use the webservice only and replace
+    # the RequestCallbackActionButton by a RequestWebserviceActionButton
+
+    def update(self):
+        if self.context.p_state == 'paid':
+            self.flash(_('This ticket has already been paid.'))
+            return
+        student = self.context.getStudent()
+        query = self.request.form
+        write_log_message(self,'callback received: %s' % query)
+
+        self.context.r_card_num = query.get('cardNum', None)
+        self.context.r_code = query.get('resp', None)
+        self.context.r_pay_reference  = query.get('payRef', None)
+        self.context.r_amount_approved = float(query.get('apprAmt', '0.0')) / 100
+        self.context.r_desc = query.get('desc', None)
+
+        if self.context.r_code != '00':
+            self.flash(_('Unsuccessful callback: ${a}',
+                mapping = {'a': query.get('desc', _('Incomplete query string.'))}))
+            write_log_message(self,'unsuccessful callback: %s' % self.context.p_id)
+            self.context.p_state = 'failed'
+            return
+
+        total_amount_auth = (
+            self.context.amount_auth
+            + self.context.surcharge_1
+            + self.context.surcharge_2)
+
+        if self.context.r_amount_approved != total_amount_auth:
+            self.flash(_('Wrong amount'))
+            write_log_message(
+                self,'successful but wrong amount: %s' % self.context.p_id)
+            self.context.p_state = 'failed'
+            return
+
+        try:
+            validation_list = get_SOAP_response(
+                PRODUCT_ID, self.context.p_id).split(':')
+            # Validation does not make sense yet since the query string
+            # formats are conflicting. We are only printing the validation
+            # string, nothing else.
+            print 'WARNING: Webservice validation is not yet implemented'
+            print 'validation list: %s' % validation_list
+        except:
+            print 'Connection to webservice failed.'
+
+        # Add webservice validation here
+
+        write_log_message(self,'valid callback: %s' % self.context.p_id)
+        self.context.p_state = 'paid'
+        self.context.payment_date = datetime.now()
+        actions_after_payment(student, self.context, self)
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
+
+# Alternative solution, replaces OnlinePaymentCallbackPage
+class InterswitchPaymentRequestWebservicePage(UtilityView, grok.View):
+    """ Request webservice view for the CollegePAY gateway
+    """
+    grok.context(IStudentOnlinePayment)
+    grok.name('request_webservice')
+    grok.require('waeup.payStudent')
+
+    def update(self):
+        if self.context.p_state == 'paid':
+            self.flash(_('This ticket has already been paid.'))
+            return
+        student = self.context.getStudent()
+        sr = get_SOAP_response(PRODUCT_ID, self.context.p_id)
+        write_log_message(self,'callback received: %s' % sr)
+        wlist = sr.split(':')
+        if len(wlist) != 7:
+            self.flash(_('Invalid callback: ${a}',
+                mapping = {'a': wlist}))
+            write_log_message(self,'invalid callback: %s' % self.context.p_id)
+            return
+        self.context.r_code = wlist[0]
+        self.context.r_desc = wlist[1]
+        self.context.r_amount_approved = float(wlist[2]) / 100
+        self.context.r_card_num = wlist[3]
+        self.context.r_pay_reference = wlist[5]
+        
+        if self.context.r_code != '00':
+            self.flash(_('Unsuccessful callback: ${a}',
+                mapping = {'a': wlist[1]}))
+            write_log_message(
+                self,'unsuccessful callback: %s' % self.context.p_id)
+            self.context.p_state = 'failed'
+            return
+
+        total_amount_auth = (
+            self.context.amount_auth
+            + self.context.surcharge_1
+            + self.context.surcharge_2)
+
+        if self.context.r_amount_approved != total_amount_auth:
+            self.flash(_('Wrong amount'))
+            write_log_message(
+                self,'successful callback but wrong amount: %s'
+                % self.context.p_id)
+            self.context.p_state = 'failed'
+            return
+
+        if wlist[4] != self.context.p_id:
+            self.flash(_('Wrong transaction id'))
+            write_log_message(
+                self,'successful callback but wrong transaction id: %s'
+                % self.context.p_id)
+            self.context.p_state = 'failed'
+            return
+
+        write_log_message(self,'successful callback: %s' % self.context.p_id)
+
+        self.context.p_state = 'paid'
+        self.context.payment_date = datetime.now()
+
+        actions_after_payment(student, self.context, self)
+
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/browser_templates/goto_interswitch.pt
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/browser_templates/goto_interswitch.pt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/browser_templates/goto_interswitch.pt	(revision 8249)
@@ -0,0 +1,79 @@
+<form i18n:domain="waeup.uniben"
+  tal:attributes="action view/action" method="POST">
+
+  <p i18n:translate="">
+    These data will be submitted to the CollegePAY payment gateway,
+    please check:
+  </p>
+
+  <table class="form-table" i18n:domain="waeup.kofa">
+    <thead>
+    </thead>
+    <tbody>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Total Amount Authorized:</td>
+        <td>
+          <span tal:replace="view/amount">AMOUNT</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Transaction Reference:</td>
+        <td>
+          <span tal:replace="view/context/p_id">TXNREF</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Customer Id:</td>
+        <td>
+          <span tal:replace="view/student/student_id">CUSTID</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Customer Name:</td>
+        <td>
+          <span tal:replace="view/student/display_fullname">CUSTNAME</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Payment Item:</td>
+        <td>
+          <span tal:replace="view/context/p_item">PAYMENTITEM</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Payment Category:</td>
+        <td>
+          <span tal:replace="view/context/p_category">PAYMENTCATEGORY</span>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+
+  <input type="hidden" name="product_id" tal:attributes="value view/product_id" />
+  <input type="hidden" name="currency" tal:attributes="value view/currency" />
+  <input type="hidden" name="pay_item_id" tal:attributes="value view/pay_item_id" />
+  <input type="hidden" name="site_redirect_url" tal:attributes="value view/site_redirect_url" />
+  <input type="hidden" name="site_name" tal:attributes="value view/site_name" />
+  <input type="hidden" name="local_date_time" tal:attributes="value view/local_date_time" />
+  <input type="hidden" name="amount" tal:attributes="value view/amount_100" />
+
+  <input type="hidden" name="txn_ref" tal:attributes="value view/context/p_id" />
+  <input type="hidden" name="cust_id_desc" tal:attributes="value view/context/p_item" />
+  <input type="hidden" name="pay_item_name" tal:attributes="value view/context/p_category" />
+
+  <input type="hidden" name="cust_id" tal:attributes="value view/student/student_id" />
+  <input type="hidden" name="cust_name" tal:attributes="value view/student/display_fullname" />
+
+
+  <input type="hidden" name="payment_params" value="college_split" />
+  <span tal:replace="structure view/xml_data"></span>
+
+  <input type="submit" class="btn" tal:attributes="value view/submit_button"/>
+
+</form>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/tests.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/tests.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/interswitch/tests.py	(revision 8249)
@@ -0,0 +1,108 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from hurry.workflow.interfaces import IWorkflowState
+from waeup.kofa.students.tests.test_browser import StudentsFullSetup
+from waeup.uniben.testing import FunctionalLayer
+
+# Also run tests that send requests to external servers?
+#   If you enable this, please make sure the external services
+#   do exist really and are not bothered by being spammed by a test programme.
+EXTERNAL_TESTS = False
+
+def external_test(func):
+    if not EXTERNAL_TESTS:
+        myself = __file__
+        if myself.endswith('.pyc'):
+            myself = myself[:-2]
+        print "WARNING: external tests are skipped!"
+        print "WARNING: edit %s to enable them." % myself
+        return
+    return func
+
+
+class InterswitchTests(StudentsFullSetup):
+    """Tests for the Interswitch payment gateway.
+    """
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(InterswitchTests, self).setUp()
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.payments_path)
+        IWorkflowState(self.student).setState('cleared')
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...ticket created...',
+                           self.browser.contents)
+        ctrl = self.browser.getControl(name='val_id')
+        value = ctrl.options[0]
+        self.browser.getLink(value).click()
+        self.assertMatches('...Amount Authorized...',
+                           self.browser.contents)
+        self.payment_url = self.browser.url
+
+
+    def callback_url(self, payment_url, resp, apprAmt):
+        return payment_url + (
+            '/isw_callback?echo=' +
+            '&resp=%s' +
+            '&desc=Something went wrong' +
+            '&txnRef=p1331792385335' +
+            '&payRef=' + '&retRef=' +
+            '&cardNum=0' +
+            '&apprAmt=%s' +
+            '&url=http://xyz') % (resp, apprAmt)
+
+    def test_interswitch_form(self):
+
+        # Manager can access InterswitchForm
+        self.browser.getLink("CollegePAY", index=0).click()
+        self.assertMatches('...Total Amount Authorized:...',
+                           self.browser.contents)
+        self.assertMatches(
+            '...<input type="hidden" name="amount" value="4000000.0" />...',
+            self.browser.contents)
+
+    @external_test
+    def test_callback(self):
+
+        # Manager can call callback manually
+        self.browser.open(self.callback_url(self.payment_url, 'XX', '300'))
+        self.assertMatches('...Unsuccessful callback: Something went wrong...',
+                          self.browser.contents)
+        self.assertMatches('...Failed...',
+                           self.browser.contents)
+        self.browser.open(self.payment_url + '/isw_callback')
+        self.assertMatches('...Unsuccessful callback: Incomplete query string...',
+                          self.browser.contents)
+        self.assertMatches('...Failed...',
+                           self.browser.contents)
+        self.browser.open(self.callback_url(self.payment_url, '00', '300000'))
+        self.assertMatches('...Wrong amount...',
+                          self.browser.contents)
+        self.browser.open(self.callback_url(self.payment_url, '00', '4000000'))
+        self.assertMatches('...Valid callback received...',
+                          self.browser.contents)
+
+    @external_test
+    def test_webservice(self):
+
+        self.browser.open(self.payment_url + '/request_webservice')
+        self.assertMatches('...Unsuccessful callback...',
+                          self.browser.contents)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/locales.zcml
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/locales.zcml	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/locales.zcml	(revision 8249)
@@ -0,0 +1,8 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:i18n="http://namespaces.zope.org/i18n">
+
+  <include package="zope.i18n" file="meta.zcml" />
+  <i18n:registerTranslations directory="locales" />
+  <include package="waeup.kofa" file="locales.zcml" />
+
+</configure>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/mail.zcml
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/mail.zcml	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/mail.zcml	(revision 8249)
@@ -0,0 +1,82 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:mail="http://namespaces.zope.org/mail">
+  <!--
+
+   SMTP Settings
+   *************
+
+   In here we define the mailers and mail deliveries we want to be
+   used by the portal.
+
+   They are set here (and not dynamically in the portal) to increase
+   security. Even portal users with all permissions cannot change mail
+   server credentials and related. You need filesystem access to
+   change/override the settings in here.
+
+   In the portal you can pick one of the deliveries for use with all
+   SMTP (aka mail) related functionality.
+
+   Each delivery (direct or queued) is bound to a certain mailer,
+   defined by a 'mail:smtpMailer' directive.
+
+   The smtpMailer directives define real mail hosts (local or remote)
+   where mail from the portal should be processed.
+
+   The 'mail:directDelivery' and 'mail:queuedDelivery' directives send
+   local mail to the mailer set in their 'mailer' attribute. While
+   directDelivery sends mail immediately when a request is finished
+   (see zope.sendmail for more info), queuedDelivery handles mail in a
+   background thread and sends mail independently from requests.
+
+   By default in Kofa we have a fake mailer activated, that does not
+   send real mail to the outside world.
+  -->
+
+  <!-- A mail server on localhost -->
+  <!-- Mail server definitions require the following attributes:
+
+        - name: (string) name to be used by deliveries
+
+       Mail server definitions allow the following additional attribs:
+
+        - hostname   (string) hostname or IP(?) of mail server to use
+                              ('localhost' by default)
+        - port       (int number) port to connect to SMTP mailer
+                              (25 by default)
+        - username   (string) Username to log in to mail server
+        - password   (string) Password to log in to mail server
+
+  -->
+  <mail:smtpMailer
+      name="smtp.mailserver"
+      hostname="localhost"
+      port="25"
+      />
+
+  <!-- The mail deliveries -->
+  <!-- Mail deliveries require the following attributes:
+
+        - name:       (string) this string will appear in portal select
+                               boxes
+        - permission: (string) zope default perms only
+        - mailer:     (string) name of some mailer registered above or
+                               'smtp'
+        - queuePath:  (string) must exist and contain cur/, new/, and
+                               tmp/ dirs. Relative paths are relative
+                               to the directory this files lives in.
+
+   -->
+  <mail:queuedDelivery
+      name="Queued SMTP on mail server"
+      permission="zope.Public"
+      mailer="smtp.mailserver"
+      queuePath="../../../var/mailqueue"
+      />
+
+  <mail:directDelivery
+      name="Direct SMTP on mail server"
+      permission="zope.Public"
+      mailer="smtp.mailserver"
+      />
+
+</configure>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/meta.zcml
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/meta.zcml	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/meta.zcml	(revision 8249)
@@ -0,0 +1,12 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta"
+    xmlns:grok="http://namespaces.zope.org/grok">
+
+  <include package="grok" file="meta.zcml" />
+  <!-- include package="z3c.autoinclude" file="meta.zcml" / -->
+
+  <!-- Load the grokkers -->
+  <grok:grok package=".meta" />
+
+</configure>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/overrides.zcml
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/overrides.zcml	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/overrides.zcml	(revision 8249)
@@ -0,0 +1,15 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:grok="http://namespaces.zope.org/grok">
+  <includeDependencies package="." />
+  <grok:grok package="." />
+
+  <!-- Register edit widget for PhoneNumbers -->
+  <adapter
+      for="waeup.kofa.schema.interfaces.IPhoneNumber
+           zope.publisher.interfaces.browser.IBrowserRequest"
+      provides="zope.formlib.interfaces.ISimpleInputWidget"
+      factory="waeup.uniben.widgets.phonewidget.CustomPhoneWidget"
+      permission="zope.Public"
+      />
+
+</configure>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/__init__.py	(revision 8249)
@@ -0,0 +1,11 @@
+"""This package contains everything regarding payments.
+"""
+# Make this a package.
+from waeup.kofa.payments.container import PaymentsContainer
+from waeup.kofa.payments.payment import SCPayment, OnlinePayment
+
+__all__ = [
+    'PaymentsContainer',
+    'SCPayment',
+    'OnlinePayment',
+    ]
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/interfaces.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/interfaces.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/interfaces.py	(revision 8249)
@@ -0,0 +1,89 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from zope.interface import Attribute
+from zope import schema
+from waeup.kofa.payments.interfaces import IPayment
+from waeup.kofa.interfaces import MessageFactory as _
+
+class ICustomOnlinePayment(IPayment):
+    """A payment via payment gateways.
+
+    """
+
+    surcharge_1 = schema.Float(
+        title = _(u'Portal Fee'),
+        default = 0.0,
+        required = False,
+        readonly = True,
+        )
+
+    surcharge_2 = schema.Float(
+        title = _(u'Surcharge 2'),
+        default = 0.0,
+        required = False,
+        readonly = True,
+        )
+
+    surcharge_3 = schema.Float(
+        title = _(u'Surcharge 3'),
+        default = 0.0,
+        required = False,
+        readonly = True,
+        )
+
+    ac = schema.TextLine(
+        title = _(u'Activation Code'),
+        default = None,
+        required = False,
+        readonly = False,
+        )
+
+    r_amount_approved = schema.Float(
+        title = _(u'Response Amount Approved'),
+        default = 0.0,
+        required = False,
+        readonly = False,
+        )
+
+    r_desc = schema.TextLine(
+        title = _(u'Response Description'),
+        default = None,
+        required = False,
+        readonly = False,
+        )
+
+    r_pay_reference = schema.TextLine(
+        title = _(u'Response Payment Reference'),
+        default = None,
+        required = False,
+        readonly = False,
+        )
+
+    r_code = schema.TextLine(
+        title = _(u'Response Code'),
+        default = None,
+        required = False,
+        readonly = False,
+        )
+
+    r_card_num = schema.TextLine(
+        title = _(u'Response Card Number'),
+        default = None,
+        required = False,
+        readonly = False,
+        )
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/payment.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/payment.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/payments/payment.py	(revision 8249)
@@ -0,0 +1,32 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+These are the payment tickets.
+"""
+import grok
+from waeup.kofa.utils.helpers import attrs_to_fields
+from waeup.kofa.payments.payment import Payment
+from waeup.uniben.payments.interfaces import ICustomOnlinePayment
+
+class CustomOnlinePayment(Payment):
+    """This is an online payment.
+    """
+    grok.implements(ICustomOnlinePayment)
+    grok.provides(ICustomOnlinePayment)
+
+CustomOnlinePayment = attrs_to_fields(CustomOnlinePayment)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/batching.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/batching.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/batching.py	(revision 8249)
@@ -0,0 +1,34 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Batch processing components for student objects.
+
+Batch processors eat CSV files to add, update or remove large numbers
+of certain kinds of objects at once.
+
+Here we define the processors for students specific objects like
+students, studycourses, payment tickets and accommodation tickets.
+"""
+from waeup.uniben.students.interfaces import (
+    ICustomStudent,
+    )
+from waeup.kofa.students.batching import StudentProcessor
+
+class CustomStudentProcessor(StudentProcessor):
+    """A batch processor for IStudent objects.
+    """
+    iface = ICustomStudent
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/browser.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/browser.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/browser.py	(revision 8249)
@@ -0,0 +1,183 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import grok
+from zope.formlib.textwidgets import BytesDisplayWidget
+from zope.component import getUtility
+from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
+from waeup.kofa.interfaces import IExtFileStore
+from waeup.kofa.browser.layout import action
+from waeup.kofa.students.browser import (
+    StudentPersonalDisplayFormPage,
+    StudentClearanceManageFormPage, StudentClearanceEditFormPage,
+    StudentClearanceDisplayFormPage, OnlinePaymentCallbackPage,
+    ExportPDFClearanceSlipPage, StudentBaseManageFormPage,
+    StudentBaseEditFormPage, StudentPersonalEditFormPage,
+    OnlinePaymentDisplayFormPage, OnlinePaymentAddFormPage,
+    OnlinePaymentBreadcrumb)
+from waeup.kofa.students.viewlets import RequestCallbackActionButton
+from waeup.uniben.students.interfaces import (
+    ICustomStudentBase, ICustomStudent, ICustomStudentPersonal,
+    ICustomUGStudentClearance,ICustomPGStudentClearance,
+    ICustomStudentOnlinePayment,
+    )
+from waeup.uniben.interfaces import MessageFactory as _
+
+class CustomOnlinePaymentBreadcrumb(OnlinePaymentBreadcrumb):
+    """A breadcrumb for payments.
+    """
+    grok.context(ICustomStudentOnlinePayment)
+
+class RequestCallbackActionButton(RequestCallbackActionButton):
+    """ Do not display the base package callback button in custom pages.
+    """
+    @property
+    def target_url(self):
+        return ''
+
+class CustomOnlinePaymentCallbackPage(OnlinePaymentCallbackPage):
+    """ Neutralize callback simulation view
+    """
+    def update(self):
+        return
+
+class CustomStudentBaseManageFormPage(StudentBaseManageFormPage):
+    """ View to manage student base data
+    """
+    form_fields = grok.AutoFields(ICustomStudentBase).omit('student_id')
+
+class CustomStudentBaseEditFormPage(StudentBaseEditFormPage):
+    """ View to edit student base data
+    """
+    form_fields = grok.AutoFields(ICustomStudentBase).select(
+        'email', 'phone')
+
+
+class CustomStudentPersonalDisplayFormPage(StudentPersonalDisplayFormPage):
+    """ Page to display student personal data
+    """
+    grok.context(ICustomStudent)
+    form_fields = grok.AutoFields(ICustomStudentPersonal)
+    form_fields['perm_address'].custom_widget = BytesDisplayWidget
+
+
+class CustomStudentPersonalEditFormPage(StudentPersonalEditFormPage):
+    """ Page to edit personal data
+    """
+    form_fields = grok.AutoFields(ICustomStudentPersonal)
+
+
+class CustomStudentClearanceDisplayFormPage(StudentClearanceDisplayFormPage):
+    """ Page to display student clearance data
+    """
+    grok.context(ICustomStudent)
+
+    @property
+    def form_fields(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            form_fields = grok.AutoFields(
+                ICustomPGStudentClearance).omit('clearance_locked')
+        else:
+            form_fields = grok.AutoFields(
+                ICustomUGStudentClearance).omit('clearance_locked')
+        return form_fields
+
+class CustomExportPDFClearanceSlipPage(ExportPDFClearanceSlipPage):
+    """Deliver a PDF slip of the context.
+    """
+    grok.context(ICustomStudent)
+
+    @property
+    def form_fields(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            form_fields = grok.AutoFields(
+                ICustomPGStudentClearance).omit('clearance_locked')
+        else:
+            form_fields = grok.AutoFields(
+                ICustomUGStudentClearance).omit('clearance_locked')
+        return form_fields
+
+class CustomStudentClearanceManageFormPage(StudentClearanceManageFormPage):
+    """ Page to edit student clearance data
+    """
+    grok.context(ICustomStudent)
+
+    @property
+    def form_fields(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            form_fields = grok.AutoFields(ICustomPGStudentClearance)
+        else:
+            form_fields = grok.AutoFields(ICustomUGStudentClearance)
+        return form_fields
+
+class CustomStudentClearanceEditFormPage(StudentClearanceEditFormPage):
+    """ View to edit student clearance data by student
+    """
+    grok.context(ICustomStudent)
+
+    @property
+    def form_fields(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit('clearance_locked')
+        else:
+            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit('clearance_locked')
+        return form_fields
+
+    def dataNotComplete(self):
+        store = getUtility(IExtFileStore)
+        if not store.getFileByContext(self.context, attr=u'birth_certicicate.jpg'):
+            return _('No birth certificate uploaded.')
+        if not store.getFileByContext(self.context, attr=u'ref_let.jpg'):
+            return _('No referee letter uploaded.')
+        if not store.getFileByContext(self.context, attr=u'acc_let.jpg'):
+            return _('No acceptance letter uploaded.')
+        if not store.getFileByContext(self.context, attr=u'fst_sit_scan.jpg'):
+            return _('No first sitting result uploaded.')
+        return False
+
+class CustomOnlinePaymentDisplayFormPage(OnlinePaymentDisplayFormPage):
+    """ Page to view an online payment ticket
+    """
+    grok.context(ICustomStudentOnlinePayment)
+    form_fields = grok.AutoFields(ICustomStudentOnlinePayment)
+    form_fields[
+        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
+    form_fields[
+        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
+    grok.template('payment_view')
+
+    @property
+    def transaction_code(self):
+        tcode = self.context.p_id
+        return tcode[len(tcode)-8:len(tcode)]
+
+class CustomOnlinePaymentAddFormPage(OnlinePaymentAddFormPage):
+    """ Page to add an online payment ticket
+    """
+    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
+        'p_category')
+    factory = u'waeup.CustomStudentOnlinePayment'
+
+    def _fillCustomFields(self, payment, pay_details):
+        payment.surcharge_1 = pay_details['surcharge_1']
+        payment.surcharge_2 = pay_details['surcharge_2']
+        payment.surcharge_3 = pay_details['surcharge_3']
+        return payment
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/browser_templates/payment_view.pt
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/browser_templates/payment_view.pt	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/browser_templates/payment_view.pt	(revision 8249)
@@ -0,0 +1,18 @@
+<table class="form-table" i18n:domain="waeup.uniben"
+  tal:define="files provider:files">
+  <tbody>
+    <tal:widgets content="structure provider:widgets" />
+    <tr tal:condition="python: files.replace('\n','')">
+      <td class="separator" colspan=2 i18n:translate="">
+        Uploaded Files
+      </td>
+    </tr>
+    <tal:files content="structure files" />
+    <tr>
+      <td class="fieldname">
+        <span i18n:translate="">Transaction Code</span>:
+      </td>
+      <td tal:content="view/transaction_code">TRANSACTIONCODE</td>
+    </tr>
+  </tbody>
+</table>
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/interfaces.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/interfaces.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/interfaces.py	(revision 8249)
@@ -0,0 +1,346 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from zope import schema
+from waeup.kofa.schema import TextLineChoice
+from waeup.kofa.interfaces import SimpleKofaVocabulary, academic_sessions_vocab
+from waeup.kofa.schema import FormattedDate
+from waeup.kofa.schoolgrades import ResultEntryField
+from waeup.kofa.students.vocabularies import nats_vocab
+from waeup.kofa.students.interfaces import (
+    IStudentBase,IUGStudentClearance,IPGStudentClearance,
+    IStudentPersonal,IStudentNavigation,
+    )
+from waeup.kofa.students.vocabularies import (
+    nats_vocab, contextual_reg_num_source)
+from waeup.uniben.interfaces import (
+    lgas_vocab, high_qual, high_grade, exam_types)
+from waeup.uniben.interfaces import MessageFactory as _
+from waeup.uniben.payments.interfaces import ICustomOnlinePayment
+
+class ICustomStudentBase(IStudentBase):
+    """Representation of student base data.
+
+    """
+
+    reg_number = TextLineChoice(
+        title = _(u'Registration Number'),
+        required = False,
+        readonly = False,
+        source = contextual_reg_num_source,
+        )
+
+class ICustomStudentPersonal(IStudentPersonal):
+    """Student personal data.
+
+    """
+
+    marit_stat = schema.Choice(
+        title = u'Maritual Status',
+        default = 'unmarried',
+        required = False,
+        vocabulary = SimpleKofaVocabulary(
+            (_('Unmarried'), 'unmarried'),
+            (_('Married'), 'married'),)
+        )
+
+class ICustomUGStudentClearance(IUGStudentClearance):
+    """Representation of ug student clearance data.
+
+    """
+    date_of_birth = FormattedDate(
+        title = _(u'Date of Birth'),
+        required = False,
+        )
+
+    nationality = schema.Choice(
+        source = nats_vocab,
+        title = _(u'Nationality'),
+        required = False,
+        )
+
+    lga = schema.Choice(
+        source = lgas_vocab,
+        title = _(u'State/LGA (Nigerians only)'),
+        required = False,
+        )
+
+    def_adm = schema.Bool(
+        title = _(u'Deferent of Admission'),
+        required = False,
+        readonly = False,
+        )
+
+    fst_sit_fname = schema.TextLine(
+        title = _(u'Full Name'),
+        required = False,
+        readonly = False,
+        )
+    fst_sit_no = schema.TextLine(
+        title = _(u'Exam Number'),
+        required = False,
+        readonly = False,
+        )
+
+    fst_sit_date = FormattedDate(
+        title = _(u'Exam Date'),
+        required = False,
+        readonly = False,
+        )
+
+    fst_sit_type = schema.Choice(
+        title = _(u'Exam Type'),
+        required = False,
+        readonly = False,
+        vocabulary = exam_types,
+        )
+
+    fst_sit_results = schema.List(
+        title = _(u'Exam Results'),
+        value_type = ResultEntryField(),
+        required = False,
+        readonly = False,
+        default = [],
+        )
+
+    scd_sit_fname = schema.TextLine(
+        title = _(u'Full Name'),
+        required = False,
+        readonly = False,
+        )
+    scd_sit_no = schema.TextLine(
+        title = _(u'Exam Number'),
+        required = False,
+        readonly = False,
+        )
+
+    scd_sit_date = FormattedDate(
+        title = _(u'Exam Date'),
+        required = False,
+        readonly = False,
+        )
+
+    scd_sit_type = schema.Choice(
+        title = _(u'Exam Type'),
+        required = False,
+        readonly = False,
+        vocabulary = exam_types,
+        )
+
+    scd_sit_results = schema.List(
+        title = _(u'Exam Results'),
+        value_type = ResultEntryField(),
+        required = False,
+        readonly = False,
+        default = [],
+        )
+
+    alr_fname = schema.TextLine(
+        title = _(u'Full Name'),
+        required = False,
+        readonly = False,
+        )
+    alr_no = schema.TextLine(
+        title = _(u'Exam Number'),
+        required = False,
+        readonly = False,
+        )
+
+    alr_date = FormattedDate(
+        title = _(u'Exam Date'),
+        required = False,
+        readonly = False,
+        )
+
+    alr_results = schema.List(
+        title = _(u'Exam Results'),
+        value_type = ResultEntryField(),
+        required = False,
+        readonly = False,
+        default = [],
+        )
+
+    hq_type = schema.Choice(
+        title = _(u'Qualification Obtained'),
+        required = False,
+        readonly = False,
+        vocabulary = high_qual,
+        )
+
+    hq_matric_no = schema.TextLine(
+        title = _(u'Former Matric Number'),
+        required = False,
+        readonly = False,
+        )
+
+    hq_degree = schema.Choice(
+        title = _(u'Class of Degree'),
+        required = False,
+        readonly = False,
+        vocabulary = high_grade,
+        )
+
+    hq_school = schema.TextLine(
+        title = _(u'Institution Attended'),
+        required = False,
+        readonly = False,
+        )
+
+    hq_session = schema.TextLine(
+        title = _(u'Years Attended'),
+        required = False,
+        readonly = False,
+        )
+
+    hq_disc = schema.TextLine(
+        title = _(u'Discipline'),
+        required = False,
+        readonly = False,
+        )
+
+
+class ICustomPGStudentClearance(IUGStudentClearance):
+    """Representation of pg student clearance data.
+
+    """
+
+    hq2_type = schema.Choice(
+        title = _(u'Qualification Obtained'),
+        required = False,
+        readonly = False,
+        vocabulary = high_qual,
+        )
+
+    hq2_matric_no = schema.TextLine(
+        title = _(u'Former Matric Number'),
+        required = False,
+        readonly = False,
+        )
+
+    hq2_degree = schema.Choice(
+        title = _(u'Class of Degree'),
+        required = False,
+        readonly = False,
+        vocabulary = high_grade,
+        )
+
+    hq2_school = schema.TextLine(
+        title = _(u'Institution Attended'),
+        required = False,
+        readonly = False,
+        )
+
+    hq2_session = schema.TextLine(
+        title = _(u'Years Attended'),
+        required = False,
+        readonly = False,
+        )
+
+    hq2_disc = schema.TextLine(
+        title = _(u'Discipline'),
+        required = False,
+        readonly = False,
+        )
+
+    nysc_year = schema.Int(
+        title = _(u'Nysc Year'),
+        required = False,
+        readonly = False,
+        )
+
+    nysc_lga = schema.Choice(
+        source = lgas_vocab,
+        title = _(u'Nysc Location'),
+        required = False,
+        )
+
+    employer = schema.TextLine(
+        title = _(u'Employer'),
+        required = False,
+        readonly = False,
+        )
+
+    emp_position = schema.TextLine(
+        title = _(u'Employer Position'),
+        required = False,
+        readonly = False,
+        )
+
+    emp_start = FormattedDate(
+        title = _(u'Start Date'),
+        required = False,
+        readonly = False,
+        )
+
+    emp_end = FormattedDate(
+        title = _(u'End Date'),
+        required = False,
+        readonly = False,
+        )
+
+    emp_reason = schema.TextLine(
+        title = _(u'Reason for Leaving'),
+        required = False,
+        readonly = False,
+        )
+
+    employer2 = schema.TextLine(
+        title = _(u'2nd Employer'),
+        required = False,
+        readonly = False,
+        )
+
+    emp2_position = schema.TextLine(
+        title = _(u'2nd Employer Position'),
+        required = False,
+        readonly = False,
+        )
+
+    emp2_start = FormattedDate(
+        title = _(u'Start Date'),
+        required = False,
+        readonly = False,
+        )
+    emp2_end = FormattedDate(
+        title = _(u'End Date'),
+        required = False,
+        readonly = False,
+        )
+
+    emp2_reason = schema.TextLine(
+        title = _(u'Reason for Leaving'),
+        required = False,
+        readonly = False,
+        )
+
+    uniben_matric = schema.TextLine(
+        title = _(u'If yes, matric number'),
+        required = False,
+        readonly = False,
+        )
+
+
+class ICustomStudent(ICustomStudentBase,ICustomUGStudentClearance,
+    ICustomPGStudentClearance,ICustomStudentPersonal):
+    """Representation of a student.
+
+    """
+
+class ICustomStudentOnlinePayment(ICustomOnlinePayment):
+    """A student payment via payment gateways.
+
+    """
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/payments.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/payments.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/payments.py	(revision 8249)
@@ -0,0 +1,57 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Student payment components.
+"""
+import grok
+from zope.component.interfaces import IFactory
+from zope.interface import implementedBy
+from waeup.kofa.students.interfaces import IStudentNavigation
+from waeup.kofa.payments import PaymentsContainer, OnlinePayment
+from waeup.kofa.utils.helpers import attrs_to_fields
+from waeup.uniben.students.interfaces import ICustomStudentOnlinePayment
+
+class CustomStudentOnlinePayment(OnlinePayment):
+    """This is an online payment.
+    """
+    grok.implements(ICustomStudentOnlinePayment, IStudentNavigation)
+    grok.provides(ICustomStudentOnlinePayment)
+
+    def __init__(self):
+        super(CustomStudentOnlinePayment, self).__init__()
+        return
+
+    def getStudent(self):
+        return self.__parent__.__parent__
+
+CustomStudentOnlinePayment = attrs_to_fields(CustomStudentOnlinePayment)
+
+# Student online payments must be importable. So we might need a factory.
+class CustomStudentOnlinePaymentFactory(grok.GlobalUtility):
+    """A factory for student online payments.
+    """
+    grok.implements(IFactory)
+    grok.name(u'waeup.CustomStudentOnlinePayment')
+    title = u"Create a new online payment.",
+    description = u"This factory instantiates new online payment instances."
+
+    def __call__(self, *args, **kw):
+        return CustomStudentOnlinePayment()
+
+    def getInterfaces(self):
+        return implementedBy(CustomStudentOnlinePayment)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/student.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/student.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/student.py	(revision 8249)
@@ -0,0 +1,50 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Container for the various objects owned by students.
+"""
+import grok
+from zope.interface import implementedBy
+from waeup.kofa.utils.helpers import attrs_to_fields
+from waeup.kofa.students.student import Student, StudentFactory
+from waeup.uniben.students.interfaces import ICustomStudent, IStudentNavigation
+
+
+class CustomStudent(Student):
+    """This is a student container for the various objects
+    owned by students.
+    """
+    grok.implements(ICustomStudent, IStudentNavigation)
+    grok.provides(ICustomStudent)
+
+
+# Set all attributes of Student required in IStudent as field
+# properties. Doing this, we do not have to set initial attributes
+# ourselves and as a bonus we get free validation when an attribute is
+# set.
+CustomStudent = attrs_to_fields(CustomStudent)
+
+class CustomStudentFactory(StudentFactory):
+    """A factory for students.
+    """
+
+    def __call__(self, *args, **kw):
+        return CustomStudent()
+
+    def getInterfaces(self):
+        return implementedBy(CustomStudent)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/sample_student_data.csv
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/sample_student_data.csv	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/sample_student_data.csv	(revision 8249)
@@ -0,0 +1,4 @@
+firstname,lastname,reg_number,date_of_birth,matric_number,email,phone,sex
+Aaren,Pieri,1,,100000,aa@aa.ng,1234,m
+Aaren,Finau,2,,100001,aa@aa.ng,1234,m
+Aaren,Berson,3,,100002,aa@aa.ng,1234,m
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/test_browser.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/test_browser.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/tests/test_browser.py	(revision 8249)
@@ -0,0 +1,168 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import os
+import shutil
+import tempfile
+from hurry.workflow.interfaces import IWorkflowState
+from zope.component.hooks import setSite, clearSite
+from waeup.kofa.app import University
+from waeup.kofa.students.tests.test_browser import StudentsFullSetup
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.kofa.students.batching import StudentProcessor
+from waeup.uniben.students.batching import CustomStudentProcessor
+from waeup.uniben.testing import FunctionalLayer
+
+STUDENT_SAMPLE_DATA = open(
+    os.path.join(os.path.dirname(__file__), 'sample_student_data.csv'),
+    'rb').read()
+
+STUDENT_HEADER_FIELDS = STUDENT_SAMPLE_DATA.split(
+    '\n')[0].split(',')
+
+class StudentProcessorTest(FunctionalTestCase):
+    """Perform some batching tests.
+    """
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(StudentProcessorTest, self).setUp()
+        # Setup a sample site for each test
+        app = University()
+        self.dc_root = tempfile.mkdtemp()
+        app['datacenter'].setStoragePath(self.dc_root)
+
+        # Prepopulate the ZODB...
+        self.getRootFolder()['app'] = app
+        # we add the site immediately after creation to the
+        # ZODB. Catalogs and other local utilities are not setup
+        # before that step.
+        self.app = self.getRootFolder()['app']
+        # Set site here. Some of the following setup code might need
+        # to access grok.getSite() and should get our new app then
+        setSite(app)
+
+        self.processor_base = StudentProcessor()
+        self.processor = CustomStudentProcessor()
+        self.workdir = tempfile.mkdtemp()
+        self.csv_file = os.path.join(self.workdir, 'sample_student_data.csv')
+        open(self.csv_file, 'wb').write(STUDENT_SAMPLE_DATA)
+
+    def tearDown(self):
+        super(StudentProcessorTest, self).tearDown()
+        shutil.rmtree(self.workdir)
+        shutil.rmtree(self.dc_root)
+        clearSite()
+        return
+
+    def test_import(self):
+        # We have an empty column 'date_of_birth' in  the import file.
+        # The original processor will fail because 'date_of_birth' is required
+        # in the base package.
+        num, num_warns, fin_file, fail_file = self.processor_base.doImport(
+            self.csv_file, STUDENT_HEADER_FIELDS)
+        self.assertEqual(num_warns,3)
+        assert len(self.app['students'].keys()) == 0
+        # The customized processor does not complain since 'date_of_birth' is
+        # not required in the custom package.
+        num, num_warns, fin_file, fail_file = self.processor.doImport(
+            self.csv_file, STUDENT_HEADER_FIELDS)
+        #print open(fail_file).read()
+        self.assertEqual(num_warns,0)
+        assert len(self.app['students'].keys()) == 3
+        shutil.rmtree(os.path.dirname(fin_file))
+
+
+class StudentUITests(StudentsFullSetup):
+    """Tests for customized student class views and pages
+    """
+
+    layer = FunctionalLayer
+
+    def test_manage_payments(self):
+        # Add missing configuration data
+        self.app['configuration']['2004'].gown_fee = 150.0
+        self.app['configuration']['2004'].transfer_fee = 90.0
+        self.app['configuration']['2004'].clearance_fee = 120.0
+        self.app['configuration']['2004'].maint_fee = 180.0
+
+        # Managers can add online payment tickets
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.payments_path)
+        self.browser.getControl("Add online payment ticket").click()
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...Amount could not be determined...',
+                           self.browser.contents)
+        IWorkflowState(self.student).setState('cleared')
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...ticket created...',
+                           self.browser.contents)
+        ctrl = self.browser.getControl(name='val_id')
+        value = ctrl.options[0]
+        self.browser.getLink(value).click()
+        self.assertMatches('...Amount Authorized...',
+                           self.browser.contents)
+        # Set ticket paid
+        ticket = self.student['payments'].items()[0][1]
+        ticket.p_state = 'paid'
+        IWorkflowState(self.student).setState('returning')
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...This type of payment has already been made...',
+                           self.browser.contents)
+        # Remove all payments so that we can add a school fee payment again
+        keys = [i for i in self.student['payments'].keys()]
+        for payment in keys:
+            del self.student['payments'][payment]
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...ticket created...',
+                           self.browser.contents)
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(name="form.p_category").value = ['gown']
+        self.browser.getControl("Create ticket").click()
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(name="form.p_category").value = ['transfer']
+        self.browser.getControl("Create ticket").click()
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(
+            name="form.p_category").value = ['bed_allocation']
+        self.browser.getControl("Create ticket").click()
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(
+            name="form.p_category").value = ['hostel_maintenance']
+        self.browser.getControl("Create ticket").click()
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(name="form.p_category").value = ['clearance']
+        self.browser.getControl("Create ticket").click()
+        self.certificate.study_mode = 'ug_pt'
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(name="form.p_category").value = ['schoolfee']
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...Amount could not be determined...',
+                           self.browser.contents)
+
+        # If the session configuration doesn't exist and error message will
+        # be shown
+        del self.app['configuration']['2004']
+        self.browser.open(self.payments_path)
+        self.browser.getControl("Add online payment ticket").click()
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...Session configuration object is not...',
+                           self.browser.contents)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/utils.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/utils.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/utils.py	(revision 8249)
@@ -0,0 +1,162 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import grok
+from waeup.kofa.students.workflow import CLEARED, RETURNING
+from waeup.kofa.students.utils import StudentsUtils
+from waeup.kofa.students.interfaces import IStudentsUtils
+from waeup.kofa.accesscodes import create_accesscode
+from waeup.uniben.interfaces import MessageFactory as _
+
+def get_school_fee(student, surcharge):
+    study_mode = student['studycourse'].certificate.study_mode
+    entry_mode = student['studycourse'].entry_mode
+    state = student.state
+    #lga = student.lga
+    lga = 'nothing'
+    current_level = student['studycourse'].current_level
+
+    if study_mode.endswith('_ft'):
+        # fresh
+        if state == CLEARED:
+            return 40000.0 - surcharge
+        # returning
+        elif state == RETURNING:
+            return 20000.0 - surcharge
+        else:
+            return 0.0
+    else:
+        return 0.0
+
+def actions_after_student_payment(student, payment, view):
+    if payment.p_category == 'clearance':
+        # Create CLR access code
+        pin, error = create_accesscode('CLR',0,student.student_id)
+        if error:
+            view.flash(_('Valid callback received. ${a}',
+                mapping = {'a':error}))
+            return
+        payment.ac = pin
+    elif payment.p_category == 'schoolfee':
+        # Create SFE access code
+        pin, error = create_accesscode('SFE',0,student.student_id)
+        if error:
+            view.flash(_('Valid callback received. ${a}',
+                mapping = {'a':error}))
+            return
+        payment.ac = pin
+    elif payment.p_category == 'bed_allocation':
+        # Create HOS access code
+        pin, error = create_accesscode('HOS',0,student.student_id)
+        if error:
+            view.flash(_('Valid callback received. ${a}',
+                mapping = {'a':error}))
+            return
+        payment.ac = pin
+    view.flash(_('Valid callback received.'))
+    return
+
+class CustomStudentsUtils(StudentsUtils):
+    """A collection of customized methods.
+
+    """
+    grok.implements(IStudentsUtils)
+
+    # not yet changed
+    def setReturningData(self, student):
+        student['studycourse'].current_level += 100
+        student['studycourse'].current_session += 1
+        verdict = student['studycourse'].current_verdict
+        student['studycourse'].current_verdict = '0'
+        student['studycourse'].previous_verdict = verdict
+        return
+
+    def getPaymentDetails(self, category, student):
+        d = {}
+        d['surcharge_1'] = d['surcharge_2'] = d['surcharge_3'] = 0.0
+        d['p_item'] = u''
+        d['amount'] = 0.0
+        d['error'] = u''
+        d['p_session'] = student['studycourse'].current_session
+        session = str(d['p_session'])
+        try:
+            academic_session = grok.getSite()['configuration'][session]
+        except KeyError:
+            d['error'] = _(u'Session configuration object is not available.')
+            return d
+        if category == 'transfer':
+            d['amount'] = academic_session.transfer_fee
+        elif category == 'gown':
+            d['amount'] = academic_session.gown_fee
+        elif category == 'bed_allocation':
+            d['amount'] = academic_session.booking_fee
+        elif category == 'hostel_maintenance':
+            d['amount'] = academic_session.maint_fee
+        elif category == 'clearance':
+            d['p_item'] = student['studycourse'].certificate.code
+            d['amount'] = academic_session.clearance_fee
+        elif category == 'schoolfee':
+            d['surcharge_1'] = academic_session.surcharge_1
+            d['surcharge_2'] = academic_session.surcharge_2
+            d['amount'] = get_school_fee(student, d['surcharge_1'] + d['surcharge_2'])
+            code = student['studycourse'].certificate.code
+            d['p_item'] = code
+            d['p_session'] += 1
+        if d['amount'] == 0.0:
+            d['error'] = _(u'Amount could not be determined.')
+        return d
+
+    VERDICTS_DICT = {
+        '0': 'not yet',
+        'A': 'Successful student',
+        'B': 'Student with carryover courses',
+        'C': 'Student on probation',
+        'D': 'Withdrawn from the faculty',
+        'E': 'Student who were previously on probation',
+        'F': 'Medical case',
+        'G': 'Absent from examination',
+        'H': 'Withheld results',
+        'I': 'Expelled/rusticated/suspended student',
+        'J': 'Temporary withdrawn from the university',
+        'K': 'Unregistered student',
+        'L': 'Referred student',
+        'M': 'Reinstatement',
+        'N': 'Student on transfer',
+        'O': 'NCE-III repeater',
+        'Y': 'No previous verdict',
+        'X': 'New 300 level student',
+        'Z': 'Successful student (provisional)',
+        'A1': 'First Class',
+        'A2': 'Second Class Upper',
+        'A3': 'Second Class Lower',
+        'A4': 'Third Class',
+        'A5': 'Pass',
+        'A6': 'Distinction',
+        'A7': 'Credit',
+        'A8': 'Merit',
+        }
+
+    SEPARATORS_DICT = {
+        'form.fst_sit_fname': _(u'First Sitting Recod'),
+        'form.scd_sit_fname': _(u'Second Sitting Record'),
+        'form.alr_fname': _(u'Advanced Level Record'),
+        'form.hq_type': _(u'Higher Education Record'),
+        'form.hq2_type': _(u'Second Higher Education Record'),
+        'form.nysc_year': _(u'NYSC Information'),
+        'form.employer': _(u'Employment History'),
+        'form.uniben_matric': _(u'Former Uniben Student'),
+        }
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/viewlets.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/viewlets.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/students/viewlets.py	(revision 8249)
@@ -0,0 +1,514 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+import grok
+from waeup.kofa.students.viewlets import (
+    FileDisplay, FileUpload, Image)
+from waeup.kofa.students.browser import ExportPDFClearanceSlipPage
+
+from waeup.uniben.interfaces import MessageFactory as _
+
+# LGA Identification
+
+class LGAIdentificationDisplay(FileDisplay):
+    """LGA Identification display viewlet.
+    """
+    grok.order(1)
+    label = _(u'LGA Identification')
+    title = _(u'LGA Identification Scan')
+    download_name = u'lga_ident'
+
+class LGAIdentificationSlip(LGAIdentificationDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class LGAIdentificationUpload(FileUpload):
+    """LGA Identification upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'LGA Identification')
+    title = _(u'LGA Identification Scan')
+    mus = 1024 * 150
+    download_name = u'lga_ident'
+
+class LGAIdentificationImage(Image):
+    """Renders LGA Identification scan.
+    """
+    grok.name('lga_ident')
+    download_name = u'lga_ident'
+
+# First Sitting Result
+
+class FirstSittingResultDisplay(FileDisplay):
+    """First Sitting Result display viewlet.
+    """
+    grok.order(1)
+    label = _(u'First Sitting Result')
+    title = _(u'First Sitting Result')
+    download_name = u'fst_sit_scan'
+
+class FirstSittingResultSlip(FirstSittingResultDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class FirstSittingResultUpload(FileUpload):
+    """First Sitting Result upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'First Sitting Result')
+    title = _(u'First Sitting Result Scan')
+    mus = 1024 * 150
+    download_name = u'fst_sit_scan'
+
+class FirstSittingResultImage(Image):
+    """Renders First Sitting Result scan.
+    """
+    grok.name('fst_sit_scan')
+    download_name = u'fst_sit_scan'
+
+# Second Sitting Result
+
+class SecondSittingResultDisplay(FileDisplay):
+    """Second Sitting Result display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Second Sitting Result')
+    title = _(u'Second Sitting Result')
+    download_name = u'scd_sit_scan'
+
+class SecondSittingResultSlip(SecondSittingResultDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class SecondSittingResultUpload(FileUpload):
+    """Second Sitting Result upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Second Sitting Result')
+    title = _(u'Second Sitting Result Scan')
+    mus = 1024 * 150
+    download_name = u'scd_sit_scan'
+
+class SecondSittingResultImage(Image):
+    """Renders Second Sitting Result scan.
+    """
+    grok.name('scd_sit_scan')
+    download_name = u'scd_sit_scan'
+
+# Higher Qualification Result
+
+class HigherQualificationResultDisplay(FileDisplay):
+    """Higher Qualification Result display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Higher Qualification Result')
+    title = _(u'Higher Qualification Result')
+    download_name = u'hq_scan'
+
+class HigherQualificationResultSlip(HigherQualificationResultDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class HigherQualificationResultUpload(FileUpload):
+    """Higher Qualification Result upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Higher Qualification Result')
+    title = _(u'Higher Qualification Result Scan')
+    mus = 1024 * 150
+    download_name = u'hq_scan'
+
+class HigherQualificationResultImage(Image):
+    """Renders Higher Qualification Result scan.
+    """
+    grok.name('hq_scan')
+    download_name = u'hq_scan'
+
+# 2nd Higher Qualification Result (PG Students only)
+
+class SecondHigherQualificationResultDisplay(FileDisplay):
+    """Second Higher Qualification Result display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Second Higher Qualification Result')
+    title = _(u'Second Higher Qualification Result')
+    download_name = u'hq_scan2'
+
+class SecondHigherQualificationResultSlip(SecondHigherQualificationResultDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class SecondHigherQualificationResultUpload(FileUpload):
+    """Second Higher Qualification Result upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Second Higher Qualification Result')
+    title = _(u'Second Higher Qualification Result Scan')
+    mus = 1024 * 150
+    download_name = u'hq_scan2'
+
+    @property
+    def show_viewlet(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            return True
+        return False
+
+class SecondHigherQualificationResultImage(Image):
+    """Renders Second Higher Qualification Result scan.
+    """
+    grok.name('hq_scan2')
+    download_name = u'hq_scan2'
+
+# Advanced Level Result
+
+class AdvancedLevelResultDisplay(FileDisplay):
+    """Advanced Level Result display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Advanced Level Result')
+    title = _(u'Advanced Level Result')
+    download_name = u'alr_scan'
+
+class AdvancedLevelResultSlip(AdvancedLevelResultDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class AdvancedLevelResultUpload(FileUpload):
+    """Advanced Level Result upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Advanced Level Result')
+    title = _(u'Advanced Level Result Scan')
+    mus = 1024 * 150
+    download_name = u'alr_scan'
+
+class AdvancedLevelResultImage(Image):
+    """Renders Advanced Level Result scan.
+    """
+    grok.name('alr_scan')
+    download_name = u'alr_scan'
+
+# Certificate 
+
+class CertificateDisplay(FileDisplay):
+    """Certificate display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Certificate')
+    title = _(u'Certificate')
+    download_name = u'certificate'
+
+class CertificateSlip(CertificateDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class CertificateUpload(FileUpload):
+    """Certificate upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Certificate')
+    title = _(u'Certificate Scan')
+    mus = 1024 * 150
+    download_name = u'certificate'
+
+class CertificateImage(Image):
+    """Renders Certificate scan.
+    """
+    grok.name('certificate')
+    download_name = u'certificate'
+
+# Second Certificate (PG Students only)
+
+class SecondCertificateDisplay(FileDisplay):
+    """ Second Certificate display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Second Certificate')
+    title = _(u'Second Certificate')
+    download_name = u'certificate2'
+
+class SecondCertificateSlip(SecondCertificateDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class SecondCertificateUpload(FileUpload):
+    """Second Certificate upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Second Certificate')
+    title = _(u'Second Certificate Scan')
+    mus = 1024 * 150
+    download_name = u'certificate2'
+
+    @property
+    def show_viewlet(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            return True
+        return False
+
+class CertificateImage(Image):
+    """Renders Second Certificate scan.
+    """
+    grok.name('certificate2')
+    download_name = u'certificate2'
+
+# Third Certificate (PG Students only)
+
+class ThirdCertificateDisplay(FileDisplay):
+    """ Third Certificate display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Third Certificate')
+    title = _(u'Third Certificate')
+    download_name = u'certificate3'
+
+class ThirdCertificateSlip(ThirdCertificateDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class ThirdCertificateUpload(FileUpload):
+    """Third Certificate upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Third Certificate')
+    title = _(u'Third Certificate Scan')
+    mus = 1024 * 150
+    download_name = u'certificate3'
+
+    @property
+    def show_viewlet(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            return True
+        return False
+
+class CertificateImage(Image):
+    """Renders Third Certificate scan.
+    """
+    grok.name('certificate3')
+    download_name = u'certificate3'
+
+# Evidence of Name
+
+class EvidenceNameDisplay(FileDisplay):
+    """Evidence of Name display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Evidence of Name')
+    title = _(u'Evidence of Name')
+    download_name = u'evid'
+
+class EvidenceNameSlip(EvidenceNameDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class EvidenceNameUpload(FileUpload):
+    """Evidence of Name upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Evidence of Name')
+    title = _(u'Evidence of Name Scan')
+    mus = 1024 * 150
+    download_name = u'evid'
+
+class EvidenceNameImage(Image):
+    """Renders Evidence of Name scan.
+    """
+    grok.name('evid')
+    download_name = u'evid'
+
+# Result Statement
+
+class ResultStatementDisplay(FileDisplay):
+    """Result Statement display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Result Statement')
+    title = _(u'Result Statement')
+    download_name = u'res_stat'
+
+class ResultStatementSlip(ResultStatementDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class ResultStatementUpload(FileUpload):
+    """Result Statement upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Result Statement')
+    title = _(u'Result Statement Scan')
+    mus = 1024 * 150
+    download_name = u'res_stat'
+
+class ResultStatementImage(Image):
+    """Renders Result Statement scan.
+    """
+    grok.name('res_stat')
+    download_name = u'res_stat'
+
+# Referee Letter
+
+class RefereeLetterDisplay(FileDisplay):
+    """Referee Letter display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Referee Letter')
+    title = _(u'Referee Letter')
+    download_name = u'ref_let'
+
+class RefereeLetterSlip(RefereeLetterDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class RefereeLetterUpload(FileUpload):
+    """Referee Letter upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Referee Letter')
+    title = _(u'Referee Letter Scan')
+    mus = 1024 * 150
+    download_name = u'ref_let'
+
+class RefereeLetterImage(Image):
+    """Renders Referee Letter scan.
+    """
+    grok.name('ref_let')
+    download_name = u'ref_let'
+
+# Second Referee Letter (PG Students only)
+
+class SecondRefereeLetterDisplay(FileDisplay):
+    """Second Referee Letter display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Second Referee Letter')
+    title = _(u'Second Referee Letter')
+    download_name = u'ref_let2'
+
+class SecondRefereeLetterSlip(SecondRefereeLetterDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class SecondRefereeLetterUpload(FileUpload):
+    """Referee Letter upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Second Referee Letter')
+    title = _(u'Second Referee Letter Scan')
+    mus = 1024 * 150
+    download_name = u'ref_let2'
+
+    @property
+    def show_viewlet(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            return True
+        return False
+
+class SecondRefereeLetterImage(Image):
+    """Renders Referee Letter scan.
+    """
+    grok.name('ref_let2')
+    download_name = u'ref_let2'
+
+# Third Referee Letter (PG Students only)
+
+class ThirdRefereeLetterDisplay(FileDisplay):
+    """Third Referee Letter display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Third Referee Letter')
+    title = _(u'Third Referee Letter')
+    download_name = u'ref_let3'
+
+class ThirdRefereeLetterSlip(ThirdRefereeLetterDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class ThirdRefereeLetterUpload(FileUpload):
+    """Referee Letter upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Third Referee Letter')
+    title = _(u'Third Referee Letter Scan')
+    mus = 1024 * 150
+    download_name = u'ref_let3'
+
+    @property
+    def show_viewlet(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            return True
+        return False
+
+class ThirdRefereeLetterImage(Image):
+    """Renders Referee Letter scan.
+    """
+    grok.name('ref_let3')
+    download_name = u'ref_let3'
+
+# Statutory Declaration of Good Conduct
+
+class StatutoryDeclarationDisplay(FileDisplay):
+    """Statutory Declaration of Good Conduct display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Statutory Declaration of Good Conduct')
+    title = _(u'Statutory Declaration of Good Conduct')
+    download_name = u'stat_dec'
+
+class StatutoryDeclarationSlip(StatutoryDeclarationDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class StatutoryDeclarationUpload(FileUpload):
+    """Statutory Declaration of Good Conduct upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Statutory Declaration of Good Conduct')
+    title = _(u'Statutory Declaration of Good Conduct Scan')
+    mus = 1024 * 150
+    download_name = u'stat_dec'
+
+class StatutoryDeclarationImage(Image):
+    """Renders Statutory Declaration of Good Conduct scan.
+    """
+    grok.name('stat_dec')
+    download_name = u'stat_dec'
+
+# Letter of Admission (PG Students only)
+
+class LetterAdmissionDisplay(FileDisplay):
+    """Letter of Admission display viewlet.
+    """
+    grok.order(1)
+    label = _(u'Letter of Admission')
+    title = _(u'Letter of Admission')
+    download_name = u'admission_let'
+
+class LetterAdmissionSlip(LetterAdmissionDisplay):
+    grok.view(ExportPDFClearanceSlipPage)
+
+class LetterAdmissionUpload(FileUpload):
+    """Letter of Admission upload viewlet.
+    """
+    grok.order(2)
+    label = _(u'Letter of Admission')
+    title = _(u'Letter of Admission Scan')
+    mus = 1024 * 150
+    download_name = u'admission_let'
+
+    @property
+    def show_viewlet(self):
+        cm = getattr(self.context,'current_mode', None)
+        if cm is not None and cm.startswith('pg'):
+            return True
+        return False
+
+class LetterAdmissionImage(Image):
+    """Renders Letter of Admission scan.
+    """
+    grok.name('admission_let')
+    download_name = u'admission_let'
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/testing.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/testing.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/testing.py	(revision 8249)
@@ -0,0 +1,27 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Testing support for :mod:`waeup.uniben`.
+"""
+import os.path
+import waeup.uniben
+from zope.app.testing.functional import ZCMLLayer
+
+ftesting_zcml = os.path.join(
+    os.path.dirname(waeup.uniben.__file__), 'ftesting.zcml')
+FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer',
+                            allow_teardown=True)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/__init__.py	(revision 8249)
@@ -0,0 +1,2 @@
+# This is a package
+
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_configuration.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_configuration.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_configuration.py	(revision 8249)
@@ -0,0 +1,76 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Tests for configuration containers and related.
+"""
+from zope.component.interfaces import IFactory
+from zope.interface import verify
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.kofa.configuration import ConfigurationContainer
+from waeup.kofa.interfaces import IConfigurationContainer
+from waeup.kofa.tests.test_configuration import (
+    ConfigurationTest, SessionConfigurationFactoryTest)
+from waeup.uniben.configuration import (
+    CustomSessionConfiguration, CustomSessionConfigurationFactory)
+from waeup.uniben.interfaces import(
+    ICustomSessionConfiguration, ICustomSessionConfigurationAdd)
+from waeup.uniben.testing import FunctionalLayer
+
+class ConfigurationTest(ConfigurationTest):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(ConfigurationTest, self).setUp()
+        self.confcontainer = ConfigurationContainer()
+        self.sessionconf = CustomSessionConfiguration()
+        return
+
+    #def tearDown(self):
+    #    super(ConfigurationTest, self).tearDown()
+    #    return
+
+    def test_interfaces(self):
+        #verify.verifyClass(IConfigurationContainer, ConfigurationContainer)
+        #verify.verifyObject(IConfigurationContainer, self.confcontainer)
+        verify.verifyClass(ICustomSessionConfiguration, CustomSessionConfiguration)
+        verify.verifyObject(ICustomSessionConfiguration, self.sessionconf)
+        verify.verifyClass(ICustomSessionConfigurationAdd, CustomSessionConfiguration)
+        verify.verifyObject(ICustomSessionConfigurationAdd, self.sessionconf)
+
+class SessionConfigurationFactoryTest(SessionConfigurationFactoryTest):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(SessionConfigurationFactoryTest, self).setUp()
+        self.factory = CustomSessionConfigurationFactory()
+
+    #def tearDown(self):
+    #    super(SessionConfigurationFactoryTest, self).tearDown()
+
+    def test_interfaces(self):
+        verify.verifyClass(IFactory, CustomSessionConfigurationFactory)
+        verify.verifyObject(IFactory, self.factory)
+
+    def test_factory(self):
+        obj = self.factory()
+        assert isinstance(obj, CustomSessionConfiguration)
+
+    def test_getInterfaces(self):
+        implemented_by = self.factory.getInterfaces()
+        assert implemented_by.isOrExtends(ICustomSessionConfiguration)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_datacenter.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_datacenter.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_datacenter.py	(revision 8249)
@@ -0,0 +1,30 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from waeup.kofa.datacenter import DataCenter
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.uniben.testing import FunctionalLayer
+
+
+class DatacenterTests(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def test_storage_path(self):
+        mydatacenter = DataCenter()
+        storagepath = mydatacenter.storage
+        self.assertTrue('/parts/test/datacenter' in storagepath)
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_smtp.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_smtp.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/tests/test_smtp.py	(revision 8249)
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+# Tests for email-related components
+import base64
+import logging
+import tempfile
+import shutil
+import unittest
+from StringIO import StringIO
+from zope.component import getUtility
+from zope.component.hooks import setSite
+from zope.sendmail.interfaces import IMailDelivery
+from waeup.kofa.app import University
+from waeup.kofa.interfaces import IMailService
+from waeup.kofa.smtp import (
+    encode_header_item, encode_address, encode_body, FakeSMTPDelivery,
+    send_mail)
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.uniben.testing import FunctionalLayer
+
+#
+# SMTP test config
+#
+
+# Also run tests that send mail to external servers?
+#   If you enable this, please make sure the external smtp hosts and receivers
+#   do exist really and are not bothered by being spammed by a test programme.
+EXTERNAL_MAIL_TESTS = False
+
+# Maybe existing receiver of externally sent mail. If this mail account
+# exists really, it might receive mail from the tests!
+EXTERNAL_MAIL_RECEIVER = 'existing_address@waeup.org'
+
+# Names of mail deliveries to use when external mail tests are enabled.
+#   See local mail.zcml for names of available deliveries.
+EXTERNAL_DIRECT_DELIVERY = 'Direct SMTP on mail server'
+EXTERNAL_QUEUED_DELIVERY = 'Queued SMTP on mail server'
+
+#
+# end of SMTP test config
+#
+
+def external_mail_test(func):
+    if not EXTERNAL_MAIL_TESTS:
+        myself = __file__
+        if myself.endswith('.pyc'):
+            myself = myself[:-2]
+        print "WARNING: external mail tests are skipped!"
+        print "WARNING: edit %s to enable them." % myself
+        return
+    return func
+
+class ExternalMailerTests(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(ExternalMailerTests, self).setUp()
+        # Setup a sample site for each test
+        app = University()
+        self.dc_root = tempfile.mkdtemp()
+        app['datacenter'].setStoragePath(self.dc_root)
+
+        # Prepopulate the ZODB...
+        self.getRootFolder()['app'] = app
+        self.app = self.getRootFolder()['app']
+        return
+
+    def tearDown(self):
+        super(ExternalMailerTests, self).tearDown()
+        shutil.rmtree(self.dc_root)
+        return
+
+    def test_config_default_mailer(self):
+        # The default mailer set in config is 'no mailer'.
+        self.assertEqual(
+            getattr(self.app.get('configuration', None), 'smtp_mailer'),
+            u'No email service')
+        return
+
+    @external_mail_test
+    def test_send_direct_mail(self):
+        # send mail using direct mail delivery
+        self.app['configuration'].smtp_mailer = EXTERNAL_DIRECT_DELIVERY
+        setSite(self.app)
+        result = send_mail(
+            'test program', 'no-reply@waeup.org',
+            'test mail receiver', EXTERNAL_MAIL_RECEIVER,
+            'Test Mail from WAeUP Kofa',
+            'Hi from test mailer!\n\nRegards,\nTest Programme\n'
+            )
+        import transaction
+        transaction.commit() # The mail is really sent when transactions is
+                             # committed
+        self.assertTrue('@' in result)
+        return
+
+    @external_mail_test
+    def test_send_queued_mail(self):
+        # send mail using queued mail delivery
+        self.app['configuration'].smtp_mailer = EXTERNAL_QUEUED_DELIVERY
+        setSite(self.app)
+        result = send_mail(
+            'test program', 'no-reply@waeup.org',
+            'test mail receiver', EXTERNAL_MAIL_RECEIVER,
+            'Test Mail from WAeUP Kofa',
+            'Hi from test mailer!\n\nRegards,\nTest Programme\n'
+            )
+        import transaction
+        transaction.commit() # The mail is really sent when transactions is
+                             # committed
+        self.assertTrue('@' in result)
+        return
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/university/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/university/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/university/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/lgas.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/lgas.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/lgas.py	(revision 8249)
@@ -0,0 +1,881 @@
+LGAS = (
+    ('abia_aba_north','Abia / Aba North'),
+    ('abia_aba_south','Abia / Aba South'),
+    ('abia_arochukwu','Abia / Arochukwu'),
+    ('abia_bende','Abia / Bende'),
+    ('abia_ikawuno','Abia / Ikawuno'),
+    ('abia_ikwuano','Abia / Ikwuano'),
+    ('abia_isiala-ngwa-north','Abia / Isiala-Ngwa-North'),
+    ('abia_isiala-ngwa-south','Abia / Isiala-Ngwa-South'),
+    ('abia_isikwuato','Abia / Isikwuato'),
+    ('abia_isuikwuato','Abia / Isuikwuato'),
+    ('abia_nneochi','Abia / Nneochi'),
+    ('abia_obi_ngwa','Abia / Obi Ngwa'),
+    ('abia_obioma_ngwa_','Abia / Obioma Ngwa'),
+    ('abia_obioma-ngwa','Abia / Obioma-Ngwa'),
+    ('abia_ohafia','Abia / Ohafia'),
+    ('abia_ohaozara','Abia / Ohaozara'),
+    ('abia_osisioma','Abia / Osisioma'),
+    ('abia_ugwunagbo','Abia / Ugwunagbo'),
+    ('abia_ukwa_west','Abia / Ukwa West'),
+    ('abia_ukwu_east','Abia / Ukwu East'),
+    ('abia_umuahia','Abia / Umuahia'),
+    ('abia_umuahia_south','Abia / Umuahia South'),
+    ('abia_umuahia-north','Abia / Umuahia-North'),
+    ('abuja_abaji','Abuja / Abaji'),
+    ('abuja_amac','Abuja / Amac'),
+    ('abuja_bwari','Abuja / Bwari'),
+    ('abuja_kuje','Abuja / Kuje'),
+    ('abuja_gwagwalada','Abuja / Gwagwalada'),
+    ('abuja_kwali','Abuja / Kwali'),
+    ('abuja_municipal','Abuja / Municipal'),
+    ('adamawa_demsa','Adamawa / Demsa'),
+    ('adamawa_fufore','Adamawa / Fufore'),
+    ('adamawa_ganye','Adamawa / Ganye'),
+    ('adamawa_girei','Adamawa / Girei'),
+    ('adamawa_gombi','Adamawa / Gombi'),
+    ('adamawa_guyuk','Adamawa / Guyuk'),
+    ('adamawa_hong','Adamawa / Hong'),
+    ('adamawa_jada','Adamawa / Jada'),
+    ('adamawa_jimeta','Adamawa / Jimeta'),
+    ('adamawa_lamurde','Adamawa / Lamurde'),
+    ('adamawa_madagali','Adamawa / Madagali'),
+    ('adamawa_maiha','Adamawa / Maiha'),
+    ('adamawa_mayo-belwa','Adamawa / Mayo-Belwa'),
+    ('adamawa_michika','Adamawa / Michika'),
+    ('adamawa_mubi-north','Adamawa / Mubi-North'),
+    ('adamawa_mubi-south','Adamawa / Mubi-South'),
+    ('adamawa_numan','Adamawa / Numan'),
+    ('adamawa_shelleng','Adamawa / Shelleng'),
+    ('adamawa_song','Adamawa / Song'),
+    ('adamawa_toungo','Adamawa / Toungo'),
+    ('adamawa_yola','Adamawa / Yola'),
+    ('akwa_ibom_abak','Akwa Ibom / Abak'),
+    ('akwa_ibom_eastern-obolo','Akwa Ibom / Eastern-Obolo'),
+    ('akwa_ibom_eket','Akwa Ibom / Eket'),
+    ('akwa_ibom_ekpe-atani','Akwa Ibom / Ekpe-Atani'),
+    ('akwa_ibom_esit_ekit','Akwa Ibom / Esit Ekit'),
+    ('akwa_ibom_essien-udim','Akwa Ibom / Essien-Udim'),
+    ('akwa_ibom_etim-ekpo','Akwa Ibom / Etim-Ekpo'),
+    ('akwa_ibom_etinam','Akwa Ibom / Etinam'),
+    ('akwa_ibom_ibeno','Akwa Ibom / Ibeno'),
+    ('akwa_ibom_ibesikpo-asutan','Akwa Ibom / Ibesikpo-Asutan'),
+    ('akwa_ibom_ibiono-ibom','Akwa Ibom / Ibiono-Ibom'),
+    ('akwa_ibom_ika','Akwa Ibom / Ika'),
+    ('akwa_ibom_ikono','Akwa Ibom / Ikono'),
+    ('akwa_ibom_ikot-abasi','Akwa Ibom / Ikot-Abasi'),
+    ('akwa_ibom_ikot-ekpene','Akwa Ibom / Ikot-Ekpene'),
+    ('akwa_ibom_ini','Akwa Ibom / Ini'),
+    ('akwa_ibom_itu','Akwa Ibom / Itu'),
+    ('akwa_ibom_mbo','Akwa Ibom / Mbo'),
+    ('akwa_ibom_mkpat-enin','Akwa Ibom / Mkpat-Enin'),
+    ('akwa_ibom_nsit-ibom','Akwa Ibom / Nsit-Ibom'),
+    ('akwa_ibom_nsit-ubium','Akwa Ibom / Nsit-Ubium'),
+    ('akwa_ibom_obot-akara','Akwa Ibom / Obot-Akara'),
+    ('akwa_ibom_okobo','Akwa Ibom / Okobo'),
+    ('akwa_ibom_onna','Akwa Ibom / Onna'),
+    ('akwa_ibom_oron','Akwa Ibom / Oron'),
+    ('akwa_ibom_oruk_anam','Akwa Ibom / Oruk-Anam'),
+    ('akwa_ibom_udung-uko','Akwa Ibom / Udung-Uko'),
+    ('akwa_ibom_ukanefun','Akwa Ibom / Ukanefun'),
+    ('akwa_ibom_uquo_ibeno','Akwa Ibom / Uquo Ibeno'),
+    ('akwa_ibom_urue-offong-oruko','Akwa Ibom / Urue-Offong-Oruko'),
+    ('akwa_ibom_uruan','Akwa Ibom / Uruan'),
+    ('akwa_ibom_uruk-anam','Akwa Ibom / Uruk-Anam'),
+    ('akwa_ibom_uyo','Akwa Ibom / Uyo'),
+    ('anambra_aguata','Anambra / Aguata'),
+    ('anambra_anambra-east','Anambra / Anambra-East'),
+    ('anambra_anambra-west','Anambra / Anambra-West'),
+    ('anambra_anaocha','Anambra / Anaocha'),
+    ('anambra_awka-north','Anambra / Awka-North'),
+    ('anambra_awka-south','Anambra / Awka-South'),
+    ('anambra_ayamelum','Anambra / Ayamelum'),
+    ('anambra_dunukofia','Anambra / Dunukofia'),
+    ('anambra_ekwusigo','Anambra / Ekwusigo'),
+    ('anambra_idemili','Anambra / Idemili'),
+    ('anambra_idemili-north','Anambra / Idemili-North'),
+    ('anambra_idemili-south','Anambra / Idemili-South'),
+    ('anambra_ihiala','Anambra / Ihiala'),
+    ('anambra_nibo','Anambra / Nibo'),
+    ('anambra_njikoka','Anambra / Njikoka'),
+    ('anambra_nnewi','Anambra / Nnewi'),
+    ('anambra_nnewi-north','Anambra / Nnewi-North'),
+    ('anambra_nnewi-south','Anambra / Nnewi-South'),
+    ('anambra_ogbaru','Anambra / Ogbaru'),
+    ('anambra_olumba','Anambra / Olumba'),
+    ('anambra_onitsha-north','Anambra / Onitsha-North'),
+    ('anambra_onitsha-south','Anambra / Onitsha-South'),
+    ('anambra_orumba-north','Anambra / Orumba-North'),
+    ('anambra_orumba-south','Anambra / Orumba-South'),
+    ('anambra_oti','Anambra / Oti'),
+    ('anambra_oyi','Anambra / Oyi'),
+    ('anambra_ubuluizor-ihiala','Anambra / Ubuluizor-Ihiala'),
+    ('anambra_uyi','Anambra / Uyi'),
+    ('bauchi_alkaleri','Bauchi / Alkaleri'),
+    ('bauchi_bauchi','Bauchi / Bauchi'),
+    ('bauchi_bogoro','Bauchi / Bogoro'),
+    ('bauchi_damban','Bauchi / Damban'),
+    ('bauchi_darazo','Bauchi / Darazo'),
+    ('bauchi_dass','Bauchi / Dass'),
+    ('bauchi_gamawa','Bauchi / Gamawa'),
+    ('bauchi_ganjuwa','Bauchi / Ganjuwa'),
+    ('bauchi_giade','Bauchi / Giade'),
+    ('bauchi_itas/gadau','Bauchi / Itas/Gadau'),
+    ('bauchi_jamaare','Bauchi / Jamaare'),
+    ('bauchi_katagum','Bauchi / Katagum'),
+    ('bauchi_kirfi','Bauchi / Kirfi'),
+    ('bauchi_misau','Bauchi / Misau'),
+    ('bauchi_ningi','Bauchi / Ningi'),
+    ('bauchi_shira','Bauchi / Shira'),
+    ('bauchi_tafawa-balewa','Bauchi / Tafawa-Balewa'),
+    ('bauchi_toro','Bauchi / Toro'),
+    ('bauchi_warji','Bauchi / Warji'),
+    ('bauchi_zaki','Bauchi / Zaki'),
+    ('bayelsa_brass','Bayelsa / Brass'),
+    ('bayelsa_ekeremor','Bayelsa / Ekeremor'),
+    ('bayelsa_kembe','Bayelsa / Kembe'),
+    ('bayelsa_kolokuma','Bayelsa / Kolokuma'),
+    ('bayelsa_kolokuma/opkuma','Bayelsa / Kolokuma/Opkuma'),
+    ('bayelsa_nembe','Bayelsa / Nembe'),
+    ('bayelsa_ogbia','Bayelsa / Ogbia'),
+    ('bayelsa_sagbama','Bayelsa / Sagbama'),
+    ('bayelsa_southern-ijaw','Bayelsa / Southern-Ijaw'),
+    ('bayelsa_toru-abubo','Bayelsa / Toru-Abubo'),
+    ('bayelsa_yenegoa','Bayelsa / Yenegoa'),
+    ('benue_ado','Benue / Ado'),
+    ('benue_agatu','Benue / Agatu'),
+    ('benue_apa','Benue / Apa'),
+    ('benue_buruku','Benue / Buruku'),
+    ('benue_gboko','Benue / Gboko'),
+    ('benue_guma','Benue / Guma'),
+    ('benue_gwer-east','Benue / Gwer-East'),
+    ('benue_gwer-west','Benue / Gwer-West'),
+    ('benue_katsina-ala','Benue / Katsina-Ala'),
+    ('benue_konshisha','Benue / Konshisha'),
+    ('benue_kwande','Benue / Kwande'),
+    ('benue_logo','Benue / Logo'),
+    ('benue_makurdi','Benue / Makurdi'),
+    ('benue_ogbadibo','Benue / Ogbadibo'),
+    ('benue_ohimini','Benue / Ohimini'),
+    ('benue_oju','Benue / Oju'),
+    ('benue_okpokwu','Benue / Okpokwu'),
+    ('benue_otukpo','Benue / Otukpo'),
+    ('benue_oturkpa','Benue / Oturkpa'),
+    ('benue_tarka','Benue / Tarka'),
+    ('benue_ukum','Benue / Ukum'),
+    ('benue_ushongo','Benue / Ushongo'),
+    ('benue_vandeikya','Benue / Vandeikya'),
+    ('borno_abadan','Borno / Abadan'),
+    ('borno_askira-uba','Borno / Askira-Uba'),
+    ('borno_bama','Borno / Bama'),
+    ('borno_bayo','Borno / Bayo'),
+    ('borno_biu','Borno / Biu'),
+    ('borno_chibok','Borno / Chibok'),
+    ('borno_damboa','Borno / Damboa'),
+    ('borno_dikwa','Borno / Dikwa'),
+    ('borno_gubio','Borno / Gubio'),
+    ('borno_guzamala','Borno / Guzamala'),
+    ('borno_gwoza','Borno / Gwoza'),
+    ('borno_hawul','Borno / Hawul'),
+    ('borno_jere','Borno / Jere'),
+    ('borno_kaga','Borno / Kaga'),
+    ('borno_kala/balge','Borno / Kala/Balge'),
+    ('borno_konduga','Borno / Konduga'),
+    ('borno_kukawa','Borno / Kukawa'),
+    ('borno_kwaya-kusar','Borno / Kwaya-Kusar'),
+    ('borno_mafa','Borno / Mafa'),
+    ('borno_magumeri','Borno / Magumeri'),
+    ('borno_maiduguri','Borno / Maiduguri'),
+    ('borno_marte','Borno / Marte'),
+    ('borno_mobbar','Borno / Mobbar'),
+    ('borno_mongunu','Borno / Mongunu'),
+    ('borno_ngala','Borno / Ngala'),
+    ('borno_nganzai','Borno / Nganzai'),
+    ('borno_shani','Borno / Shani'),
+    ('cross_river_abi','Cross River / Abi'),
+    ('cross_river_abuochichie','Cross River / Abuochichie'),
+    ('cross_river_akamkpa','Cross River / Akamkpa'),
+    ('cross_river_akpabuyo','Cross River / Akpabuyo'),
+    ('cross_river_bakassi','Cross River / Bakassi'),
+    ('cross_river_bekwara','Cross River / Bekwara'),
+    ('cross_river_biasi','Cross River / Biasi'),
+    ('cross_river_boki','Cross River / Boki'),
+    ('cross_river_calabar-municipal','Cross River / Calabar-Municipal'),
+    ('cross_river_calabar-south','Cross River / Calabar-South'),
+    ('cross_river_etunk','Cross River / Etunk'),
+    ('cross_river_ikom','Cross River / Ikom'),
+    ('cross_river_obanliku','Cross River / Obanliku'),
+    ('cross_river_obubra','Cross River / Obubra'),
+    ('cross_river_obudu','Cross River / Obudu'),
+    ('cross_river_odukpani','Cross River / Odukpani'),
+    ('cross_river_ogoja','Cross River / Ogoja'),
+    ('cross_river_ugep-north','Cross River / Ugep-North'),
+    ('cross_river_yakurr','Cross River / Yakurr'),
+    ('cross_river_yala','Cross River / Yala'),
+    ('delta_aniocha-north','Delta / Aniocha-North'),
+    ('delta_aniocha-south','Delta / Aniocha-South'),
+    ('delta_bomadi','Delta / Bomadi'),
+    ('delta_burutu','Delta / Burutu'),
+    ('delta_effurun','Delta / Effurun'),
+    ('delta_ethiope-east','Delta / Ethiope-East'),
+    ('delta_ethiope-west','Delta / Ethiope-West'),
+    ('delta_idu','Delta / Idu'),
+    ('delta_ika-ne','Delta / Ika-Ne'),
+    ('delta_ika-north-east','Delta / Ika-North-East'),
+    ('delta_ika-south','Delta / Ika-South'),
+    ('delta_idemili-south','Delta / Idemili-South'),
+    ('delta_isoko-north','Delta / Isoko-North'),
+    ('delta_isoko-south','Delta / Isoko-South'),
+    ('delta_ndokwa-east','Delta / Ndokwa-East'),
+    ('delta_ndokwa-north','Delta / Ndokwa-North'),
+    ('delta_ndokwa-south','Delta / Ndokwa-South'),
+    ('delta_ndokwa-west','Delta / Ndokwa-West'),
+    ('delta_okpe','Delta / Okpe'),
+    ('delta_okwuani','Delta / Okwuani'),
+    ('delta_oleh','Delta / Oleh'),
+    ('delta_oshielli-north','Delta / Oshielli-North'),
+    ('delta_oshimili','Delta / Oshimili'),
+    ('delta_oshimili-north','Delta / Oshimili-North'),
+    ('delta_oshimili-south','Delta / Oshimili-South'),
+    ('delta_osimili','Delta / Osimili'),
+    ('delta_osimili-north','Delta / Osimili-North'),
+    ('delta_osimili-south','Delta / Osimili-South'),
+    ('delta_patani','Delta / Patani'),
+    ('delta_sapele','Delta / Sapele'),
+    ('delta_udokwa','Delta / Udokwa'),
+    ('delta_udu','Delta / Udu'),
+    ('delta_ughelli-north','Delta / Ughelli-North'),
+    ('delta_ughelli-south','Delta / Ughelli-South'),
+    ('delta_ukwuani','Delta / Ukwuani'),
+    ('delta_urwie','Delta / Urwie'),
+    ('delta_uvie','Delta / Uvie'),
+    ('delta_uvwei','Delta / Uvwei'),
+    ('delta_uvwie','Delta / Uvwie'),
+    ('delta_warri-central','Delta / Warri-Central'),
+    ('delta_warri-north','Delta / Warri-North'),
+    ('delta_warri-south','Delta / Warri-South'),
+    ('delta_warri-south-west','Delta / Warri-South-West'),
+    ('ebonyi_abakaliki','Ebonyi / Abakaliki'),
+    ('ebonyi_afikpo-north','Ebonyi / Afikpo-North'),
+    ('ebonyi_afikpo-south','Ebonyi / Afikpo-South'),
+    ('ebonyi_bomadim','Ebonyi / Bomadim'),
+    ('ebonyi_ebonyi','Ebonyi / Ebonyi'),
+    ('ebonyi_ezza-north','Ebonyi / Ezza-North'),
+    ('ebonyi_ezza-south','Ebonyi / Ezza-South'),
+    ('ebonyi_ikwo','Ebonyi / Ikwo'),
+    ('ebonyi_ishielu','Ebonyi / Ishielu'),
+    ('ebonyi_ivo','Ebonyi / Ivo'),
+    ('ebonyi_izzi','Ebonyi / Izzi'),
+    ('ebonyi_obaukwu','Ebonyi / Obaukwu'),
+    ('ebonyi_ohakwu','Ebonyi / Ohakwu'),
+    ('ebonyi_ohaozara','Ebonyi / Ohaozara'),
+    ('ebonyi_onicha','Ebonyi / Onicha'),
+    ('ebonyi_ukaba','Ebonyi / Ukaba'),
+    ('edo_afokpella','Edo / Afokpella'),
+    ('edo_afuze','Edo / Afuze'),
+    ('edo_agbazilo','Edo / Agbazilo'),
+    ('edo_akoko-edo','Edo / Akoko-Edo'),
+    ('edo_egor','Edo / Egor'),
+    ('edo_esan-central','Edo / Esan-Central'),
+    ('edo_esan-north-east','Edo / Esan-North-East'),
+    ('edo_esan-north-west','Edo / Esan-North-West'),
+    ('edo_esan-south-east','Edo / Esan-South-East'),
+    ('edo_esan-west','Edo / Esan-West'),
+    ('edo_etsako-central','Edo / Etsako-Central'),
+    ('edo_etsako-east','Edo / Etsako-East'),
+    ('edo_etsako-west','Edo / Etsako-West'),
+    ('edo_igueben','Edo / Igueben'),
+    ('edo_ikpoba-okha','Edo / Ikpoba-Okha'),
+    ('edo_ohunmwode','Edo / Ohunmwode'),
+    ('edo_ologbo','Edo / Ologbo'),
+    ('edo_opoji_irrua','Edo / Opoji Irrua'),
+    ('edo_oredo','Edo / Oredo'),
+    ('edo_orhionmwon','Edo / Orhionmwon'),
+    ('edo_ovia-north-east','Edo / Ovia-North-East'),
+    ('edo_ovia-south-west','Edo / Ovia-South-West'),
+    ('edo_owan-east','Edo / Owan-East'),
+    ('edo_owan-west','Edo / Owan-West'),
+    ('edo_uhunmwonde','Edo / Uhunmwonde'),
+    ('ekiti_ado-ekiti','Ekiti / Ado-Ekiti'),
+    ('ekiti_aiyekire','Ekiti / Aiyekire'),
+    ('ekiti_efon','Ekiti / Efon'),
+    ('ekiti_ekiti-east','Ekiti / Ekiti-East'),
+    ('ekiti_ekiti-south-west','Ekiti / Ekiti-South-West'),
+    ('ekiti_ekiti-west','Ekiti / Ekiti-West'),
+    ('ekiti_emure/ise/orun','Ekiti / Emure/Ise/Orun'),
+    ('ekiti_gbonyin','Ekiti / Gbonyin'),
+    ('ekiti_ido-osi','Ekiti / Ido-Osi'),
+    ('ekiti_ijero','Ekiti / Ijero'),
+    ('ekiti_ikare','Ekiti / Ikare'),
+    ('ekiti_ikere','Ekiti / Ikere'),
+    ('ekiti_ikole','Ekiti / Ikole'),
+    ('ekiti_ilejemeje','Ekiti / Ilejemeje'),
+    ('ekiti_irepodun/ifelodun','Ekiti / Irepodun/Ifelodun'),
+    ('ekiti_ise-orun','Ekiti / Ise-Orun'),
+    ('ekiti_moba','Ekiti / Moba'),
+    ('ekiti_oye','Ekiti / Oye'),
+    ('enugu_aninri','Enugu / Aninri'),
+    ('enugu_awgu','Enugu / Awgu'),
+    ('enugu_enugu-east','Enugu / Enugu-East'),
+    ('enugu_enugu-north','Enugu / Enugu-North'),
+    ('enugu_enugu-south','Enugu / Enugu-South'),
+    ('enugu_ezeagu','Enugu / Ezeagu'),
+    ('enugu_igbo-etiti','Enugu / Igbo-Etiti'),
+    ('enugu_igbo-eze-north','Enugu / Igbo-Eze-North'),
+    ('enugu_igbo-eze-south','Enugu / Igbo-Eze-South'),
+    ('enugu_isi-uzo','Enugu / Isi-Uzo'),
+    ('enugu_nkanu-east','Enugu / Nkanu-East'),
+    ('enugu_nkanu-west','Enugu / Nkanu-West'),
+    ('enugu_nsukka','Enugu / Nsukka'),
+    ('enugu_nukanu_east','Enugu / Nukanu East'),
+    ('enugu_oji-river','Enugu / Oji-River'),
+    ('enugu_udenu','Enugu / Udenu'),
+    ('enugu_udi','Enugu / Udi'),
+    ('enugu_uzo-uwani','Enugu / Uzo-Uwani'),
+    ('gombe_akko','Gombe / Akko'),
+    ('gombe_balanga','Gombe / Balanga'),
+    ('gombe_billiri','Gombe / Billiri'),
+    ('gombe_dukku','Gombe / Dukku'),
+    ('gombe_funakaye','Gombe / Funakaye'),
+    ('gombe_gombe','Gombe / Gombe'),
+    ('gombe_kaltungo','Gombe / Kaltungo'),
+    ('gombe_kwami','Gombe / Kwami'),
+    ('gombe_nafada/bajoga','Gombe / Nafada/Bajoga'),
+    ('gombe_shomgom','Gombe / Shomgom'),
+    ('gombe_yamaltu/deba','Gombe / Yamaltu/Deba'),
+    ('imo_aboh-mbaise','Imo / Aboh-Mbaise'),
+    ('imo_ahiazu-mbaise','Imo / Ahiazu-Mbaise'),
+    ('imo_dral-esat','Imo / Dral-Esat'),
+    ('imo_ehime-mbano','Imo / Ehime-Mbano'),
+    ('imo_ezinihitte','Imo / Ezinihitte'),
+    ('imo_ideato','Imo / Ideato'),
+    ('imo_ideato-north','Imo / Ideato-North'),
+    ('imo_ideato-south','Imo / Ideato-South'),
+    ('imo_ihitte/uboma','Imo / Ihitte/Uboma'),
+    ('imo_ikeduru','Imo / Ikeduru'),
+    ('imo_isiala-mbano','Imo / Isiala-Mbano'),
+    ('imo_isu','Imo / Isu'),
+    ('imo_mbaitoli','Imo / Mbaitoli'),
+    ('imo_mbano','Imo / Mbano'),
+    ('imo_ngor-okpala','Imo / Ngor-Okpala'),
+    ('imo_njaba','Imo / Njaba'),
+    ('imo_nkwerre','Imo / Nkwerre'),
+    ('imo_nwangele','Imo / Nwangele'),
+    ('imo_obowo','Imo / Obowo'),
+    ('imo_oguta','Imo / Oguta'),
+    ('imo_ohaji-egbema','Imo / Ohaji-Egbema'),
+    ('imo_okigwe','Imo / Okigwe'),
+    ('imo_onuimo','Imo / Onuimo'),
+    ('imo_orlu','Imo / Orlu'),
+    ('imo_orsu','Imo / Orsu'),
+    ('imo_oru-east','Imo / Oru-East'),
+    ('imo_oru-west','Imo / Oru-West'),
+    ('imo_owerri-municipal','Imo / Owerri-Municipal'),
+    ('imo_owerri-north','Imo / Owerri-North'),
+    ('imo_owerri-west','Imo / Owerri-West'),
+    ('imo_ugiri-ike_ikeduru','Imo / Ugiri-Ike Ikeduru'),
+    ('imo_ugiri-ikedikeduru','Imo / Ugiri-Ikedikeduru'),
+    ('imo_unbano','Imo / Unbano'),
+    ('imo_zinihitte','Imo / Zinihitte'),
+    ('jigawa_auyo','Jigawa / Auyo'),
+    ('jigawa_babura','Jigawa / Babura'),
+    ('jigawa_biriniwa','Jigawa / Biriniwa'),
+    ('jigawa_birnin-kudu','Jigawa / Birnin-Kudu'),
+    ('jigawa_bosuwa','Jigawa / Bosuwa'),
+    ('jigawa_buji','Jigawa / Buji'),
+    ('jigawa_dutse','Jigawa / Dutse'),
+    ('jigawa_gagarawa','Jigawa / Gagarawa'),
+    ('jigawa_garki','Jigawa / Garki'),
+    ('jigawa_gumel','Jigawa / Gumel'),
+    ('jigawa_guri','Jigawa / Guri'),
+    ('jigawa_gwaram','Jigawa / Gwaram'),
+    ('jigawa_gwiwa','Jigawa / Gwiwa'),
+    ('jigawa_hadejia','Jigawa / Hadejia'),
+    ('jigawa_jahun','Jigawa / Jahun'),
+    ('jigawa_kafin-hausa','Jigawa / Kafin-Hausa'),
+    ('jigawa_kaugama','Jigawa / Kaugama'),
+    ('jigawa_kazaure','Jigawa / Kazaure'),
+    ('jigawa_kirkasamma','Jigawa / Kirkasamma'),
+    ('jigawa_maigatari','Jigawa / Maigatari'),
+    ('jigawa_malam-maduri','Jigawa / Malam-Maduri'),
+    ('jigawa_miga','Jigawa / Miga'),
+    ('jigawa_ringim','Jigawa / Ringim'),
+    ('jigawa_roni','Jigawa / Roni'),
+    ('jigawa_sule-tankarkar','Jigawa / Sule-Tankarkar'),
+    ('jigawa_taura','Jigawa / Taura'),
+    ('jigawa_yankwashi','Jigawa / Yankwashi'),
+    ('kaduna_birnin-gwari','Kaduna / Birnin-Gwari'),
+    ('kaduna_chikun','Kaduna / Chikun'),
+    ('kaduna_giwa','Kaduna / Giwa'),
+    ('kaduna_gwagwada','Kaduna / Gwagwada'),
+    ('kaduna_igabi','Kaduna / Igabi'),
+    ('kaduna_ikara','Kaduna / Ikara'),
+    ('kaduna_jaba','Kaduna / Jaba'),
+    ('kaduna_jemaa','Kaduna / Jemaa'),
+    ('kaduna_kachia','Kaduna / Kachia'),
+    ('kaduna_kaduna-north','Kaduna / Kaduna-North'),
+    ('kaduna_kagarko','Kaduna / Kagarko'),
+    ('kaduna_kajuru','Kaduna / Kajuru'),
+    ('kaduna_kaura','Kaduna / Kaura'),
+    ('kaduna_kauru','Kaduna / Kauru'),
+    ('kaduna_koka/kawo','Kaduna / Koka/Kawo'),
+    ('kaduna_kubah','Kaduna / Kubah'),
+    ('kaduna_kudan','Kaduna / Kudan'),
+    ('kaduna_lere','Kaduna / Lere'),
+    ('kaduna_makarfi','Kaduna / Makarfi'),
+    ('kaduna_sabon-gari','Kaduna / Sabon-Gari'),
+    ('kaduna_sanga','Kaduna / Sanga'),
+    ('kaduna_soba','Kaduna / Soba'),
+    ('kaduna_tudun-wada/makera','Kaduna / Tudun-Wada/Makera'),
+    ('kaduna_zango-kataf','Kaduna / Zango-Kataf'),
+    ('kaduna_zaria','Kaduna / Zaria'),
+    ('kano_ajingi','Kano / Ajingi'),
+    ('kano_albasu','Kano / Albasu'),
+    ('kano_bagwai','Kano / Bagwai'),
+    ('kano_bebeji','Kano / Bebeji'),
+    ('kano_bichi','Kano / Bichi'),
+    ('kano_bunkure','Kano / Bunkure'),
+    ('kano_dala','Kano / Dala'),
+    ('kano_dambatta','Kano / Dambatta'),
+    ('kano_dawakin-kudu','Kano / Dawakin-Kudu'),
+    ('kano_dawakin-tofa','Kano / Dawakin-Tofa'),
+    ('kano_doguwa','Kano / Doguwa'),
+    ('kano_fagge','Kano / Fagge'),
+    ('kano_gabasawa','Kano / Gabasawa'),
+    ('kano_garko','Kano / Garko'),
+    ('kano_garun-mallam','Kano / Garun-Mallam'),
+    ('kano_gaya','Kano / Gaya'),
+    ('kano_gezawa','Kano / Gezawa'),
+    ('kano_gwale','Kano / Gwale'),
+    ('kano_gwarzo','Kano / Gwarzo'),
+    ('kano_kano-municipal','Kano / Kano-Municipal'),
+    ('kano_karaye','Kano / Karaye'),
+    ('kano_kibiya','Kano / Kibiya'),
+    ('kano_kiru','Kano / Kiru'),
+    ('kano_kumbotso','Kano / Kumbotso'),
+    ('kano_kunchi','Kano / Kunchi'),
+    ('kano_kura','Kano / Kura'),
+    ('kano_madobi','Kano / Madobi'),
+    ('kano_makoda','Kano / Makoda'),
+    ('kano_minjibir','Kano / Minjibir'),
+    ('kano_nasarawa','Kano / Nasarawa'),
+    ('kano_rano','Kano / Rano'),
+    ('kano_rimin-gado','Kano / Rimin-Gado'),
+    ('kano_rogo','Kano / Rogo'),
+    ('kano_shanono','Kano / Shanono'),
+    ('kano_sumaila','Kano / Sumaila'),
+    ('kano_takai','Kano / Takai'),
+    ('kano_tarauni','Kano / Tarauni'),
+    ('kano_tofa','Kano / Tofa'),
+    ('kano_tsanyawa','Kano / Tsanyawa'),
+    ('kano_tudun-wada','Kano / Tudun-Wada'),
+    ('kano_ungogo','Kano / Ungogo'),
+    ('kano_warawa','Kano / Warawa'),
+    ('kano_wudil','Kano / Wudil'),
+    ('katsina_bakori','Katsina / Bakori'),
+    ('katsina_batagarawa','Katsina / Batagarawa'),
+    ('katsina_batsari','Katsina / Batsari'),
+    ('katsina_baure','Katsina / Baure'),
+    ('katsina_bindawa','Katsina / Bindawa'),
+    ('katsina_charanchi','Katsina / Charanchi'),
+    ('katsina_dan-musa','Katsina / Dan-Musa'),
+    ('katsina_dandume','Katsina / Dandume'),
+    ('katsina_danji','Katsina / Danji'),
+    ('katsina_daura','Katsina / Daura'),
+    ('katsina_dutsi','Katsina / Dutsi'),
+    ('katsina_dutsinma','Katsina / Dutsinma'),
+    ('katsina_faskari','Katsina / Faskari'),
+    ('katsina_funtua','Katsina / Funtua'),
+    ('katsina_ingawa','Katsina / Ingawa'),
+    ('katsina_jibia','Katsina / Jibia'),
+    ('katsina_kafur','Katsina / Kafur'),
+    ('katsina_kaita','Katsina / Kaita'),
+    ('katsina_kankara','Katsina / Kankara'),
+    ('katsina_kankia','Katsina / Kankia'),
+    ('katsina_katsina','Katsina / Katsina'),
+    ('katsina_kurfi','Katsina / Kurfi'),
+    ('katsina_kusada','Katsina / Kusada'),
+    ('katsina_mai-adua','Katsina / Mai-Adua'),
+    ('katsina_malumfashi','Katsina / Malumfashi'),
+    ('katsina_mani','Katsina / Mani'),
+    ('katsina_mashi','Katsina / Mashi'),
+    ('katsina_matazu','Katsina / Matazu'),
+    ('katsina_musawa','Katsina / Musawa'),
+    ('katsina_rimi','Katsina / Rimi'),
+    ('katsina_sabuwa','Katsina / Sabuwa'),
+    ('katsina_safana','Katsina / Safana'),
+    ('katsina_sandamu','Katsina / Sandamu'),
+    ('katsina_zango','Katsina / Zango'),
+    ('kebbi_aleiro','Kebbi / Aleiro'),
+    ('kebbi_arewa-dandi','Kebbi / Arewa-Dandi'),
+    ('kebbi_argungu','Kebbi / Argungu'),
+    ('kebbi_augie','Kebbi / Augie'),
+    ('kebbi_bagudo','Kebbi / Bagudo'),
+    ('kebbi_birnin-kebbi','Kebbi / Birnin-Kebbi'),
+    ('kebbi_bumza','Kebbi / Bumza'),
+    ('kebbi_dandi','Kebbi / Dandi'),
+    ('kebbi_danko','Kebbi / Danko'),
+    ('kebbi_fakai','Kebbi / Fakai'),
+    ('kebbi_gwandu','Kebbi / Gwandu'),
+    ('kebbi_jega','Kebbi / Jega'),
+    ('kebbi_kalgo','Kebbi / Kalgo'),
+    ('kebbi_koko-besse','Kebbi / Koko-Besse'),
+    ('kebbi_maiyama','Kebbi / Maiyama'),
+    ('kebbi_ngaski','Kebbi / Ngaski'),
+    ('kebbi_sakaba','Kebbi / Sakaba'),
+    ('kebbi_shanga','Kebbi / Shanga'),
+    ('kebbi_suru','Kebbi / Suru'),
+    ('kebbi_wasagu','Kebbi / Wasagu'),
+    ('kebbi_yauri','Kebbi / Yauri'),
+    ('kebbi_zuru','Kebbi / Zuru'),
+    ('kogi_adavi','Kogi / Adavi'),
+    ('kogi_ajaokuta','Kogi / Ajaokuta'),
+    ('kogi_ankpa','Kogi / Ankpa'),
+    ('kogi_bassa','Kogi / Bassa'),
+    ('kogi_dekina','Kogi / Dekina'),
+    ('kogi_ibaji','Kogi / Ibaji'),
+    ('kogi_idah','Kogi / Idah'),
+    ('kogi_igalamela','Kogi / Igalamela'),
+    ('kogi_ijumu','Kogi / Ijumu'),
+    ('kogi_ikoyi-ijumu','Kogi / Ikoyi-Ijumu'),
+    ('kogi_kabba/bunu','Kogi / Kabba/Bunu'),
+    ('kogi_kogi','Kogi / Kogi'),
+    ('kogi_lokoja','Kogi / Lokoja'),
+    ('kogi_mopa-muro','Kogi / Mopa-Muro'),
+    ('kogi_obaji','Kogi / Obaji'),
+    ('kogi_ofu','Kogi / Ofu'),
+    ('kogi_ogori/magongo','Kogi / Ogori/Magongo'),
+    ('kogi_okehi','Kogi / Okehi'),
+    ('kogi_okene','Kogi / Okene'),
+    ('kogi_olamaboro','Kogi / Olamaboro'),
+    ('kogi_omala','Kogi / Omala'),
+    ('kogi_oru','Kogi / Oru'),
+    ('kogi_oyi','Kogi / Oyi'),
+    ('kogi_yagba-east','Kogi / Yagba-East'),
+    ('kogi_yagba-west','Kogi / Yagba-West'),
+    ('kwara_asa','Kwara / Asa'),
+    ('kwara_baruten','Kwara / Baruten'),
+    ('kwara_edu','Kwara / Edu'),
+    ('kwara_ekiti','Kwara / Ekiti'),
+    ('kwara_ilorin-east','Kwara / Ilorin-East'),
+    ('kwara_ilorin-south','Kwara / Ilorin-South'),
+    ('kwara_ilorin-west','Kwara / Ilorin-West'),
+    ('kwara_isin','Kwara / Isin'),
+    ('kwara_kaiama','Kwara / Kaiama'),
+    ('kwara_moro','Kwara / Moro'),
+    ('kwara_offa','Kwara / Offa'),
+    ('kwara_oke-ero','Kwara / Oke-Ero'),
+    ('kwara_oyun','Kwara / Oyun'),
+    ('kwara_pategi','Kwara / Pategi'),
+    ('kwara_ifelodun','Kwara / Ifelodun'),
+    ('kwara_irepodun','Kwara / Irepodun'),
+    ('lagos_agege','Lagos / Agege'),
+    ('lagos_ajeromi-ifelodun','Lagos / Ajeromi-Ifelodun'),
+    ('lagos_alimosho','Lagos / Alimosho'),
+    ('lagos_amuwo-odofin','Lagos / Amuwo-Odofin'),
+    ('lagos_apapa','Lagos / Apapa'),
+    ('lagos_badagry','Lagos / Badagry'),
+    ('lagos_epe','Lagos / Epe'),
+    ('lagos_eti-osa','Lagos / Eti-Osa'),
+    ('lagos_ibeju-lekki','Lagos / Ibeju-Lekki'),
+    ('lagos_ifako-ijaiye','Lagos / Ifako-Ijaiye'),
+    ('lagos_ikeja','Lagos / Ikeja'),
+    ('lagos_ikorodu','Lagos / Ikorodu'),
+    ('lagos_island','Lagos / Island'),
+    ('lagos_kosofe','Lagos / Kosofe'),
+    ('lagos_lagos-island','Lagos / Lagos-Island'),
+    ('lagos_lagos-mainland','Lagos / Lagos-Mainland'),
+    ('lagos_mushin','Lagos / Mushin'),
+    ('lagos_ojo','Lagos / Ojo'),
+    ('lagos_oshodi-isolo','Lagos / Oshodi-Isolo'),
+    ('lagos_shomolu','Lagos / Shomolu'),
+    ('lagos_somolu','Lagos / Somolu'),
+    ('lagos_suru-lere','Lagos / Suru-Lere'),
+    ('nassarawa_akwanga','Nassarawa / Akwanga'),
+    ('nassarawa_awe','Nassarawa / Awe'),
+    ('nassarawa_doma','Nassarawa / Doma'),
+    ('nassarawa_karu','Nassarawa / Karu'),
+    ('nassarawa_keana','Nassarawa / Keana'),
+    ('nassarawa_keffi','Nassarawa / Keffi'),
+    ('nassarawa_kokona','Nassarawa / Kokona'),
+    ('nassarawa_lafia','Nassarawa / Lafia'),
+    ('nassarawa_nassawara','Nassarawa / Nassawara'),
+    ('nassarawa_nassarawa','Nassarawa / Nassarawa'),
+    ('nassarawa_nassawara_eggon','Nassarawa / Nassawara Eggon'),
+    ('nassarawa_obi','Nassarawa / Obi'),
+    ('nassarawa_toto','Nassarawa / Toto'),
+    ('nassarawa_wambu','Nassarawa / Wambu'),
+    ('niger_agaie','Niger / Agaie'),
+    ('niger_agwara','Niger / Agwara'),
+    ('niger_bida','Niger / Bida'),
+    ('niger_borgu','Niger / Borgu'),
+    ('niger_bosso','Niger / Bosso'),
+    ('niger_chanchaga','Niger / Chanchaga'),
+    ('niger_edati','Niger / Edati'),
+    ('niger_gbako','Niger / Gbako'),
+    ('niger_gurara','Niger / Gurara'),
+    ('niger_katcha','Niger / Katcha'),
+    ('niger_kontagora','Niger / Kontagora'),
+    ('niger_lapai','Niger / Lapai'),
+    ('niger_lavun','Niger / Lavun'),
+    ('niger_magama','Niger / Magama'),
+    ('niger_mariga','Niger / Mariga'),
+    ('niger_mashegu','Niger / Mashegu'),
+    ('niger_mokwa','Niger / Mokwa'),
+    ('niger_muya','Niger / Muya'),
+    ('niger_paikoro','Niger / Paikoro'),
+    ('niger_rafi','Niger / Rafi'),
+    ('niger_rijau','Niger / Rijau'),
+    ('niger_shiroro','Niger / Shiroro'),
+    ('niger_suleja','Niger / Suleja'),
+    ('niger_tafa','Niger / Tafa'),
+    ('niger_wushishi','Niger / Wushishi'),
+    ('ogun_abeokuta-north','Ogun / Abeokuta-North'),
+    ('ogun_abeokuta-south','Ogun / Abeokuta-South'),
+    ('ogun_ado-odo/ota','Ogun / Ado-Odo/Ota'),
+    ('ogun_adoodo-ota','Ogun / Adoodo-Ota'),
+    ('ogun_ewekoro','Ogun / Ewekoro'),
+    ('ogun_idarapo','Ogun / Idarapo'),
+    ('ogun_iffo-otta','Ogun / Iffo-Otta'),
+    ('ogun_ifo','Ogun / Ifo'),
+    ('ogun_igbado-north','Ogun / Igbado-North'),
+    ('ogun_igbado-south','Ogun / Igbado-South'),
+    ('ogun_ijebu-east','Ogun / Ijebu-East'),
+    ('ogun_ijebu-north','Ogun / Ijebu-North'),
+    ('ogun_ijebu-north-east','Ogun / Ijebu-North-East'),
+    ('ogun_ijebu-ode','Ogun / Ijebu-Ode'),
+    ('ogun_ikenne','Ogun / Ikenne'),
+    ('ogun_ilishan_remo','Ogun / Ilishan Remo'),
+    ('ogun_ilugun-alaro','Ogun / Ilugun-Alaro'),
+    ('ogun_imeko-afon','Ogun / Imeko-Afon'),
+    ('ogun_ipokia','Ogun / Ipokia'),
+    ('ogun_lgayekpe_','Ogun / Lgayekpe'),
+    ('ogun_obafemi-owode','Ogun / Obafemi-Owode'),
+    ('ogun_odedah','Ogun / Odedah'),
+    ('ogun_odogbolu','Ogun / Odogbolu'),
+    ('ogun_ogun-waterside','Ogun / Ogun-Waterside'),
+    ('ogun_remo-north','Ogun / Remo-North'),
+    ('ogun_sagamu','Ogun / Sagamu'),
+    ('ogun_shagamu','Ogun / Shagamu'),
+    ('ogun_yewa','Ogun / Yewa'),
+    ('ondo_akoko','Ondo / Akoko'),
+    ('ondo_akoko-north','Ondo / Akoko-North'),
+    ('ondo_akoko-north-east','Ondo / Akoko-North-East'),
+    ('ondo_akoko-north-west','Ondo / Akoko-North-West'),
+    ('ondo_akoko-south','Ondo / Akoko-South'),
+    ('ondo_akoko-south-east','Ondo / Akoko-South-East'),
+    ('ondo_akoko-south-west','Ondo / Akoko-South-West'),
+    ('ondo_akure','Ondo / Akure'),
+    ('ondo_akure-north','Ondo / Akure-North'),
+    ('ondo_akure-south','Ondo / Akure-South'),
+    ('ondo_ese-odo','Ondo / Ese-Odo'),
+    ('ondo_idanre','Ondo / Idanre'),
+    ('ondo_ifedore','Ondo / Ifedore'),
+    ('ondo_ikale','Ondo / Ikale'),
+    ('ondo_ilaje','Ondo / Ilaje'),
+    ('ondo_ilaje-west','Ondo / Ilaje-West'),
+    ('ondo_ile-oluji-okeigbo','Ondo / Ile-Oluji-Okeigbo'),
+    ('ondo_irele','Ondo / Irele'),
+    ('ondo_odigbo','Ondo / Odigbo'),
+    ('ondo_okiti-pupa','Ondo / Okiti-Pupa'),
+    ('ondo_ondo','Ondo / Ondo'),
+    ('ondo_ondo-east','Ondo / Ondo-East'),
+    ('ondo_ondo-west','Ondo / Ondo-West'),
+    ('ondo_ose','Ondo / Ose'),
+    ('ondo_owo','Ondo / Owo'),
+    ('osun_atakumosa','Osun / Atakumosa'),
+    ('osun_atakumosa_east','Osun / Atakumosa East'),
+    ('osun_ayeda-ade','Osun / Ayeda-Ade'),
+    ('osun_ayedire','Osun / Ayedire'),
+    ('osun_boluwaduro','Osun / Boluwaduro'),
+    ('osun_boripe','Osun / Boripe'),
+    ('osun_ede','Osun / Ede'),
+    ('osun_ede-north','Osun / Ede North'),
+    ('osun_egbedore','Osun / Egbedore'),
+    ('osun_ejigbo','Osun / Ejigbo'),
+    ('osun_ife','Osun / Ife'),
+    ('osun_ife-north','Osun / Ife-North'),
+    ('osun_ife-south','Osun / Ife-South'),
+    ('osun_ife-central','Osun / Ife-Central'),
+    ('osun_ife-east','Osun / Ife-East'),
+    ('osun_ifelodun','Osun / Ifelodun'),
+    ('osun_ila','Osun / Ila'),
+    ('osun_ilesa-east','Osun / Ilesa-East'),
+    ('osun_ilesa-west','Osun / Ilesa-West'),
+    ('osun_ilesha','Osun / Ilesha'),
+    ('osun_ilesha_west','Osun / Ilesha West'),
+    ('osun_irepodun','Osun / Irepodun'),
+    ('osun_irewole','Osun / Irewole'),
+    ('osun_isokan','Osun / Isokan'),
+    ('osun_iwo','Osun / Iwo'),
+    ('osun_obokun','Osun / Obokun'),
+    ('osun_odo-otin','Osun / Odo-Otin'),
+    ('osun_ola_oluwa','Osun / Ola Oluwa'),
+    ('osun_olorunda','Osun / Olorunda'),
+    ('osun_ori-ade','Osun / Ori-Ade'),
+    ('osun_orolu','Osun / Orolu'),
+    ('osun_osogbo','Osun / Osogbo'),
+    ('oyo_afijio','Oyo / Afijio'),
+    ('oyo_akinyele','Oyo / Akinyele'),
+    ('oyo_atiba','Oyo / Atiba'),
+    ('oyo_atigbo','Oyo / Atigbo'),
+    ('oyo_egbeda','Oyo / Egbeda'),
+    ('oyo_ibadan-central','Oyo / Ibadan-Central'),
+    ('oyo_ibadan-north-east','Oyo / Ibadan-North-East'),
+    ('oyo_ibadan-north-west','Oyo / Ibadan-North-West'),
+    ('oyo_ibadan-south-east','Oyo / Ibadan-South-East'),
+    ('oyo_ibadan-south-west','Oyo / Ibadan-South-West'),
+    ('oyo_ibarapa-central','Oyo / Ibarapa-Central'),
+    ('oyo_ibarapa-east','Oyo / Ibarapa-East'),
+    ('oyo_ibarapa-north','Oyo / Ibarapa-North'),
+    ('oyo_ido','Oyo / Ido'),
+    ('oyo_ifedayo','Oyo / Ifedayo'),
+    ('oyo_ifeloju','Oyo / Ifeloju'),
+    ('oyo_irepo','Oyo / Irepo'),
+    ('oyo_iseyin','Oyo / Iseyin'),
+    ('oyo_itseiwaju','Oyo / Itseiwaju'),
+    ('oyo_iwajowa','Oyo / Iwajowa'),
+    ('oyo_kajola','Oyo / Kajola'),
+    ('oyo_lagelu','Oyo / Lagelu'),
+    ('oyo_odo-oluwa','Oyo / Odo-Oluwa'),
+    ('oyo_ogbomosho-north','Oyo / Ogbomosho-North'),
+    ('oyo_ogbomosho-south','Oyo / Ogbomosho-South'),
+    ('oyo_olorunsogo','Oyo / Olorunsogo'),
+    ('oyo_oluyole','Oyo / Oluyole'),
+    ('oyo_ona-ara','Oyo / Ona-Ara'),
+    ('oyo_orelope','Oyo / Orelope'),
+    ('oyo_ori-ire','Oyo / Ori-Ire'),
+    ('oyo_oyo-west','Oyo / Oyo-West'),
+    ('oyo_saki-east','Oyo / Saki-East'),
+    ('oyo_saki-west','Oyo / Saki-West'),
+    ('oyo_surulere','Oyo / Surulere'),
+    ('plateau_barkin-ladi','Plateau / Barkin-Ladi'),
+    ('plateau_bassa','Plateau / Bassa'),
+    ('plateau_bokkos','Plateau / Bokkos'),
+    ('plateau_jos-east','Plateau / Jos-East'),
+    ('plateau_jos-north','Plateau / Jos-North'),
+    ('plateau_jos-south','Plateau / Jos-South'),
+    ('plateau_kanam','Plateau / Kanam'),
+    ('plateau_kanke','Plateau / Kanke'),
+    ('plateau_langtang-north','Plateau / Langtang-North'),
+    ('plateau_langtang-south','Plateau / Langtang-South'),
+    ('plateau_mangu','Plateau / Mangu'),
+    ('plateau_mikang','Plateau / Mikang'),
+    ('plateau_pankshin','Plateau / Pankshin'),
+    ('plateau_quananpan','Plateau / Quananpan'),
+    ('plateau_riyom','Plateau / Riyom'),
+    ('plateau_shendam','Plateau / Shendam'),
+    ('plateau_wase','Plateau / Wase'),
+    ('rivers_aboa/odual','Rivers / Aboa/Odual'),
+    ('rivers_ahoada-east','Rivers / Ahoada-East'),
+    ('rivers_ahoada-west','Rivers / Ahoada-West'),
+    ('rivers_akukutoru','Rivers / Akukutoru'),
+    ('rivers_andoni','Rivers / Andoni'),
+    ('rivers_asari-toru','Rivers / Asari-Toru'),
+    ('rivers_bonny','Rivers / Bonny'),
+    ('rivers_buguma','Rivers / Buguma'),
+    ('rivers_degema','Rivers / Degema'),
+    ('rivers_eleme','Rivers / Eleme'),
+    ('rivers_elfane','Rivers / Elfane'),
+    ('rivers_emuoha','Rivers / Emuoha'),
+    ('rivers_etche','Rivers / Etche'),
+    ('rivers_gokana','Rivers / Gokana'),
+    ('rivers_ikwerre','Rivers / Ikwerre'),
+    ('rivers_khana','Rivers / Khana'),
+    ('rivers_obia/akpor','Rivers / Obia/Akpor'),
+    ('rivers_ogba-egbema-ndoni','Rivers / Ogba-Egbema-Ndoni'),
+    ('rivers_ogba/egbema/ndoni','Rivers / Ogba/Egbema/Ndoni'),
+    ('rivers_ogu/bolo','Rivers / Ogu/Bolo'),
+    ('rivers_okirika','Rivers / Okirika'),
+    ('rivers_omuma','Rivers / Omuma'),
+    ('rivers_opobo/nkoro','Rivers / Opobo/Nkoro'),
+    ('rivers_oyigbo','Rivers / Oyigbo'),
+    ('rivers_port-harcourt','Rivers / Port-Harcourt'),
+    ('rivers_tai','Rivers / Tai'),
+    ('sokoto_binji','Sokoto / Binji'),
+    ('sokoto_bodinga','Sokoto / Bodinga'),
+    ('sokoto_dange-shuni','Sokoto / Dange-Shuni'),
+    ('sokoto_gada','Sokoto / Gada'),
+    ('sokoto_goronyo','Sokoto / Goronyo'),
+    ('sokoto_gudu','Sokoto / Gudu'),
+    ('sokoto_gwadabawa','Sokoto / Gwadabawa'),
+    ('sokoto_illela','Sokoto / Illela'),
+    ('sokoto_kebbe','Sokoto / Kebbe'),
+    ('sokoto_kware','Sokoto / Kware'),
+    ('sokoto_raba','Sokoto / Raba'),
+    ('sokoto_sabo-birni','Sokoto / Sabo-Birni'),
+    ('sokoto_shagari','Sokoto / Shagari'),
+    ('sokoto_silame','Sokoto / Silame'),
+    ('sokoto_sokoto-north','Sokoto / Sokoto-North'),
+    ('sokoto_sokoto-south','Sokoto / Sokoto-South'),
+    ('sokoto_tambuwal','Sokoto / Tambuwal'),
+    ('sokoto_tangaza','Sokoto / Tangaza'),
+    ('sokoto_tureta','Sokoto / Tureta'),
+    ('sokoto_wamakko','Sokoto / Wamakko'),
+    ('sokoto_wurno','Sokoto / Wurno'),
+    ('sokoto_yabo','Sokoto / Yabo'),
+    ('taraba_ardo-kola','Taraba / Ardo-Kola'),
+    ('taraba_bali','Taraba / Bali'),
+    ('taraba_donga','Taraba / Donga'),
+    ('taraba_gashaka','Taraba / Gashaka'),
+    ('taraba_gassol','Taraba / Gassol'),
+    ('taraba_ibi','Taraba / Ibi'),
+    ('taraba_jalingo','Taraba / Jalingo'),
+    ('taraba_karim-lamido','Taraba / Karim-Lamido'),
+    ('taraba_kurmi','Taraba / Kurmi'),
+    ('taraba_lau','Taraba / Lau'),
+    ('taraba_oilingo','Taraba / Oilingo'),
+    ('taraba_sardauna','Taraba / Sardauna'),
+    ('taraba_takum','Taraba / Takum'),
+    ('taraba_ussa','Taraba / Ussa'),
+    ('taraba_wukari','Taraba / Wukari'),
+    ('taraba_yorro','Taraba / Yorro'),
+    ('taraba_zing','Taraba / Zing'),
+    ('yobe_bade','Yobe / Bade'),
+    ('yobe_borsali','Yobe / Borsali'),
+    ('yobe_damaturu','Yobe / Damaturu'),
+    ('yobe_fika','Yobe / Fika'),
+    ('yobe_fune','Yobe / Fune'),
+    ('yobe_geidam','Yobe / Geidam'),
+    ('yobe_gogaram','Yobe / Gogaram'),
+    ('yobe_gujba','Yobe / Gujba'),
+    ('yobe_gulani','Yobe / Gulani'),
+    ('yobe_jakusko','Yobe / Jakusko'),
+    ('yobe_karasuwa','Yobe / Karasuwa'),
+    ('yobe_machina','Yobe / Machina'),
+    ('yobe_nangere','Yobe / Nangere'),
+    ('yobe_nguru','Yobe / Nguru'),
+    ('yobe_potiskum','Yobe / Potiskum'),
+    ('yobe_tarmua','Yobe / Tarmua'),
+    ('yobe_yunusari','Yobe / Yunusari'),
+    ('yobe_yusufari','Yobe / Yusufari'),
+    ('zamfara_anka','Zamfara / Anka'),
+    ('zamfara_bakura','Zamfara / Bakura'),
+    ('zamfara_bukkuyum','Zamfara / Bukkuyum'),
+    ('zamfara_bungudu','Zamfara / Bungudu'),
+    ('zamfara_gumi','Zamfara / Gumi'),
+    ('zamfara_gusau','Zamfara / Gusau'),
+    ('zamfara_isa','Zamfara / Isa'),
+    ('zamfara_kaura-namoda','Zamfara / Kaura-Namoda'),
+    ('zamfara_kiyawa','Zamfara / Kiyawa'),
+    ('zamfara_maradun','Zamfara / Maradun'),
+    ('zamfara_maru','Zamfara / Maru'),
+    ('zamfara_shinkafi','Zamfara / Shinkafi'),
+    ('zamfara_talata-mafara','Zamfara / Talata-Mafara'),
+    ('zamfara_tsafe','Zamfara / Tsafe'),
+    ('zamfara_zurmi','Zamfara / Zurmi'),
+    ('osun_aiyedire','Osun / Aiyedire'),
+    ('cross_river_biase','Cross River / Biase'),
+    ('ogun_egbado-north','Ogun / Egbado-North'),
+    ('ogun_egbado-south','Ogun / Egbado-South'),
+    ('oyo_itesiwaju','Oyo / Itesiwaju'),
+    ('oyo_ogo-oluwa','Oyo / Ogo-Oluwa'),
+    ('ebonyi_ohaukwu','Ebonyi / Ohaukwu'),
+    ('ondo_okitipupa','Ondo / Okitipupa'),
+    ('osun_oriade','Osun / Oriade'),
+    ('benue_oturkpo','Benue / Oturkpo'),
+    ('oyo_oyo-east','Oyo / Oyo-East'),
+    ('abia_ukwa-east','Abia / Ukwa-East'),
+    ('akwa_ibom_urue-ffong-oruko','Akwa Ibom / Urue-Offong-Oruko'),
+    ('foreigner','Foreigner')
+    )
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/tests.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/tests.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/tests.py	(revision 8249)
@@ -0,0 +1,29 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.uniben.testing import FunctionalLayer
+
+
+class CustomPackageUtilsTests(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def test_foo(self):
+        '''Test method foo.
+        '''
+        return
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/utils.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/utils.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/utils/utils.py	(revision 8249)
@@ -0,0 +1,201 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Customize general helper utilities for Kofa.
+"""
+import os
+import pytz
+from waeup.kofa.utils.utils import KofaUtils, sorted_phone_prefixes
+from waeup.uniben.interfaces import MessageFactory as _
+
+INT_PHONE_PREFIXES = [
+    (1, _('Nigeria'), '234'),
+    (99, _('Germany'), '49'),
+    (99, _('United States'), '1'),
+    (99, _('Niger'), '227'),
+    (99, _('Benin'), '229'),
+    (99, _('Cameroon'), '237'),
+    (99, _('United Kingdom'), '44'),
+    (99, _('France'), '33'),
+    ]
+
+class KofaUtils(KofaUtils):
+    """A collection of methods subject to customization.
+    """
+    PORTAL_LANGUAGE = 'en'
+
+    # We do not dosplay the language selector at the moment.
+    PREFERRED_LANGUAGES_DICT = {
+        }
+
+    #: A function to return
+    @classmethod
+    def sorted_phone_prefixes(cls, data=INT_PHONE_PREFIXES, request=None):
+        return sorted_phone_prefixes(data, request)
+
+    EXAM_SUBJECTS_DICT = {
+        'accounts': 'Accounts',
+        'add_general_science': 'Add General Science',
+        'add_maths': 'Add Maths',
+        'adv_elect_install_maint': 'Adv. Electrical Installation and Maintenance',
+        'agricultural_science': 'Agricultural Science',
+        'applied_electricity': 'Applied Electricity',
+        'arabi': 'Arabic',
+        'arithmetics': 'Arithmetics',
+        'art': 'Art',
+        'auto_mechanics': 'Auto Mechanics',
+        'basic_electricity': 'Basic Electricity',
+        'bible_knowledge': 'Bible Knowledge',
+        'biology': 'Biology',
+        'biology_alt_syl': 'Biology (Alt.Syl)',
+        'book_keeping': 'Book Keeping',
+        'building_construction': 'Building Construction',
+        'business_management': 'Business Management',
+        'business_construction_management': 'Business/Construction Management (Adv)',
+        'chemistry': 'Chemistry',
+        'chemistry_alt_syl': 'Chemistry (Alt.Syl)',
+        'christian_religious_studies': 'Christian Religious Studies',
+        'clerical_office_duties': 'Clerical Office Duties',
+        'clothing_and_textiles': 'Clothing and Textiles',
+        'commerce': 'Commerce',
+        'economics': 'Economics',
+        'education': 'Education',
+        'efik': 'Efik',
+        'electronics': 'Electronics',
+        'elementary_surveying': 'Elementary Surveying',
+        'english_language': 'English Language',
+        'engineering_science': 'Engineering Science',
+        'financial_accounting': 'Financial Accounting',
+        'food_and_nutrition': 'Food and Nutrition',
+        'french': 'French',
+        'further_mathematics': 'Further Mathematics',
+        'general_science': 'General Science',
+        'geography': 'Geography',
+        'german': 'German',
+        'government': 'Government',
+        'hausa': 'Hausa',
+        'hausa_literature': 'Hausa Literature',
+        'health_science': 'Health Science',
+        'history': 'History',
+        'home_management': 'Home Management',
+        'industrial_electrical_installation': 'Industrial Elect Installation (Adv)',
+        'intergrated_science': 'Intergrated Science',
+        'islamic_studies': 'Islamic Studies',
+        'literature_in_english': 'Literature in English',
+        'literature_in_nigerian_languages': 'Literature in Nigerian Languages',
+        'igbo': 'Igbo',
+        'igbo_literature': 'Igbo Literature',
+        'yoruba': 'Yoruba',
+        'yoruba_literature': 'Yoruba Literature',
+        'management_in_living': 'Management in Living',
+        'mathematics': 'Mathematics',
+        'metalwork': 'Metalwork',
+        'music': 'Music',
+        'nigerian_language': 'Nigerian Language',
+        'office_practice': 'Office Practice',
+        'physical_education': 'Physical Education',
+        'physical_health_education': 'Physical and Health Education',
+        'physics': 'Physics',
+        'physics_alt_syl': 'Physics (Alt.Syl)',
+        'principles_of_cost_accounting': 'Principles of Cost Accounting',
+        'rural_science': 'Rural Science',
+        'science': 'Science',
+        'secretarial_duties': 'Secretarial Duties',
+        'shorthand': 'Shorthand',
+        'sierra_leone_studies': 'Sierra Leone Studies',
+        'sierra_leone_languages': 'Sierra Leone Languages',
+        'social_studies': 'Social Studies',
+        'statistics': 'Statistics',
+        'teaching_practice': 'Teaching Practice',
+        'technical_drawing': 'Technical Drawing',
+        'typewriting': 'Typewriting',
+        'visual_art': 'Visual Art',
+        'woodwork': 'Woodwork',
+        'winding_elect_machines': 'Winding of Elect Machines and Elect Eng Sc'
+        }
+
+    EXAM_GRADES = (
+        ('A1', 'Excellent (A1)'),
+        ('A2', 'Very Good (A2)'),
+        ('A3', 'Good (A3)'),
+        ('B2', 'Very Good (B2)'),
+        ('B3', 'Good (B3)'),
+        ('C4', 'Credit (C4)'),
+        ('C5', 'Credit (C5)'),
+        ('C6', 'Credit (C6)'),
+        ('A', 'Pass (A)'),
+        ('B', 'Pass (B)'),
+        ('C', 'Pass (C)'),
+        ('U', 'Pass (U)'),
+        ('D7', 'Pass (D7)'),
+        ('P7', 'Pass (P7)'),
+        ('P8', 'Pass (P8)'),
+        ('E8', 'Pass (E8)'),
+        ('F9', 'Fail (F9)'),
+        ('Aa', 'A (a)'),
+        ('Bb', 'B (b)'),
+        ('Cc', 'C (c)'),
+        ('Dd', 'D (d)'),
+        ('Ee', 'E (e)'),
+        ('Ff', 'F (f)'),
+        ('Gg', 'G (g)')
+        )
+
+    INST_TYPES_DICT = {
+        'none': '',
+        'faculty': 'Faculty of',
+        'department': 'Department of',
+        'school': 'School of',
+        'office': 'Office for',
+        'centre': 'Centre for',
+        'institute': 'Institute of',
+        'school_for': 'School for',
+        'college': 'College of',
+        }
+
+    STUDY_MODES_DICT = {
+        'rmd_ft': 'Remedial with deficiencies',
+        'dp_pt': 'Diploma Part Time',
+        'ct_ft': 'Certificate Full Time',
+        'dp_ft': 'Diploma Full Time',
+        'de_pt': 'Direct Entry Part Time',
+        'pg_ft': 'Postgraduate Full Time',
+        'pg_pt': 'Postgraduate Part Time',
+        'jm_ft': 'Joint Matriculation Full Time',
+        'ume_ft': 'UME Full Time',
+        'de_ft': 'Direct Entry Full Time',
+        'ph_ft': 'Post Higher Education Full Time',
+        'transfer_pt': 'Transfer Part Time',
+        'ug_pt': 'Undergraduate Part Time',
+        'transfer_ft': 'Transfer Full Time',
+        'ct_pt': 'Certificate Part Time',
+        'ug_ft': 'Undergraduate Full Time',
+        'rm_ft': 'Remedial'
+        }
+
+    APP_CATS_DICT = {
+        'basic': 'PUME, PDE, PCE, PRENCE',
+        'no': 'no application',
+        'pg_ft': 'Postgraduate Full-Time',
+        'pg_pt': 'Postgraduate Part-Time',
+        'sandwich': 'Sandwich',
+        'cest': 'Part-Time, Diploma, Certificate'
+        }
+
+    @property
+    def tzinfo(self):
+        return pytz.timezone('Africa/Lagos')
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/widgets/__init__.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/widgets/__init__.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/widgets/__init__.py	(revision 8249)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/waeup.uniben/branches/uli-payments/src/waeup/uniben/widgets/phonewidget.py
===================================================================
--- main/waeup.uniben/branches/uli-payments/src/waeup/uniben/widgets/phonewidget.py	(revision 8249)
+++ main/waeup.uniben/branches/uli-payments/src/waeup/uniben/widgets/phonewidget.py	(revision 8249)
@@ -0,0 +1,28 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+A customized phone widget
+"""
+
+from waeup.kofa.widgets.phonewidget import PhoneWidget
+
+class CustomPhoneWidget(PhoneWidget):
+    """A phone widget without area prefix.
+    """
+    subwidget_names = ('country', 'ext')
+    bootstrap_span = 'span3'
