LP#1312699 - Allow user to edit their borrowing history
authorDan Pearl <dpearl@cwmars.org>
Wed, 23 Sep 2015 16:55:21 +0000 (12:55 -0400)
committerDan Pearl <dpearl@cwmars.org>
Wed, 23 Sep 2015 17:20:42 +0000 (13:20 -0400)
Signed-off-by: Dan Pearl <dpearl@cwmars.org>
1  2 
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
Open-ILS/src/sql/Pg/upgrade/XXXX.editable_usr_circ_history.sql
Open-ILS/src/templates/opac/myopac/circ_history.tt2

Simple merge
@@@ -1553,11 -1535,38 +1557,39 @@@ sub load_myopac_circ_history 
          where => {id => $e->requestor->id}, 
          limit => $limit,
          offset => $offset
 -    });
 +        });
 +    }
  
      $ctx->{circs} = $self->fetch_user_circs(1, [map { $_->{id} } @$circ_ids]);
-     return Apache2::Const::OK;
+     return defined($circ_handle_result) ? $circ_handle_result : Apache2::Const::OK;
+ }
+ sub handle_circ_update {
+     my $self = shift;
+     my $action = shift;
+     my $circ_ids = shift;
+     my $e = $self->editor;
+     my $url;
+     my @circ_ids = ($circ_ids) ? @$circ_ids : $self->cgi->param('circ_id'); # for non-_all actions
+     my $cstore_ses = OpenSRF::AppSession->create('open-ils.cstore');
+     $cstore_ses->connect();
+     $cstore_ses->request('open-ils.cstore.transaction.begin')->gather(1);
+     if($action =~ /delete/) {
+         for my $circ_id (@circ_ids) {
+             my $circ = $cstore_ses->request(
+                 'open-ils.cstore.direct.action.circulation.retrieve', $circ_id)->gather(1);
+             $circ->hide_from_usr_history(1);
+             my $resp = $cstore_ses->request(
+                 'open-ils.cstore.direct.action.circulation.update', $circ)->gather(1);
+         }
+     }
+     $cstore_ses->request('open-ils.cstore.transaction.commit')->gather(1);
+     $cstore_ses->disconnect();
+     return undef;
  }
  
  # TODO: action.usr_visible_holds does not return cancelled holds.  Should it?
index 0000000,420bee2..5ff459e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,54 +1,48 @@@
 -COMMIT;
 -
 -BEGIN;
 -
+ BEGIN;
+ ALTER TABLE action.circulation 
+       ADD COLUMN hide_from_usr_history boolean not null default false;
 - RETURNS SETOF action.circulation
 - LANGUAGE plpgsql
 -AS $function$
+ CREATE OR REPLACE FUNCTION action.usr_visible_circs(usr_id integer)
 -RETURN NEXT c;
++ RETURNS SETOF action.circulation AS $function$
+ DECLARE
+     c               action.circulation%ROWTYPE;
+     view_age        INTERVAL;
+     usr_view_age    actor.usr_setting%ROWTYPE;
+     usr_view_start  actor.usr_setting%ROWTYPE;
+ BEGIN
+     SELECT * INTO usr_view_age FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.circ.retention_age';
+     SELECT * INTO usr_view_start FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.circ.retention_start';
+     IF usr_view_age.value IS NOT NULL AND usr_view_start.value IS NOT NULL THEN
+         -- User opted in and supplied a retention age
+         IF oils_json_to_text(usr_view_age.value)::INTERVAL > AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ) THEN
+             view_age := AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ);
+         ELSE
+             view_age := oils_json_to_text(usr_view_age.value)::INTERVAL;
+         END IF;
+     ELSIF usr_view_start.value IS NOT NULL THEN
+         -- User opted in
+         view_age := AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ);
+     ELSE
+         -- User did not opt in
+         RETURN;
+     END IF;
+     FOR c IN
+         SELECT  *
+           FROM  action.circulation
+           WHERE usr = usr_id
+                 AND parent_circ IS NULL
+                 AND xact_start > NOW() - view_age
+                 AND NOT hide_from_usr_history
+           ORDER BY xact_start DESC
+     LOOP
 -$function$
++        RETURN NEXT c;
+     END LOOP;
+     RETURN;
+ END;
++$function$ LANGUAGE PLPGSQL;
+ COMMIT;
      <div id='checked_main'>
          <table id="acct_checked_main_header"
              title="[% l('History of Items Checked Out') %]">
 -                    <th align="center">
 -                    <input type="checkbox" onclick="var inputs=document.getElementsByTagName('input'); for (i = 0; i < inputs.length; i++) { if (inputs[i].name == 'circ_id' && !inputs[i].disabled) inputs[i].checked = this.checked;}"/>
 -                    </th>
              <thead>
                  <tr>
 -                    <th>[% l('Title / Author') %]</th>
 -                    <th>[% l('Checkout Date') %]</th>
 -                    <th>[% l('Due Date') %]</th>
 -                    <th>[% l('Date Returned') %]</th>
 -                    <th>[% l('Barcode') %]</th>
 -                    <th>[% l('Call Number') %]</th>
