use strict;
use warnings;
+
use OpenILS::Application;
use base qw/OpenILS::Application/;
use OpenILS::Application::AppUtils;
return {'num_items_received' => scalar @$items, 'new_unit_id' => $new_unit_id};
}
+__PACKAGE__->register_method(
+ method => "receive_items_one_unit_per",
+ api_name => "open-ils.serial.receive_items.one_unit_per",
+ stream => 1,
+ api_level => 1,
+ argc => 1,
+ signature => {
+ desc => "Marks items in a list as received, creates a new unit for each item if any unit is fleshed on",
+ "params" => [ {
+ name => "items",
+ desc => "array of serial items, possibly fleshed with units and definitely fleshed with stream->distribution",
+ type => "array"
+ }
+ ],
+ "return" => {
+ desc => "The item ID for each item successfully received",
+ type => "int"
+ }
+ }
+);
+
+sub receive_items_one_unit_per {
+ # XXX This function may be temporary. unitize_items() would seem to aim to
+ # accomodate what this function does as well as other variations on the
+ # operation (binding multiple items into one unit, etc.?) plus generating
+ # summaries. This is just a minimal get-it-working-now implementation.
+ # In the future, when unitize_items() is ready, perhaps any registered
+ # method names that point to this function can be repointed at
+ # unitize_items()
+
+ my ($self, $client, $auth, $items) = @_;
+
+ my $e = new_editor("authtoken" => $auth, "xact" => 1);
+ return $e->die_event unless $e->checkauth;
+
+ my $user_id = $e->requestor->id;
+
+ # Get a list of all the non-virtual field names in a serial::unit for
+ # merging given unit objects with template-built units later.
+ # XXX move this somewhere global so it isn't re-run all the time
+ my $all_unit_fields =
+ $Fieldmapper::fieldmap->{"Fieldmapper::serial::unit"}->{"fields"};
+ my @real_unit_fields = grep {
+ not $all_unit_fields->{$_}->{"virtual"}
+ } keys %$all_unit_fields;
+
+ foreach my $item (@$items) {
+ # Note that we expect a certain fleshing on the items we're getting.
+ my $sdist = $item->stream->distribution;
+
+ # Create unit if given by user
+ if (ref $item->unit) {
+ # detach from the item, as we need to create separately
+ my $user_unit = $item->unit;
+
+ # get a unit based on associated template
+ my $template_unit = _build_unit($e, $sdist, "receive");
+ if ($U->event_code($template_unit)) {
+ $e->rollback;
+ $template_unit->{"note"} = "Item ID: " . $item->id;
+ return $template_unit;
+ }
+
+ # merge built unit with provided unit from user
+ foreach (@real_unit_fields) {
+ unless ($user_unit->$_) {
+ $user_unit->$_($template_unit->$_);
+ }
+ }
+
+ # set the incontrovertibles on the unit
+ $user_unit->edit_date("now");
+ $user_unit->create_date("now");
+ $user_unit->editor($user_id);
+ $user_unit->creator($user_id);
+
+ return $e->die_event unless $e->create_serial_unit($user_unit);
+
+ # save reference to new unit
+ $item->unit($e->data->id);
+ }
+
+ # Create notes if given by user
+ if (ref($item->notes) and @{$item->notes}) {
+ foreach my $note (@{$item->notes}) {
+ $note->creator($user_id);
+ $note->create_date("now");
+
+ return $e->die_event unless $e->create_serial_item_note($note);
+ }
+
+ $item->clear_notes; # They're saved; we no longer want them here.
+ }
+
+ # Set the incontrovertibles on the item
+ $item->date_received("now");
+ $item->edit_date("now");
+ $item->editor($user_id);
+
+ return $e->die_event unless $e->update_serial_item($item);
+
+ # send client a response
+ $client->respond($item->id);
+ }
+
+ # XXX TODO update basic/supplementary/index summaries
+
+ $e->commit or return $e->die_event;
+ undef;
+}
+
sub _build_unit {
my $editor = shift;
my $sdist = shift;
my $mode = shift;
my $attr = $mode . '_unit_template';
- my $template = $editor->retrieve_asset_copy_template($sdist->$attr);
+ my $template = $editor->retrieve_asset_copy_template($sdist->$attr) or
+ return new OpenILS::Event("SERIAL_DISTRIBUTION_HAS_NO_COPY_TEMPLATE");
my @parts = qw( status location loan_duration fine_level age_protect circulate deposit ref holdable deposit_amount price circ_modifier circ_as_type alert_message opac_visible floating mint_condition );
$unit->circ_lib($sdist->holding_lib);
$unit->creator($editor->requestor->id);
$unit->editor($editor->requestor->id);
+
$attr = $mode . '_call_number';
- $unit->call_number($sdist->$attr);
+ my $cn = $sdist->$attr or
+ return new OpenILS::Event("SERIAL_DISTRIBUTION_HAS_NO_CALL_NUMBER");
+
+ $unit->call_number($cn);
$unit->barcode('AUTO');
$unit->sort_key('');
$unit->summary_contents('');
my $issuance_ids = $e->json_query({
"select" => {
"siss" => [
- {"transform" => "distinct", "column" => "id"}
+ {"transform" => "distinct", "column" => "id"},
+ "date_published"
]
},
"from" => {"siss" => "sitem"},
"where" => {
"subscription" => $sub_id,
"+sitem" => {"date_received" => undef}
+ },
+ "order_by" => {
+ "siss" => {"date_published" => {"direction" => "asc"}}
}
+
}) or return $e->die_event;
$client->respond($e->retrieve_serial_issuance($_->{"id"}))
}
function T(s) { return document.createTextNode(s); }
-function D(s) {return s ? openils.Util.timeStamp(s, {"selector":"date"}) : "";}
-function node_by_name(s, ctx) {return dojo.query("[name='" + s + "']", ctx)[0];}
+function D(s) {return s ? openils.Util.timeStamp(s,{"selector":"date"}) : "";}
+function node_by_name(s, ctx) {return dojo.query("[name='"+ s +"']",ctx)[0];}
function num_sort(a, b) {
[a, b] = [Number(a), Number(b)];
this._clear_entry_batch_row();
- this._copy_loc_by_lib = {};
+ this._location_by_lib = {};
/* empty the entry receiving table if we're starting over */
if (this.item_cache) {
- for (var id in this.item_cache)
+ for (var id in this.item_cache) {
this.finish_receipt(this.item_cache[id]);
+ hard_empty(this.entry_tbody);
+ }
+ /* XXX incredibly, running hard_empty() more than once seems to be
+ * good and necessary. There's a bug under the covers somewhere,
+ * but this keeps it out of sight for the moment. */
+ hard_empty(this.entry_tbody);
}
+ hard_empty(this.entry_tbody);
this.rows = {};
this.item_cache = {};
return issuances;
};
- this._build_circ_mod_dropdown = function() {
- if (!this._built_circ_mod_dropdown) {
+ this._build_circ_modifier_dropdown = function() {
+ if (!this._built_circ_modifier_dropdown) {
var menulist = dojo.create("menulist");
var menupopup = dojo.create("menupopup", null, menulist, "only");
dojo.create(
var mods = [];
fieldmapper.standardRequest(
- ["open-ils.circ", "open-ils.circ.circ_modifier.retrieve.all"], {
- "params": [],
+ ["open-ils.circ", "open-ils.circ.circ_modifier.retrieve.all"],{
+ "params": [{"full": true}],
"async": false,
"onresponse": function(r) {
if (mods = openils.Util.readResponse(r)) {
- mods.forEach(
+ mods.sort(
+ function(a,b) {
+ return a.code() > b.code() ? 1 :
+ b.code() > a.code() ? -1 :
+ 0;
+ }
+ ).forEach(
function(mod) {
dojo.create(
"menuitem", {
- "value": mod, "label": mod
+ "value": mod.code(),
+ /* XXX use format string */
+ "label": mod.code()+" "+mod.name()
}, menupopup, "last"
);
}
);
if (!mods.length) {
/* in this case, discard menulist and menupopup */
- this._built_circ_mod_dropdown =
+ this._built_circ_modifier_dropdown =
dojo.create("description", {"value": "-"});
} else {
- this._built_circ_mod_dropdown = menulist;
+ this._built_circ_modifier_dropdown = menulist;
}
}
- return dojo.clone(this._built_circ_mod_dropdown);
+ return dojo.clone(this._built_circ_modifier_dropdown);
};
- this._extend_circ_mod_for_batch = function(control) {
+ this._extend_circ_modifier_for_batch = function(control) {
dojo.create(
"menuitem", {"value": -1, "label": "---"},
dojo.query("menupopup", control)[0],
return control;
};
- this._build_copy_loc_dropdown = function(locs, add_unset_value) {
+ this._build_location_dropdown = function(locs, add_unset_value) {
var menulist = dojo.create("menulist");
var menupopup = dojo.create("menupopup", null, menulist, "only");
return menulist;
};
- this._get_copy_locs_for_lib = function(lib) {
- if (!this._copy_loc_by_lib[lib]) {
+ this._get_locations_for_lib = function(lib) {
+ if (!this._location_by_lib[lib]) {
fieldmapper.standardRequest(
- ["open-ils.circ", "open-ils.circ.copy_location.retrieve.all"], {
+ ["open-ils.circ", "open-ils.circ.copy_location.retrieve.all"],{
"params": [lib, false, true],
"async": false,
"onresponse": function(r) {
if (locs = openils.Util.readResponse(r))
- self._copy_loc_by_lib[lib] = locs;
+ self._location_by_lib[lib] = locs;
}
}
);
}
- return this._copy_loc_by_lib[lib];
+ return this._location_by_lib[lib];
};
this._build_receive_toggle = function(item) {
],
"async": false,
"oncomplete": function(r) {
- /* These two things better come before readResponse(), which
- * can throw exceptions. */
+ /* These two things better come before readResponse(),
+ * which can throw exceptions. */
busy(false);
dojo.byId("bib_lookup_submit").disabled = false;
this.issuances.sort(
function(a, b) {
- if (a.date_published() > b.date_published()) return 1;
- else if (b.date_published() > a.date_published()) return -1;
+ if (a.date_published()>b.date_published()) return 1;
+ else if (b.date_published()>a.date_published()) return -1;
else return 0;
}
).forEach(
this.batch_controls.note = dojo.create("textbox", {"size": 20})
);
- node_by_name("copy_loc", row).appendChild(
- this.batch_controls.copy_loc = this._build_copy_loc_dropdown(
- /* XXX is 1 really the right value below? */
- this._get_copy_locs_for_lib(1),
+ node_by_name("location", row).appendChild(
+ this.batch_controls.location = this._build_location_dropdown(
+ /* XXX TODO build a smarter list. rather than all copy locs
+ * under OU #1, try building a list of copy locs available to
+ * all OUs represented in actual items */
+ this._get_locations_for_lib(1),
true /* add_unset_value */
)
);
- node_by_name("circ_mod", row).appendChild(
- this.batch_controls.circ_mod = this._extend_circ_mod_for_batch(
- this._build_circ_mod_dropdown()
- )
+ node_by_name("circ_modifier", row).appendChild(
+ this.batch_controls.circ_modifier =
+ this._extend_circ_modifier_for_batch(
+ this._build_circ_modifier_dropdown()
+ )
);
node_by_name("price", row).appendChild(
)
);
- n("copy_loc").appendChild(
- this._build_copy_loc_dropdown(
- this._get_copy_locs_for_lib(
+ n("location").appendChild(
+ this._build_location_dropdown(
+ this._get_locations_for_lib(
item.stream().distribution().holding_lib().id()
)
)
);
n("note").appendChild(dojo.create("textbox", {"size": 20}));
- n("circ_mod").appendChild(this._build_circ_mod_dropdown());
+ n("circ_modifier").appendChild(this._build_circ_modifier_dropdown());
n("price").appendChild(dojo.create("textbox", {"size": 9}));
n("receive").appendChild(this._build_receive_toggle(item));
};
this.receive = function() {
- var recv_ids = [];
+ var items = [];
for (var id in this.rows) {
- /* XXX TODO: get field values, send to ML,
- * and yes do trimming here. */
- if (!this._row_disabled(id)) recv_ids.push(id);
+ if (this._row_disabled(id))
+ continue;
+
+ var item = this.item_cache[id];
+
+ var barcode = this._row_field_value(id, "barcode");
+ if (barcode) {
+ var unit = new sunit();
+ unit.barcode(barcode);
+
+ ["price", "location", "circ_modifier"].forEach(
+ function(field) {
+ var value = self._row_field_value(id, field).trim();
+ if (value) unit[field](value);
+ }
+ );
+
+
+ item.unit(unit);
+ }
+
+ var note_value = this._row_field_value(id, "note").trim();
+ if (note_value) {
+ var note = new sin();
+ note.item(id);
+ note.pub(false);
+ note.title(S("receive_time_note"));
+ note.value(note_value);
+
+ item.notes([note]);
+ }
+
+ items.push(item);
}
busy(true);
fieldmapper.standardRequest(
- ["open-ils.serial", "open-ils.serial.items.receive_by_id"], {
- "params": [authtoken, recv_ids],
+ ["open-ils.serial", "open-ils.serial.receive_items.one_unit_per"],{
+ "params": [authtoken, items],
"async": true,
"oncomplete": function(r) {
try {
- while (item = openils.Util.readResponse(r))
- self.finish_receipt(item);
+ while (item_id = openils.Util.readResponse(r))
+ self.finish_receipt(item_id);
} catch (E) {
alert(E);
}
);
};
- this.finish_receipt = function(item) {
- dojo.destroy(this.rows[item.id()]);
- delete this.rows[item.id()];
- delete this.item_cache[item.id()];
+ this.finish_receipt = function(item_id) {
+ hard_empty(this.rows[item_id]);
+ dojo.destroy(this.rows[item_id]);
+ delete this.rows[item_id];
+ delete this.item_cache[item_id];
};
this.autogen_if_appropriate = function(textbox, item_id) {