Merge branch 'master' of git.evergreen-ils.org:Evergreen into template-toolkit-opac
authorMike Rylander <mrylander@gmail.com>
Mon, 27 Jun 2011 18:26:37 +0000 (14:26 -0400)
committerMike Rylander <mrylander@gmail.com>
Mon, 27 Jun 2011 18:26:37 +0000 (14:26 -0400)
Open-ILS/src/extras/Makefile.install
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
Open-ILS/src/perlmods/lib/OpenILS/Const.pm
Open-ILS/src/sql/Pg/002.schema.config.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/0567.data.ou_setting_generate_overdue_on_lost.sql [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/util/list.js
Open-ILS/xul/staff_client/server/patron/search_result.js
README

index 263989a..2a3afa7 100644 (file)
@@ -266,6 +266,7 @@ rhel: install_redhat_pgsql centos_like
 centos_like: install_centos_rpms install_yaz install_cpan_marc install install_centos_perl create_ld_local install_cpan_safe install_cpan_force
 
 fedora14: install_fedora_rpms install_cpan install_cpan_fedora install_cpan_marc install_js_sm install_cpan_force
+fedora15: fedora14
 
 debian-squeeze: squeeze generic_debian
 squeeze: install_pgsql_client_debs_90  install_extra_debs_squeeze
index df81b27..f5cc14c 100644 (file)
@@ -1306,79 +1306,100 @@ __PACKAGE__->register_method(
 sub mark_item_missing_pieces {
        my( $self, $conn, $auth, $copy_id, $args ) = @_;
     ### FIXME: We're starting a transaction here, but we're doing a lot of things outside of the transaction
-       my $e = new_editor(authtoken=>$auth, xact =>1);
-       return $e->die_event unless $e->checkauth;
+    ### FIXME: Even better, we're going to use two transactions, the first to affect pertinent holds before checkout can
+
+       my $e2 = new_editor(authtoken=>$auth, xact =>1);
+       return $e2->die_event unless $e2->checkauth;
     $args ||= {};
 
-    my $copy = $e->retrieve_asset_copy([
+    my $copy = $e2->retrieve_asset_copy([
         $copy_id,
         {flesh => 1, flesh_fields => {'acp' => ['call_number']}}])
-            or return $e->die_event;
+            or return $e2->die_event;
 
     my $owning_lib = 
         ($copy->call_number->id == OILS_PRECAT_CALL_NUMBER) ? 
             $copy->circ_lib : $copy->call_number->owning_lib;
 
-    return $e->die_event unless $e->allowed('MARK_ITEM_MISSING_PIECES', $owning_lib);
+    return $e2->die_event unless $e2->allowed('MARK_ITEM_MISSING_PIECES', $owning_lib);
 
     #### grab the last circulation
-    my $circ = $e->search_action_circulation([
+    my $circ = $e2->search_action_circulation([
         {   target_copy => $copy->id}, 
         {   limit => 1, 
             order_by => {circ => "xact_start DESC"}
         }
     ])->[0];
 
-    if ($circ) {
-        if (! $circ->checkin_time) { # if circ active, attempt renew
-            my ($res) = $self->method_lookup('open-ils.circ.renew')->run($e->authtoken,{'copy_id'=>$circ->target_copy});
-            if (ref $res ne 'ARRAY') { $res = [ $res ]; }
-            if ( $res->[0]->{textcode} eq 'SUCCESS' ) {
-                $circ = $res->[0]->{payload}{'circ'};
-                $circ->target_copy( $copy->id );
-                $logger->info('open-ils.circ.mark_item_missing_pieces: successful renewal');
-            } else {
-                $logger->info('open-ils.circ.mark_item_missing_pieces: non-successful renewal');
-            }
-        } else {
+    if (!$circ) {
+        $logger->info('open-ils.circ.mark_item_missing_pieces: no previous checkout');
+        $e2->rollback;
+        return OpenILS::Event->new('ACTION_CIRCULATION_NOT_FOUND',{'copy'=>$copy});
+    }
 
-            my $co_params = {
-                'copy_id'=>$circ->target_copy,
-                'patron_id'=>$circ->usr,
-                'skip_deposit_fee'=>1,
-                'skip_rental_fee'=>1
-            };
+       my $holds = $e2->search_action_hold_request(
+               { 
+                       current_copy => $copy->id,
+                       fulfillment_time => undef,
+                       cancel_time => undef,
+               }
+       );
 
-            if ($U->ou_ancestor_setting_value($e->requestor->ws_ou, 'circ.block_renews_for_holds')) {
+    $logger->debug("resetting holds that target the marked copy");
+    OpenILS::Application::Circ::Holds->_reset_hold($e2->requestor, $_) for @$holds;
 
-                my ($hold, undef, $retarget) = $holdcode->find_nearest_permitted_hold(
-                    $e, $copy, $e->requestor, 1 );
+    
+       if (! $e2->commit) {
+        return $e2->die_event;
+    }
 
-                if ($hold) { # needed for hold? then due now
+       my $e = new_editor(authtoken=>$auth, xact =>1);
+       return $e->die_event unless $e->checkauth;
 
-                    $logger->info('open-ils.circ.mark_item_missing_pieces: item needed for hold, shortening due date');
-                    my $due_date = DateTime->now(time_zone => 'local');
-                    $co_params->{'due_date'} = cleanse_ISO8601( $due_date->strftime('%FT%T%z') );
-                } else {
-                    $logger->info('open-ils.circ.mark_item_missing_pieces: item not needed for hold');
-                }
-            }
+    if (! $circ->checkin_time) { # if circ active, attempt renew
+        my ($res) = $self->method_lookup('open-ils.circ.renew')->run($e->authtoken,{'copy_id'=>$circ->target_copy});
+        if (ref $res ne 'ARRAY') { $res = [ $res ]; }
+        if ( $res->[0]->{textcode} eq 'SUCCESS' ) {
+            $circ = $res->[0]->{payload}{'circ'};
+            $circ->target_copy( $copy->id );
+            $logger->info('open-ils.circ.mark_item_missing_pieces: successful renewal');
+        } else {
+            $logger->info('open-ils.circ.mark_item_missing_pieces: non-successful renewal');
+        }
+    } else {
+
+        my $co_params = {
+            'copy_id'=>$circ->target_copy,
+            'patron_id'=>$circ->usr,
+            'skip_deposit_fee'=>1,
+            'skip_rental_fee'=>1
+        };
+
+        if ($U->ou_ancestor_setting_value($e->requestor->ws_ou, 'circ.block_renews_for_holds')) {
+
+            my ($hold, undef, $retarget) = $holdcode->find_nearest_permitted_hold(
+                $e, $copy, $e->requestor, 1 );
 
-            my ($res) = $self->method_lookup('open-ils.circ.checkout.full.override')->run($e->authtoken,$co_params);
-            if (ref $res ne 'ARRAY') { $res = [ $res ]; }
-            if ( $res->[0]->{textcode} eq 'SUCCESS' ) {
-                $logger->info('open-ils.circ.mark_item_missing_pieces: successful checkout');
-                $circ = $res->[0]->{payload}{'circ'};
+            if ($hold) { # needed for hold? then due now
+
+                $logger->info('open-ils.circ.mark_item_missing_pieces: item needed for hold, shortening due date');
+                my $due_date = DateTime->now(time_zone => 'local');
+                $co_params->{'due_date'} = cleanse_ISO8601( $due_date->strftime('%FT%T%z') );
             } else {
-                $logger->info('open-ils.circ.mark_item_missing_pieces: non-successful checkout');
-                $e->rollback;
-                return $res;
+                $logger->info('open-ils.circ.mark_item_missing_pieces: item not needed for hold');
             }
         }
-    } else {
-        $logger->info('open-ils.circ.mark_item_missing_pieces: no previous checkout');
-        $e->rollback;
-        return OpenILS::Event->new('ACTION_CIRCULATION_NOT_FOUND',{'copy'=>$copy});
+
+        my ($res) = $self->method_lookup('open-ils.circ.checkout.full.override')->run($e->authtoken,$co_params);
+        if (ref $res ne 'ARRAY') { $res = [ $res ]; }
+        if ( $res->[0]->{textcode} eq 'SUCCESS' ) {
+            $logger->info('open-ils.circ.mark_item_missing_pieces: successful checkout');
+            $circ = $res->[0]->{payload}{'circ'};
+        } else {
+            $logger->info('open-ils.circ.mark_item_missing_pieces: non-successful checkout');
+            $e->rollback;
+            return $res;
+        }
     }
 
     ### Update the item status
@@ -1396,17 +1417,6 @@ sub mark_item_missing_pieces {
 
        $e->update_asset_copy($copy) or return $e->die_event;
 
-       my $holds = $e->search_action_hold_request(
-               { 
-                       current_copy => $copy->id,
-                       fulfillment_time => undef,
-                       cancel_time => undef,
-               }
-       );
-
-    $logger->debug("resetting holds that target the marked copy");
-    OpenILS::Application::Circ::Holds->_reset_hold($e->requestor, $_) for @$holds;
-
        if ($e->commit) {
 
         my $ses = OpenSRF::AppSession->create('open-ils.trigger');
index 4d65617..0b36f40 100644 (file)
@@ -342,20 +342,31 @@ sub run_method {
         $circulator->editor->rollback;
 
     } else {
+
         $circulator->editor->commit;
-    }
 
-    $circulator->script_runner->cleanup if $circulator->script_runner;
+        if ($circulator->generate_lost_overdue) {
+            # Generating additional overdue billings has to happen after the 
+            # main commit and before the final respond() so the caller can
+            # receive the latest transaction summary.
+            my $evt = $circulator->generate_lost_overdue_fines;
+            $circulator->bail_on_events($evt) if $evt;
+        }
+    }
     
     $conn->respond_complete(circ_events($circulator));
 
-    unless($circulator->bail_out) {
-        $circulator->do_hold_notify($circulator->notify_hold)
-            if $circulator->notify_hold;
-        $circulator->retarget_holds if $circulator->retarget;
-        $circulator->append_reading_list;
-        $circulator->make_trigger_events;
-    }
+    $circulator->script_runner->cleanup if $circulator->script_runner;
+
+    return undef if $circulator->bail_out;
+
+    $circulator->do_hold_notify($circulator->notify_hold)
+        if $circulator->notify_hold;
+    $circulator->retarget_holds if $circulator->retarget;
+    $circulator->append_reading_list;
+    $circulator->make_trigger_events;
+    
+    return undef;
 }
 
 sub circ_events {
@@ -522,6 +533,7 @@ my @AUTOLOAD_FIELDS = qw/
     skip_deposit_fee
     skip_rental_fee
     use_booking
+    generate_lost_overdue
 /;
 
 
@@ -3134,10 +3146,12 @@ sub checkin_handle_lost {
             $circ_lib, OILS_SETTING_VOID_LOST_PROCESS_FEE_ON_CHECKIN, $self->editor) || 0;
         my $restore_od = $U->ou_ancestor_setting_value(
             $circ_lib, OILS_SETTING_RESTORE_OVERDUE_ON_LOST_RETURN, $self->editor) || 0;
+        $self->generate_lost_overdue(1) if $U->ou_ancestor_setting_value(
+            $circ_lib, OILS_SETTING_GENERATE_OVERDUE_ON_LOST_RETURN, $self->editor);
 
         $self->checkin_handle_lost_now_found(3) if $void_lost;
         $self->checkin_handle_lost_now_found(4) if $void_lost_fee;
-        $self->checkin_handle_lost_now_found_restore_od() if $restore_od && ! $self->void_overdues;
+        $self->checkin_handle_lost_now_found_restore_od($circ_lib) if $restore_od && ! $self->void_overdues;
     }
 
     $self->copy->status($U->copy_status(OILS_COPY_STATUS_RESHELVING));
@@ -3486,6 +3500,7 @@ sub checkin_handle_lost_now_found {
 
 sub checkin_handle_lost_now_found_restore_od {
     my $self = shift;
+    my $circ_lib = shift;
 
     # ------------------------------------------------------------------
     # restore those overdue charges voided when item was set to lost
@@ -3514,4 +3529,58 @@ sub checkin_handle_lost_now_found_restore_od {
     }
 }
 
+# ------------------------------------------------------------------
+# Lost-then-found item checked in.  This sub generates new overdue
+# fines, beyond the point of any existing and possibly voided 
+# overdue fines, up to the point of final checkin time (or max fine
+# amount).  
+# ------------------------------------------------------------------
+sub generate_lost_overdue_fines {
+    my $self = shift;
+    my $circ = $self->circ;
+    my $e = $self->editor;
+
+    # Re-open the transaction so the fine generator can see it
+    if($circ->xact_finish or $circ->stop_fines) {
+        $e->xact_begin;
+        $circ->clear_xact_finish;
+        $circ->clear_stop_fines;
+        $circ->clear_stop_fines_time;
+        $e->update_action_circulation($circ) or return $e->die_event;
+        $e->xact_commit;
+    }
+
+    $e->xact_begin; # generate_fines expects an in-xact editor
+    $self->generate_fines;
+    $circ = $self->circ; # generate fines re-fetches the circ
+    
+    my $update = 0;
+
+    # Re-close the transaction if no money is owed
+    my ($obt) = $U->fetch_mbts($circ->id, $e);
+    if ($obt and $obt->balance_owed == 0) {
+        $circ->xact_finish('now');
+        $update = 1;
+    }
+
+    # Set stop fines if the fine generator didn't have to
+    unless($circ->stop_fines) {
+        $circ->stop_fines(OILS_STOP_FINES_CHECKIN);
+        $circ->stop_fines_time('now');
+        $update = 1;
+    }
+
+    # update the event data sent to the caller within the transaction
+    $self->checkin_flesh_events;
+
+    if ($update) {
+        $e->update_action_circulation($circ) or return $e->die_event;
+        $e->commit;
+    } else {
+        $e->rollback;
+    }
+
+    return undef;
+}
+
 1;
index 1be6838..de3f75e 100644 (file)
@@ -3453,6 +3453,8 @@ sub change_hold_title {
 
     $e->commit;
 
+    _reset_hold($self, $e->requestor, $_) for @$holds;
+
     return 1;
 }
 
index 6da2ed6..f86a801 100644 (file)
@@ -91,6 +91,7 @@ econst OILS_SETTING_VOID_LOST_PROCESS_FEE_ON_CHECKIN    => 'circ.void_lost_proc_
 econst OILS_SETTING_RESTORE_OVERDUE_ON_LOST_RETURN      => 'circ.restore_overdue_on_lost_return';
 econst OILS_SETTING_LOST_IMMEDIATELY_AVAILABLE          => 'circ.lost_immediately_available';
 econst OILS_SETTING_BLOCK_HOLD_FOR_EXPIRED_PATRON       => 'circ.holds.expired_patron_block';
+econst OILS_SETTING_GENERATE_OVERDUE_ON_LOST_RETURN     => 'circ.lost.generate_overdue_on_checkin';
 
 
 
index 5af4acf..18c39b3 100644 (file)
@@ -86,7 +86,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0566', :eg_version); -- miker/berick
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0567', :eg_version); -- miker/berick
 
 CREATE TABLE config.bib_source (
        id              SERIAL  PRIMARY KEY,
index dc036a9..279f2a4 100644 (file)
@@ -8788,3 +8788,19 @@ INSERT INTO action_trigger.environment (event_def, path) VALUES
     (38, 'bib_rec.bib_record.simple_record');
 
 
+INSERT INTO config.org_unit_setting_type ( name, label, description, datatype ) VALUES (
+    'circ.lost.generate_overdue_on_checkin',
+    oils_i18n_gettext( 
+        'circ.lost.generate_overdue_on_checkin',
+        'Circ:  Lost Checkin Generates New Overdues',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext( 
+        'circ.lost.generate_overdue_on_checkin',
+        'Enabling this setting causes retroactive creation of not-yet-existing overdue fines on lost item checkin, up to the point of checkin time (or max fines is reached).  This is different than "restore overdue on lost", because it only creates new overdue fines.  Use both settings together to get the full complement of overdue fines for a lost item',
+        'coust',
+        'label'
+    ),
+    'bool'
+);
diff --git a/Open-ILS/src/sql/Pg/upgrade/0567.data.ou_setting_generate_overdue_on_lost.sql b/Open-ILS/src/sql/Pg/upgrade/0567.data.ou_setting_generate_overdue_on_lost.sql
new file mode 100644 (file)
index 0000000..82c9903
--- /dev/null
@@ -0,0 +1,24 @@
+-- Evergreen DB patch XXXX.data.ou_setting_generate_overdue_on_lost.sql.sql
+BEGIN;
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0567', :eg_version);
+
+INSERT INTO config.org_unit_setting_type ( name, label, description, datatype ) VALUES (
+    'circ.lost.generate_overdue_on_checkin',
+    oils_i18n_gettext( 
+        'circ.lost.generate_overdue_on_checkin',
+        'Circ:  Lost Checkin Generates New Overdues',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext( 
+        'circ.lost.generate_overdue_on_checkin',
+        'Enabling this setting causes retroactive creation of not-yet-existing overdue fines on lost item checkin, up to the point of checkin time (or max fines is reached).  This is different than "restore overdue on lost", because it only creates new overdue fines.  Use both settings together to get the full complement of overdue fines for a lost item',
+        'coust',
+        'label'
+    ),
+    'bool'
+);
+
+COMMIT;
index 1edabec..a125c4d 100644 (file)
@@ -1716,6 +1716,7 @@ util.list.prototype = {
                 var col_id = prefix + hint + '_' + my_field.name;
                 var dataobj = hint;
                 var datafield = my_field.name;
+                var fleshed_display_field;
                 if (column_extras) {
                     if (column_extras['*']) {
                         if (column_extras['*']['dataobj']) {
@@ -1729,6 +1730,9 @@ util.list.prototype = {
                         if (column_extras[col_id]['datafield']) {
                             datafield = column_extras[col_id]['datafield'];
                         }
+                        if (column_extras[col_id]['fleshed_display_field']) {
+                            fleshed_display_field = column_extras[col_id]['fleshed_display_field'];
+                        }
                     }
                 }
                 var def = {
@@ -1743,7 +1747,24 @@ util.list.prototype = {
                 // my_field.datatype => bool float id int interval link money number org_unit text timestamp
                 if (my_field.datatype == 'link') {
                     def.render = function(my) { 
-                        return typeof my[dataobj][datafield]() == 'object' ? my[dataobj][datafield]()[my_field.key]() : my[dataobj][datafield](); 
+                        // is the object fleshed?
+                        return my[dataobj][datafield]() && typeof my[dataobj][datafield]() == 'object'
+                            // yes, show the display field
+                            ? my[dataobj][datafield]()[fleshed_display_field||my_field.key]()
+                            // no, do we have its class in data.hash?
+                            : ( typeof data.hash[ my[dataobj].Structure.field_map[datafield].class ] != 'undefined'
+                                // yes, do we have this particular object cached?
+                                ? ( data.hash[ my[dataobj].Structure.field_map[datafield].class ][ my[dataobj][datafield]() ]
+                                    // yes, show the display field
+                                    ? data.hash[ my[dataobj].Structure.field_map[datafield].class ][ my[dataobj][datafield]() ][
+                                        fleshed_display_field||my_field.key
+                                    ]()
+                                    // no, just show the raw value
+                                    : my[dataobj][datafield]()
+                                )
+                                // no, just show the raw value
+                                : my[dataobj][datafield]()
+                            ); 
                     }
                 } else {
                     def.render = function(my) { return my[dataobj][datafield](); }
index fadbb68..5449753 100644 (file)
@@ -36,7 +36,11 @@ patron.search_result.prototype = {
             'au_family_name' : { 'hidden' : false },
             'au_first_given_name' : { 'hidden' : false },
             'au_second_given_name' : { 'hidden' : false },
-            'au_dob' : { 'hidden' : false }
+            'au_dob' : { 'hidden' : false },
+            'au_profile' : { 'fleshed_display_field' : 'name' },
+            'au_ident_type' : { 'fleshed_display_field' : 'name' },
+            'au_ident_type2' : { 'fleshed_display_field' : 'name' },
+            'au_net_access_level' : { 'fleshed_display_field' : 'name' }
         }).concat(
             obj.list.fm_columns('ac',{
                 '*' : { 'remove_virtual' : true, 'expanded_label' : true, 'hidden' : true },
diff --git a/README b/README
index 4ac7ab0..c09628d 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 README for Evergreen master
-========================
+===========================
 
 Installing prerequisites:
 -------------------------
@@ -29,14 +29,17 @@ deb http://archive.ubuntu.com/ubuntu lucid-backports main universe multiverse re
   * On Fedora 14, follow the http://yum.pgrpms.org/howtoyum.php[instructions
     in the Yum HOWTO] to enable the PostgreSQL RPM Building Project yum
     repository.
+  * Fedora 15 comes with PostgreSQL 9, so no additional steps are required.
 +
-3. On Debian and Ubuntu, the easiest way to install the rest of the
+3. On Debian and Ubuntu, run `aptitude update` to retrieve the new packages
+   from the backports repository.
+4. On Debian and Ubuntu, the easiest way to install the rest of the
    prerequisites for Evergreen is to use the Makefile.install prerequisite
    installer.
-4. Issue the following commands as the root user to install prerequisites
+5. Issue the following commands as the root user to install prerequisites
    using the Makefile.install prerequisite installer, substituting
-   `debian-squeeze`, `fedora-14`, `ubuntu-lucid`, `centos`, or `rhel` for
-   <osname> below:
+   `debian-squeeze`, `fedora15`, `fedora14`, `ubuntu-lucid`, `centos`, or
+   `rhel` for <osname> below:
 +
 [source, bash]
 ------------------------------------------------------------------------------
@@ -79,25 +82,6 @@ This will install Evergreen, including example configuration files in
 The `STAFF_CLIENT_STAMP_ID` variable stamps the server-side and client-side files
 for the staff client to ensure that they match.
 
-Install Dojo Toolkit:
----------------------
-
-Evergreen uses the Dojo Toolkit to support its Web and staff client interfaces.
-
-Download the Dojo Toolkit (Dojo + Dijit + DojoX) from
-http://dojotoolkit.org/downloads
-
-Issue the following commands as the root user to fetch, extract, and copy the
-files into the correct directory, adjusting the version number to match the
-version of the Dojo Toolkit that you downloaded:
-
-[source, bash]
-------------------------------------------------------------------------------
-wget http://download.dojotoolkit.org/release-1.3.3/dojo-release-1.3.3.tar.gz
-tar -C /openils/var/web/js -xzf dojo-release-1.3.3.tar.gz
-cp -r /openils/var/web/js/dojo-release-1.3.3/* /openils/var/web/js/dojo/.
-------------------------------------------------------------------------------
-
 Create the oils_web.xml configuration file:
 -------------------------------------------
 Many administration interfaces, such as acquisitions, bookings, and various
@@ -124,13 +108,87 @@ chown -R opensrf:opensrf /openils
 Configure the Apache Web server:
 --------------------------------
 
-Use the example configuration files in `Open-ILS/examples/apache/` to configure
+1. Use the example configuration files in `Open-ILS/examples/apache/` to configure
 your Web server for the Evergreen catalog, staff client, Web services, and
 administration interfaces.
++
+.Debian and Ubuntu
+[source,bash]
+------------------------------------------------------------------------------
+cp Open-ILS/examples/apache/eg.conf       /etc/apache2/sites-available/
+cp Open-ILS/examples/apache/eg_vhost.conf /etc/apache2/
+cp Open-ILS/examples/apache/startup.pl    /etc/apache2/
+# Now set up SSL
+mkdir /etc/apache2/ssl
+cd /etc/apache2/ssl
+------------------------------------------------------------------------------
++
+.Fedora
+[source,bash]
+------------------------------------------------------------------------------
+cp Open-ILS/examples/apache/eg.conf       /etc/httpd/sites-available/
+cp Open-ILS/examples/apache/eg_vhost.conf /etc/httpd/
+cp Open-ILS/examples/apache/startup.pl    /etc/httpd/
+# Now set up SSL
+mkdir /etc/httpd/ssl
+cd /etc/httpd/ssl
+------------------------------------------------------------------------------
++
+2. Create an SSL key for the Apache server:
++
+[source,bash]
+------------------------------------------------------------------------------
+openssl req -new -x509 -days 365 -nodes -out server.crt -keyout server.key
+------------------------------------------------------------------------------
++
+The `openssl` command cuts a new SSL key for your Apache server. For a
+production server, you should purchase a signed SSL certificate, but you can
+just use a self-signed certificate and accept the warnings in the staff client
+and browser during testing and development
++
+3. Edit the `eg.conf` file that you copied into place.
+  a. Replace `Allow from 10.0.0.0/8` with `Allow from all` (to enable
+     access to the offline upload / execute interface from any workstation on
+     any network - note that you must secure this for a production instance)
+  b. Comment the line `Listen 443` as it conflicts with the same declaration
+     elsewhere in the Apache configuration files.
+4. Change the user for the Apache server.
+  * (Debian and Ubuntu): As the root user, edit `/etc/apache2/envvars`.
+    Change `export APACHE_RUN_USER=www-data` to 
+    `export APACHE_RUN_USER=opensrf`.
+  * (Fedora): As the root user, edit `/etc/httpd/conf/httpd.conf`. Change
+    `User apache` to `User opensrf`.
+5. Configure Apache with performance settings appropriate for Evergreen:
+  * (Debian and Ubuntu): As the root user, edit `/etc/apache2/apache2.conf`:
+  * (Fedora): As the root user, edit `/etc/httpd/conf/httpd.conf`:
+    a. Change `KeepAliveTimeout` to `1`. Higher values reduce the chance of
+       a request timing out unexpectedly, but increase the risk of using up
+       all available Apache child processes.
+    b. 'Optional': Change `MaxKeepAliveRequests` to `100`
+    c. Update the prefork configuration section to suit your environment. The
+       following settings apply to a busy system:
++
+[source,bash]
+------------------------------------------------------------------------------
+<IfModule mpm_prefork_module>
+   StartServers           20
+   MinSpareServers         5
+   MaxSpareServers        15
+   MaxClients            150
+   MaxRequestsPerChild 10000
+</IfModule>
+------------------------------------------------------------------------------
++
+6. (Debian and Ubuntu): As the root user, enable the Evergreen site:
++
+[source,bash]
+------------------------------------------------------------------------------
+a2dissite default  # OPTIONAL: disable the default site (the "It Works" page)
+a2ensite eg.conf
+------------------------------------------------------------------------------
 
 Configure OpenSRF for the Evergreen application:
 ------------------------------------------------
-
 There are a number of example OpenSRF configuration files in `/openils/conf/`
 that you can use as a template for your Evergreen installation.
 
@@ -236,8 +294,8 @@ version of Dojo as follows:
 [source, bash]
 ------------------------------------------------------------------------------
 wget http://download.dojotoolkit.org/release-1.3.3/dojo-release-1.3.3.tar.gz
-tar xzf dojo-release-1.3.3.tar.gz
-cp -r dojo-release-1.3.3/* /openils/var/web/js/dojo/.
+tar -C /openils/var/web/js -xzf dojo-release-1.3.3.tar.gz
+cp -r /openils/var/web/js/dojo-release-1.3.3/* /openils/var/web/js/dojo/.
 ------------------------------------------------------------------------------
 
 Getting help: