Serials: In Alternate Serial Control interface, under Subscription Details
authorsenator <senator@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 3 Dec 2010 00:18:30 +0000 (00:18 +0000)
committersenator <senator@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 3 Dec 2010 00:18:30 +0000 (00:18 +0000)
within the Caption and Patterns tab, provide a new feature to import caption
and pattern data from existing bib records and/or legacy serials data
(serial.record_entry objects)

git-svn-id: svn://svn.open-ils.org/ILS/trunk@18906 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/Application/Serial.pm
Open-ILS/web/js/ui/default/serial/subscription.js
Open-ILS/web/js/ui/default/serial/subscription/caption_and_pattern.js
Open-ILS/web/templates/default/serial/subscription.tt2
Open-ILS/web/templates/default/serial/subscription/caption_and_pattern.tt2

index 1393a2a..c76004c 100644 (file)
@@ -2926,4 +2926,113 @@ sub replace_routing_list_users {
     undef;
 }
 
+__PACKAGE__->register_method(
+    "method" => "get_records_with_marc_85x",
+    "api_name"=>"open-ils.serial.caption_and_pattern.find_legacy_by_bib_record",
+    "stream" => 1,
+    "signature" => {
+        "desc" => "Return the specified BRE itself and/or any related SRE ".
+            "whenever they have 853-855 tags",
+        "params" => [
+            {"desc" => "Authtoken", "type" => "string"},
+            {"desc" => "bib record ID", "type" => "number"},
+        ],
+        "return" => {
+            "desc" => "objects, either bre or sre", "type" => "object"
+        }
+    }
+);
+
+sub get_records_with_marc_85x { # specifically, 853-855
+    my ($self, $client, $auth, $bre_id) = @_;
+
+    my $e = new_editor("authtoken" => $auth);
+    return $e->die_event unless $e->checkauth;
+
+    my $bre = $e->search_biblio_record_entry([
+        {"id" => $bre_id, "deleted" => "f"}, {
+            "flesh" => 1,
+            "flesh_fields" => {"bre" => [qw/creator editor owner/]}
+        }
+    ]) or return $e->die_event;
+
+    return undef unless @$bre;
+    $bre = $bre->[0];
+
+    my $record = MARC::Record->new_from_xml($bre->marc);
+    $client->respond($bre) if $record->field("85[3-5]");
+    # XXX Is passing a regex to ->field() an abuse of MARC::Record ?
+
+    my $sres = $e->search_serial_record_entry([
+        {"record" => $bre_id, "deleted" => "f"}, {
+            "flesh" => 1,
+            "flesh_fields" => {"sre" => [qw/creator editor owning_lib/]}
+        }
+    ]) or return $e->die_event;
+
+    $e->disconnect;
+
+    foreach my $sre (@$sres) {
+        $client->respond($sre) if
+            MARC::Record->new_from_xml($sre->marc)->field("85[3-5]");
+    }
+
+    undef;
+}
+
+__PACKAGE__->register_method(
+    "method" => "create_scaps_from_marcxml",
+    "api_name" => "open-ils.serial.caption_and_pattern.create_from_records",
+    "stream" => 1,
+    "signature" => {
+        "desc" => "Create caption and pattern objects from 853-855 tags " .
+            "in MARCXML documents",
+        "params" => [
+            {"desc" => "Authtoken", "type" => "string"},
+            {"desc" => "Subscription ID", "type" => "number"},
+            {"desc" => "list of MARCXML documents as strings",
+                "type" => "array"},
+        ],
+        "return" => {
+            "desc" => "Newly created caption and pattern objects",
+            "type" => "object", "class" => "scap"
+        }
+    }
+);
+
+sub create_scaps_from_marcxml {
+    my ($self, $client, $auth, $sub_id, $docs) = @_;
+
+    return undef unless ref $docs eq "ARRAY";
+
+    my $e = new_editor("authtoken" => $auth, "xact" => 1);
+    return $e->die_event unless $e->checkauth;
+
+    # Retrieve the subscription just for perm checking (whether we can create
+    # scaps at the owning lib).
+    my $sub = $e->retrieve_serial_subscription($sub_id) or return $e->die_event;
+    return $e->die_event unless
+        $e->allowed("ADMIN_SERIAL_CAPTION_PATTERN", $sub->owning_lib);
+
+    foreach my $record (map { MARC::Record->new_from_xml($_) } @$docs) {
+        foreach my $field ($record->field("85[3-5]")) {
+            my $scap = new Fieldmapper::serial::caption_and_pattern;
+            $scap->subscription($sub_id);
+            $scap->type($MFHD_NAMES_BY_TAG{$field->tag});
+            $scap->pattern_code(
+                OpenSRF::Utils::JSON->perl2JSON(
+                    [ $field->indicator(1), $field->indicator(2),
+                        map { @$_ } $field->subfields ] # flattens nested array
+                )
+            );
+            $e->create_serial_caption_and_pattern($scap) or
+                return $e->die_event;
+            $client->respond($e->data);
+        }
+    }
+
+    $e->commit or return $e->die_event;
+    undef;
+}
+
 1;
index 7c37a12..873b4d4 100644 (file)
@@ -17,6 +17,10 @@ var cgi;
 var sub;
 var sub_id;
 
+function node_by_name(name, ctx) {
+    return dojo.query("[name='" + name + "']", ctx)[0];
+}
+
 /* typing save: add {get,set}Value() to all HTML <select> elements */
 HTMLSelectElement.prototype.getValue = function() {
     return this.options[this.selectedIndex].value;
index 116cae2..0174547 100644 (file)
@@ -207,3 +207,135 @@ function SCAPEditor() {
 
     this.init.apply(this, arguments);
 }
+
+function SCAPImporter() {
+    var self = this;
+
+    this.init = function(sub) {
+        this.sub = sub;
+
+        this.template = dojo.byId("record_template");
+        this.template = this.template.parentNode.removeChild(this.template);
+        this.template.removeAttribute("id");
+
+        dojo.byId("scaps_from_bib").onclick = function() { self.launch(); };
+    };
+
+    this.launch = function() {
+        this.reset();
+        progress_dialog.show(true);
+
+        fieldmapper.standardRequest(
+            ["open-ils.serial",
+                "open-ils.serial.caption_and_pattern.find_legacy_by_bib_record"], {
+                "params": [openils.User.authtoken, this.sub.record_entry()],
+                "timeout": 10, /* sync */
+                "onresponse": function(r) {
+                    if (r = openils.Util.readResponse(r)) {
+                        self.add_record(r);
+                    }
+                }
+            }
+        );
+
+        progress_dialog.hide();
+        if (this.any_records())
+            scaps_from_bib_dialog.show();
+        else /* XXX i18n */
+            alert("No related records with any caption and pattern fields.");
+    };
+
+    this.reset = function() {
+        dojo.empty("record_holder");
+        this._records = [];
+    };
+
+    this.any_records = function() {
+        return Boolean(this._records.length);
+    }
+
+    this.add_record = function(obj) {
+        var row = dojo.clone(this.template);
+
+        var checkbox = dojo.query("input[type='checkbox']", row)[0];
+        obj._checkbox = checkbox;
+
+        this._records.push(obj);
+
+        if (obj.classname == "bre") {
+            /* XXX i18n */
+            node_by_name("obj_class", row).innerHTML = "Bibliographic";
+            node_by_name("obj_id", row).innerHTML = obj.tcn_value();
+            if (obj.owner()) {
+                openils.Util.show(
+                    node_by_name("obj_owner_container", row), "inline"
+                );
+                node_by_name("obj_owner", row).innerHTML = obj.owner();
+            }
+        } else {
+            /* XXX i18n */
+            node_by_name("obj_class", row).innerHTML = "Legacy serial";
+            node_by_name("obj_id", row).innerHTML = obj.id();
+            node_by_name("obj_owner", row).innerHTML = obj.owning_lib();
+            openils.Util.show(
+                node_by_name("obj_owner_container", row), "inline"
+            );
+        }
+
+        if (!openils.Util.isTrue(obj.active()))
+            openils.Util.show(node_by_name("obj_inactive", row), "inline");
+
+        node_by_name("obj_create", row).innerHTML =
+            /* XXX i18n */
+            dojo.string.substitute(
+                "${0}, ${1} ${2}", [
+                    obj.creator().family_name(),
+                    obj.creator().first_given_name(),
+                    obj.creator().second_given_name(),
+                ].map(function(o) { return o || ""; })
+            ) + " on " + openils.Util.timeStamp(obj.create_date());
+
+        node_by_name("obj_edit", row).innerHTML =
+            /* XXX i18n */
+            dojo.string.substitute(
+                "${0}, ${1} ${2}", [
+                    obj.editor().family_name(),
+                    obj.editor().first_given_name(),
+                    obj.editor().second_given_name(),
+                ].map(function(o) { return o || ""; })
+            ) + " on " + openils.Util.timeStamp(obj.edit_date());
+
+        dojo.place(row, "record_holder", "last");
+    };
+
+    this.import = function() {
+        var documents = this._records.filter(
+            function(o) { return o._checkbox.checked; }
+        ).map(
+            function(o) { return o.marc(); }
+        );
+
+        if (!documents.length) {
+            /* XXX i18n */
+            alert("You have selected no records from which to import.");
+        } else {
+            progress_dialog.show(true);
+            fieldmapper.standardRequest(
+                ["open-ils.serial",
+                    "open-ils.serial.caption_and_pattern.create_from_records"],{
+                    "params": [openils.User.authtoken,this.sub.id(),documents],
+                    "async": false,
+                    "onresponse": function(r) {
+                        if (r = openils.Util.readResponse(r)) {
+                            cap_editor.add_row(r);
+                        }
+                    }
+                }
+            );
+            progress_dialog.hide();
+        }
+
+    };
+
+    this.init.apply(this, arguments);
+}
index a147a58..0112292 100644 (file)
@@ -1,6 +1,7 @@
 [% WRAPPER "default/base.tt2" %]
 <script>
     var cap_editor;
+    var cap_importer;
 </script>
 <script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription.js">
 </script>
     <div dojoType="dijit.layout.ContentPane"
         title="Captions and Patterns" layoutAlign="client">
         <script type="dojo/connect" event="onShow">
-            if (!cap_editor) cap_editor = new SCAPEditor(sub_id);
+            if (!cap_editor) {
+                cap_editor = new SCAPEditor(sub_id);
+                cap_importer = new SCAPImporter(sub);
+            }
         </script>
         [% INCLUDE "default/serial/subscription/caption_and_pattern.tt2" %]
     </div>
index 3802d3d..17d8e9d 100644 (file)
         </tbody>
         <tfoot>
             <tr>
-                <td colspan="7">
-                    <button name="add">Add Caption and Pattern</button>
+                <td colspan="7" align="center">
+                    <button name="add">Add New</button>
+                    &nbsp;
+                    <button id="scaps_from_bib">
+                        Import From Bibliographic or Legacy Serial Records
+                    </button>
                 </td>
             </tr>
         </tfoot>
     </table>
 </div>
+<div class="hidden">
+    <div id="record_template" style="padding-bottom: 0.5em;">
+        <input type="checkbox" />&nbsp; <span name="obj_class"></span> record
+        #<span name="obj_id"></span>
+        <span name="obj_owner_container" class="hidden">
+            (<span name="obj_owner"></span>)
+        </span><br />
+        &nbsp; Created by <span name="obj_create"></span><br />
+        &nbsp; Edited by <span name="obj_edit"></span><br />
+        <em class="hidden" name="obj_inactive">(Inactive)</em>
+    </div>
+    <div dojoType="dijit.Dialog" execute="cap_importer.import()"
+        jsId="scaps_from_bib_dialog">
+        <div>
+            <em>
+                Select records from which to import caption and pattern fields.
+            </em>
+        </div>
+        <div id="record_holder" style="padding: 1em 0;"></div>
+        <button dojoType="dijit.form.Button" type="submit">
+            Import
+        </button>
+    </div>
+</div>