++                    <th align="center">
++                        <input type="checkbox" onclick="var inputs=document.getElementsByTagName('input'); for (i = 0; i < inputs.length; i++) { if (inputs[i].name == 'circ_id' && !inputs[i].disabled) inputs[i].checked = this.checked;}"/>
++                    </th>
 +                    <th>[% sort_head("sort_title", l("Title")) %]</th>
 +                    <th>[% sort_head("author", l("Author")) %]</th>
 +                    <th>[% sort_head("checkout", l("Checkout Date")) %]</th>
 +                    <th>[% sort_head("due", l("Due Date")) %]</th>
 +                    <th>[% sort_head("returned", l("Date Returned")) %]</th>
 +                    <th>[% sort_head("barcode", l("Barcode")) %]</th>
 +                    <th>[% sort_head("callnum", l("Call Number")) %]</th>
                  </tr>
              </thead>
              <tbody>
 -                [% FOR circ IN ctx.circs;
 -                    attrs = {marc_xml => circ.marc_xml};
 -                        <td align="center" style="text-align:center;">
 -                          <input type="checkbox" name="circ_id" value="[% circ.circ.id %]" />
 -                        </td>
 -                    PROCESS get_marc_attrs args=attrs; %]
 +                [%# Copy the ctx.circs into a local array, then add a SORT field
 +                    that contains the value to sort on.  Since we need the item attrs,
 +                    invoke it and save the result in ATTRS.
 +              %]
 +              [% 
 +                circ_items = ctx.circs;  # Array assignment
 +
 +                FOR circ IN circ_items;
 +                    circ.ATTRS = {marc_xml => circ.marc_xml};
 +                    PROCESS get_marc_attrs args=circ.ATTRS;
 +              
 +                    SWITCH sort_field;
 +
 +                       CASE "sort_title";
 +                          circ.SORTING = circ.ATTRS.sort_title;
 +
 +                       CASE "author";
 +                          circ.SORTING = circ.ATTRS.author;
 +
 +                       CASE "checkout";
 +                          circ.SORTING = circ.circ.xact_start;
 +
 +                       CASE "due";
 +                          circ.SORTING = circ.circ.due_date;
 +
 +                       CASE "returned";
 +                          circ.SORTING = circ.circ.checkin_time;
 +
 +                       CASE "barcode";
 +                          circ.SORTING = circ.circ.target_copy.barcode;
 +
 +                       CASE "callnum";
 +                          circ.SORTING = circ.circ.target_copy.call_number.label;
 +
 +                       CASE;
 +                          sort_field = "";
 +                    END; # SWITCH
 +                END; #FOR circ
 +
 +                IF (sort_field != "sort_title");
 +                   deemphasize_class = "";
 +                ELSE;
 +                   deemphasize_class = " class=\"sort_deemphasize\"";
 +                END;
 +                       
 +                # Apply sorting to circ_items
 +                IF (sort_field);
 +                   circ_items = circ_items.sort("SORTING");
 +                   IF (CGI.param("sort_type") == "desc");
 +                      circ_items = circ_items.reverse;
 +                   END;
 +
 +                   # Shorten the circ_items list per offset/limit/cout
 +                   hi = offset + limit - 1;
 +                   hi = hi > circ_items.max ? circ_items.max : hi;
 +
 +                   circ_items = circ_items.slice(offset, hi);
 +                END;
 +
 +                # circ_items list is now sorted.  Traverse and dump the information.
 +
 +                FOR circ IN circ_items; %]
                      <tr>
++                      <td align="center" style="text-align:center;">
++                              <input type="checkbox" name="circ_id" value="[% circ.circ.id %]" />
++                      </td>
 +                        <td>
 +                            <a href="[% mkurl(ctx.opac_root _ '/record/' _ 
 +                                circ.circ.target_copy.call_number.record.id, {}, 1) %]"
 +                                name="[% l('Catalog record') %]"><span[%- deemphasize_class -%]>
 +                                [%- circ.ATTRS.title.substr(0,circ.ATTRS.nonfiling_characters) | html %]</span>
 +                                [%- circ.ATTRS.title.substr(circ.ATTRS.nonfiling_characters) | html %]</a>
 +                        </td>
                          <td>
 -                            <a href="[% mkurl(ctx.opac_root _ '/record/' _ circ.circ.target_copy.call_number.record.id) %]" 
 -                                [% html_text_attr('title', l('Catalog record [_1]', attrs.title)) %]>
 -                                [% attrs.title | html %]
 -                            </a>
 -                            [% IF attrs.author %] /
                              <a href="[% mkurl(ctx.opac_root _ '/results',
 -                                {qtype => 'author', query => attrs.author.replace('[,\.:;]', '')}
 -                            )%]">[% attrs.author | html %]</a>
 -                            [% END %]
 +                                {qtype => 'author', query => circ.ATTRS.author.replace('[,\.:;]', '')},
 +                                1
 +                            ) %]">[% circ.ATTRS.author | html %]</a>
                          </td>
                          <td>
                              [% date.format(ctx.parse_datetime(circ.circ.xact_start),DATE_FORMAT); %]