my($e, $po_id, $options) = @_;
$options ||= {};
- my $po = $e->retrieve_acq_purchase_order($po_id) or return $e->event;
+ my $po = $e->retrieve_acq_purchase_order(
+ $options->{"flesh_notes"} ? [
+ $po_id, {"flesh" => 1, "flesh_fields" => {"acqpo" => ["notes"]}}
+ ] : $po_id
+ ) or return $e->event;
if($$options{flesh_lineitems}) {
}
+__PACKAGE__->register_method(
+ method => "po_note_CUD_batch",
+ api_name => "open-ils.acq.po_note.cud.batch",
+ stream => 1,
+ signature => {
+ desc => q/Manage purchase order notes/,
+ params => [
+ {desc => "Authentication token", type => "string"},
+ {desc => "List of po_notes to manage", type => "array"},
+ ],
+ return => {desc => "Stream of successfully managed objects"}
+ }
+);
+
+sub po_note_CUD_batch {
+ my ($self, $conn, $auth, $notes) = @_;
+
+ my $e = new_editor("xact"=> 1, "authtoken" => $auth);
+ return $e->die_event unless $e->checkauth;
+ # XXX perms
+
+ my $total = @$notes;
+ my $count = 0;
+
+ foreach my $note (@$notes) {
+
+ $note->editor($e->requestor->id);
+ $note->edit_time("now");
+
+ if ($note->isnew) {
+ $note->creator($e->requestor->id);
+ $note = $e->create_acq_po_note($note) or return $e->die_event;
+ } elsif ($note->isdeleted) {
+ $e->delete_acq_po_note($note) or return $e->die_event;
+ } elsif ($note->ischanged) {
+ $e->update_acq_po_note($note) or return $e->die_event;
+ }
+
+ unless ($note->isdeleted) {
+ $note = $e->retrieve_acq_po_note($note->id) or
+ return $e->die_event;
+ }
+
+ $conn->respond(
+ {"maximum" => $total, "progress" => ++$count, "note" => $note}
+ );
+ }
+
+ $e->commit and $conn->respond_complete or return $e->die_event;
+}
+
1;
#acq-lit-export-attr { margin-left: 10px; }
.acq-lit-note-textarea { border-right: 2px solid #aaa; width:50%;}
.acq-lit-note-textarea div { padding: 4px; font-weight: bold; }
-#acq-lit-notes-tbody td {padding: 20px 10px 20px 10px; border-bottom:2px solid #aaa;}
-#acq-lit-alert-value { height: 5em; width: 20em; }
-.acq-lit-note-row { margin: 6px 0; }
-span[name="alert_code"] {color: #c00;padding-right: 1em;font-weight: bold;}
-span[name="notes_alert_flag"] {color: #c00;font-weight: bold;font-size: 110%;margin: 0 7px;}
-
-.acq-lit-li-menu-bar {width:99%; text-align:left; border:1px solid #aaa; margin:5px 0px 10px 0px;}
.acq-lit-li-menu-left {text-align:left; width:300px;}
.acq-lit-li-menu-right {text-align:left;}
.acq-lit-distrib-form-use-count { color: #999; font-weight: bold; }
.acq-lit-distrib-applied-row th { border-bottom: 1px #999 solid;padding-bottom: 4px;}
.acq-lit-table-spacer { height:20px; }
.acq-lit-row td[name="selector"] { width:1.5em; font-weight:bold; color:blue; font-size:110%;}
+
+.acq-notes-menu-bar {width:99%; text-align:left; border:1px solid #aaa; margin:5px 0px 10px 0px;}
+.acq-notes-note-row { margin: 6px 0; }
+#acq-po-notes-tbody li { margin-bottom:10px; border:1px solid #aaa; -moz-border-radius: 5px 5px 5px 5px; }
+#acq-po-notes-tbody td {padding: 20px 10px 20px 10px; border-bottom:2px solid #aaa;}
#acq-lit-notes-tbody li { margin-bottom:10px; border:1px solid #aaa; -moz-border-radius: 5px 5px 5px 5px; }
+#acq-lit-notes-tbody td {padding: 20px 10px 20px 10px; border-bottom:2px solid #aaa;}
+#acq-lit-alert-value { height: 5em; width: 20em; }
+span[name="vendor_public"] {color: #00c;padding-right: 1em;font-weight: bold;}
+span[name="alert_code"] {color: #c00;padding-right: 1em;font-weight: bold;}
+span[name="notes_alert_flag"] {color: #c00;font-weight: bold;font-size: 110%;margin: 0 7px;}
+
'DFA_TIP': "<strong>Applied by</strong>: ${0}<br /><strong>When</strong>: ${1}",
'ITS_YOU': "You",
'JUST_NOW': "Just now",
- 'EXPLAIN_DFA_MGMT': "Remove record of this distribution formula usage?"
+ 'EXPLAIN_DFA_MGMT': "Remove record of this distribution formula usage?",
+ 'VENDOR_PUBLIC': "VENDOR PUBLIC"
}
}
- //dojo.byId('acq-lit-notes-new-button').onclick = function(){acqLitCreateLiNoteDialog.show();}
-
dojo.byId('acq-lit-select-toggle').onclick = function(){self.toggleSelect()};
dojo.byId('acq-lit-info-back-button').onclick = function(){self.show('list')};
dojo.byId('acq-lit-copies-back-button').onclick = function(){self.show('list')};
this.liNotesTbody.removeChild(this.liNotesTbody.childNodes[0]);
this.show('notes');
- acqLitCreateLiNoteSubmit.onClick = function() {
+ acqLitCreateNoteSubmit.onClick = function() {
var value = acqLitCreateNoteText.attr('value');
if(!value) return;
var note = new fieldmapper.acqlin();
note.isnew(true);
+ note.vendor_public(
+ Boolean(acqLitCreateNoteVendorPublic.attr('checked'))
+ );
note.value(value);
note.lineitem(li.id());
self.updateLiNotes(li, note);
+ acqLitCreateNoteVendorPublic.attr("checked", false);
+ acqLitCreateNoteText.attr("value", "");
}
acqLitCreateAlertSubmit.onClick = function() {
}
}
+ if (note.vendor_public() == "t")
+ nodeByName("vendor_public", row).innerHTML =
+ localeStrings.VENDOR_PUBLIC;
+
nodeByName("delete", row).onclick = function() {
note.isdeleted(true);
self.liNotesTbody.removeChild(row);
var PO = null;
var liTable;
+var poNoteTable;
+
+function AcqPoNoteTable() {
+ var self = this;
+
+ this.notesTbody = dojo.byId("acq-po-notes-tbody");
+ this.notesRow = this.notesTbody.removeChild(dojo.byId("acq-po-notes-row"));
+
+ dojo.byId("acq-po-notes-back-button").onclick = function() { self.hide(); };
+ dojo.byId("acq-po-view-notes").onclick = function() { self.show(); };
+
+ /* widgets' event properties are cased likeThis */
+ acqPoCreateNoteSubmit.onClick = function() {
+ if (!acqPoCreateNoteText.attr("value")) return;
+
+ /* prep new note */
+ var note = new acqpon();
+ note.vendor_public(
+ Boolean(acqPoCreateNoteVendorPublic.attr('checked'))
+ );
+ note.value(acqPoCreateNoteText.attr("value"));
+ note.purchase_order(PO.id());
+ note.isnew(true);
+
+ /* save it */
+ self.updatePoNotes(note);
+
+ /* reset fields for next use */
+ acqPoCreateNoteText.attr("value", "");
+ acqPoCreateNoteVendorPublic.attr("checked", false);
+ };
+
+ this.drawPoNote = function(note) {
+ if (note.isdeleted())
+ return;
+
+ var row = dojo.clone(this.notesRow);
+
+ nodeByName("value", row).innerHTML = note.value();
+
+ if (note.vendor_public() == "t")
+ nodeByName("vendor_public", row).innerHTML =
+ localeStrings.VENDOR_PUBLIC;
+
+ nodeByName("delete", row).onclick = function() {
+ note.isdeleted(true);
+ self.notesTbody.removeChild(row);
+ self.updatePoNotes();
+ };
+
+ if (note.edit_time()) {
+ nodeByName("edit_time", row).innerHTML =
+ dojo.date.locale.format(
+ dojo.date.stamp.fromISOString(note.edit_time()),
+ {"formatLength": "short"}
+ );
+ }
+
+ self.notesTbody.appendChild(row);
+ };
+
+ this.drawPoNotes = function() {
+ /* sort */
+ PO.notes(
+ PO.notes().sort(
+ function(a, b) {
+ return (a.edit_time() < b.edit_time()) ? 1 : -1;
+ }
+ )
+ );
+
+ /* remove old renderings of notes */
+ dojo.empty(this.notesTbody);
+
+ PO.notes().forEach(function(o) { self.drawPoNote(o); });
+ };
+
+ this.updatePoNotesCount = function() {
+ dojo.byId("acq-po-view-notes").innerHTML = PO.notes().length;
+ };
+
+ this.updatePoNotes = function(newNote) {
+ var notes = newNote ?
+ [newNote] :
+ PO.notes().filter(
+ function(o) {
+ if (o.ischanged() || o.isnew() || o.isdeleted())
+ return o;
+ }
+ );
+
+ if (notes.length < 1)
+ return;
+
+ progressDialog.show();
+
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.po_note.cud.batch"], {
+ "async": true,
+ "params": [openils.User.authtoken, notes],
+ "onresponse": function(r) {
+ var resp = openils.Util.readResponse(r);
+ if (resp) {
+ progressDialog.update(resp);
+
+ if (!resp.note.isdeleted()) {
+ resp.note.isnew(false);
+ resp.note.ischanged(false);
+ PO.notes().push(resp.note);
+ }
+ }
+ },
+ "oncomplete": function() {
+ if (!newNote) {
+ /* remove the old changed notes */
+ var list = [];
+ PO.notes(
+ PO.notes().filter(
+ function(o) {
+ return (!(
+ o.ischanged() || o.isnew() ||
+ o.isdeleted()
+ ));
+ }
+ )
+ );
+ }
+
+ progressDialog.hide();
+ self.updatePoNotesCount();
+ self.drawPoNotes();
+ }
+ }
+ );
+ };
+
+ this.hide = function() {
+ openils.Util.hide("acq-po-notes-div");
+ liTable.show("list");
+ };
+
+ this.show = function() {
+ liTable.hide();
+ self.drawPoNotes();
+ openils.Util.show("acq-po-notes-div");
+ };
+}
function updatePoState(po_info) {
var data = po_info[PO.id()];
dojo.byId("acq-po-view-total-enc").innerHTML = PO.amount_encumbered();
dojo.byId("acq-po-view-total-spent").innerHTML = PO.amount_spent();
dojo.byId("acq-po-view-state").innerHTML = PO.state(); // TODO i18n
+ dojo.byId("acq-po-view-notes").innerHTML = PO.notes().length;
if(PO.state() == "pending") {
openils.Util.show("acq-po-activate");
}
}
+
function init() {
+ /* set up li table */
liTable = new AcqLiTable();
liTable.reset();
liTable.isPO = poId;
liTable.poUpdateCallback = updatePoState;
+ /* set up po notes table */
+ poNoteTable = new AcqPoNoteTable();
+
+ /* retrieve data and populate */
fieldmapper.standardRequest(
['open-ils.acq', 'open-ils.acq.purchase_order.retrieve'],
{ async: true,
- params: [openils.User.authtoken, poId, {flesh_price_summary:true, flesh_lineitem_count:true}],
+ params: [openils.User.authtoken, poId, {
+ "flesh_price_summary": true,
+ "flesh_lineitem_count": true,
+ "flesh_notes": true
+ }],
oncomplete: function(r) {
PO = openils.Util.readResponse(r); /* save PO globally */
renderPo();
pcrud.update(PO, {
oncomplete : function(r, cudResults) {
var stat = cudResults[0];
- if(stat)
+ if(stat)
dojo.byId('acq-po-view-name').innerHTML = value;
}
});
</div>
<!-- Lineitem notes table -->
- <div id='acq-lit-notes-div' class='hidden'>
-
- <div class='acq-lit-li-menu-bar'>
- <table style='width:100%'>
- <tr>
- <td style='text-align:left;'>
- <div dojoType='dijit.form.Button' id='acq-lit-notes-back-button'>↖ Return</div>
- </td>
- <td style='text-align:right;'>
- <div dojoType="dijit.form.DropDownButton">
- <span>New Note</span>
- <div dojoType="dijit.TooltipDialog">
- <div class="acq-lit-note-row">
- <div jsId='acqLitCreateNoteText' dojoType='dijit.form.Textarea' style='height:5em; width:25em;' name='note'></div>
- </div>
- <button jsId='acqLitCreateLiNoteSubmit' dojoType='dijit.form.Button' type="submit">Create</button>
- </div>
- </div>
- <div dojoType="dijit.form.DropDownButton">
- <span>New Alert</span>
- <div dojoType="dijit.TooltipDialog">
- <div class="acq-lit-note-row">
- <label for="acq-lit-alert-alert-text">Choose alert code </label>
- <input id="acq-lit-alert-alert-text" jsId="acqLitAlertAlertText" dojoType="dijit.form.FilteringSelect" labelAttr="code" searchAttr="code" required="true" />
- </div>
- <div class="acq-lit-note-row">
- <label for="acq-lit-alert-value">Additional comments</label>
- <div jsId="acqLitAlertNoteValue" id="acq-lit-alert-value" dojoType="dijit.form.Textarea" name="value"></div>
- </div>
- <button jsId="acqLitCreateAlertSubmit" dojoType="dijit.form.Button" type="submit">Create</button>
- </div>
- </div>
- </td>
- </tr>
- </table>
- </div>
-
- <ol id='acq-lit-notes-tbody'>
- <li id='acq-lit-notes-row'>
- <table style='width:100%;' class='oils-generic-table'>
- <tr>
- <td width='70%' align='left'><span name="alert_code"></span><span style='font-size:120%' name='value'></span></td>
- <td align='right' style='padding-right:30px;'>
- <span name='edit_time'></span>
- <span style='padding-left:4px;'><a name='delete' href='javascript:void(0);' style='color:red;'>Delete</a></span>
- </td>
- </tr>
- </div>
- </li>
- </ol>
- </div>
+ [% note_table_for = "Lit" %]
+ [% INCLUDE "default/acq/common/notes.tt2" %]
<!-- Copies table -->
<div id='acq-lit-li-details' class='hidden'>
--- /dev/null
+[% note_table_for_lc = note_table_for | lower %]
+ <div id="acq-[% note_table_for_lc %]-notes-div" class="hidden">
+ <div class="acq-notes-menu-bar">
+ <table style="width:100%">
+ <tr>
+ <td style="text-align:left;">
+ <div dojoType="dijit.form.Button" id="acq-[% note_table_for_lc %]-notes-back-button">↖ Return</div>
+ </td>
+ <td style="text-align:right;">
+ <div dojoType="dijit.form.DropDownButton">
+ <span>New Note</span>
+ <div dojoType="dijit.TooltipDialog">
+ <div class="acq-notes-note-row">
+ <div jsId="acq[% note_table_for %]CreateNoteText" dojoType="dijit.form.Textarea" style="height:5em; width:25em;" name="note"></div>
+ <div style="margin: 8px 0;">
+ <div dojoType="dijit.form.CheckBox" jsId="acq[% note_table_for %]CreateNoteVendorPublic" name="vendor_public" id="acq-[% note_table_for_lc %]-create-note-vendor-public"></div><label for="acq-[% note_table_for_lc %]-create-note-vendor-public">Note is vendor-public</label>
+ </div>
+ </div>
+ <button jsId="acq[% note_table_for %]CreateNoteSubmit" dojoType="dijit.form.Button" type="submit">Create</button>
+ </div>
+ </div>
+[% IF note_table_for == "Lit" %]
+ <div dojoType="dijit.form.DropDownButton">
+ <span>New Alert</span>
+ <div dojoType="dijit.TooltipDialog">
+ <div class="acq-notes-note-row">
+ <label for="acq-lit-alert-alert-text">Choose alert code </label>
+ <input id="acq-lit-alert-alert-text" jsId="acqLitAlertAlertText" dojoType="dijit.form.FilteringSelect" labelAttr="code" searchAttr="code" required="true" />
+ </div>
+ <div class="acq-notes-note-row">
+ <label for="acq-lit-alert-value">Additional comments</label>
+ <div jsId="acqLitAlertNoteValue" id="acq-lit-alert-value" dojoType="dijit.form.Textarea" name="value"></div>
+ </div>
+ <button jsId="acqLitCreateAlertSubmit" dojoType="dijit.form.Button" type="submit">Create</button>
+ </div>
+ </div>
+[% END %]
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ <ol id="acq-[% note_table_for_lc %]-notes-tbody">
+ <li id="acq-[% note_table_for_lc %]-notes-row">
+ <table style="width:100%;" class="oils-generic-table">
+ <tr>
+ <td width="70%" align="left">
+ <span name="vendor_public"></span>
+ <span name="alert_code"></span>
+ <span style="font-size:120%" name="value"></span>
+ </td>
+ <td align="right" style="padding-right:30px;">
+ <span name="edit_time"></span>
+ <span style="padding-left:4px;">
+ <a name="delete" href="javascript:void(0);" style="color:red;">Delete</a>
+ </span>
+ </td>
+ </tr>
+ </table>
+ </li>
+ </ol>
+ </div>
<tr><td>Total Encumbered</td><td>$<span id='acq-po-view-total-enc'/></td></tr>
<tr><td>Total Spent</td><td>$<span id='acq-po-view-total-spent'/></td></tr>
<tr><td>Status</td><td><span id='acq-po-view-state'/></td></tr>
+ <tr>
+ <td>Notes</td>
+ <td>
+ <a href="javascript:void(0);"
+ id="acq-po-view-notes"></a>
+ </td>
+ </tr>
<tr><td><a class='hidden' id='acq-po-activate' href='javascript:void(0);' onclick='activatePo()'>Activate Order</a></td></tr>
<tr><td><a class="hidden" id="acq-po-split" href="javascript:void(0);" onclick="if (confirm(localeStrings.CONFIRM_SPLIT_PO)) splitPo();">Split Order by Lineitems</a></td></tr>
</table>
</div>
<script type="text/javascript">var poId = '[% ctx.page_args.0 %]';</script>
[% INCLUDE 'default/acq/common/li_table.tt2' %]
+ [% note_table_for = "Po" %]
+ [% INCLUDE "default/acq/common/notes.tt2" %]
</div>
[% END %]