2 WRAPPER "staff/base.tt2";
3 ctx.page_title = l("Offline");
4 ctx.page_app = "egOffline";
8 <script type="text/ng-template" id="offline-template">
11 <div class="col-md-12">
12 <div class="input-group">
13 <div class="input-group-addon"><b>[% l('Workstation') %]</b></div>
14 <div class="input-group-addon">
15 <select class="form-control" required
16 ng-model="workstation"
17 ng-options="ws.id as ws.name for ws in workstations"></select>
19 <div class="input-group-addon"><b>[% l('Working location') %]</b></div>
20 <div class="input-group-addon">
21 <eg-org-selector sticky-setting="eg.org.offline_location" selected="org"></eg-org-selector>
23 <div class="input-group-addon">
25 class="btn btn-primary"
26 ng-disabled="all_xact.length == 0 || active_tab == 'register'"
28 [% l('Save Transactions') %]
31 class="btn btn-default"
32 ng-disabled="!printed"
33 ng-click="reprintLast()">
34 [% l('Reprint Last Receipt') %]
37 class="btn btn-default"
38 ng-disabled="buildingBlockList"
40 ng-click="downloadBlockList()">
41 [% l('Download block list') %]
44 class="btn btn-default"
45 ng-disabled="pending_xacts.length == 0"
48 default-file-name="pending.xacts"
49 json-array="pending_xacts"
50 >[% l('Export Transactions') %]</button>
56 <div class="row col-md-offset-3 col-md-6 pad-vert">
57 <div ng-show="logged_in && active_tab != 'session'" class="alert alert-danger">
58 <h2>[% l('Warning') %]</h2>
59 [% l('You are about to enter offline mode. If you proceed, you will be logged out.') %]
62 <button class="btn btn-danger" ng-click="logout()">[% l('Proceed') %]</button>
66 <div class="row col-md-12 pad-vert">
67 <div class="col-md-12">
68 <uib-tabset active="active_tab">
69 <!-- note that non-numeric index values must be enclosed in single-quotes,
70 otherwise selecting the active table won't work cleanly -->
71 <uib-tab ng-show="logged_in" index="'session'" heading="[% l('Session Management') %]">
72 <div class="col-md-12" ng-controller="OfflineSessionCtrl">
73 <uib-tabset active="active_session_tab">
74 <uib-tab index="'pending'" heading="[% l('Pending Transactions') %]">
76 <div class="col-md-12 container">
78 class="btn btn-default"
79 ng-disabled="pending_xacts.length == 0"
81 default-file-name="pending.xacts"
82 json-array="pending_xacts"
83 >[% l('Export Transactions') %]</button>
84 <div class="btn-group">
85 <span class="btn btn-default btn-file">
86 [% l('Import Transactions') %]
87 <input type="file" eg-file-reader container="imported_pending_xacts.data">
90 <button class="btn btn-warning pull-right" ng-click="clear_pending()">[% l('Clear Transactions') %]</button>
94 <div class="col-md-12 container">
98 <th>[% l('Type') %]</th>
99 <th>[% l('Timestamp') %]</th>
100 <th>[% l('Patron Barcode') %]</th>
101 <th>[% l('Item Barcode') %]</th>
102 <th>[% l('Non-cataloged Type') %]</th>
103 <th>[% l('Checkout Date') %]</th>
104 <th>[% l('Due Date') %]</th>
105 <th>[% l('Checkin Date') %]</th>
106 <th>[% l('First Name') %]</th>
107 <th>[% l('Last Name') %]</th>
111 <tr ng-repeat="xact in pending_xacts track by $index">
112 <td>{{xact.type}}</td>
113 <td>{{createDate(xact.timestamp, true) | date:'short'}}</td>
114 <td>{{xact.patron_barcode || xact.user.card.barcode}}</td>
115 <td>{{xact.barcode}}</td>
116 <td>{{lookupNoncatTypeName(xact.noncat_type)}}</td>
117 <td>{{createDate(xact.checkout_time) | date:'short'}}</td>
118 <td>{{createDate(xact.due_date) | date:'shortDate'}}</td>
119 <td>{{createDate(xact.backdate) | date:'shortDate'}}</td>
120 <td>{{xact.user.first_given_name}}</td>
121 <td>{{xact.user.family_name}}</td>
128 <uib-tab index="'offline_sessions'" heading="[% l('Offline Sessions') %]">
130 <div class="col-md-12">
132 class="btn btn-primary"
133 ng-disabled="!logged_in"
134 ng-click="createSession()">[% l('Create Session') %]</button>
136 class="btn btn-default pull-right"
137 ng-disabled="!logged_in"
138 ng-click="refreshSessions()">[% l('Refresh') %]</button>
142 <div class="col-md-12"><h2>[% l('Session List') %]</h2></div>
145 <div class="col-md-12">
146 <table class="table" ts-wrapper>
149 <th ts-criteria="org">[% l('Organization') %]</th>
150 <th ts-criteria="creator">[% l('Created By') %]</th>
151 <th ts-criteria="description">[% l('Description') %]</th>
152 <th ts-criteria="create_time|parseInt" ts-default="descending">[% l('Date Created') %]</th>
153 <th>[% l('Upload Count') %]</th>
154 <th>[% l('Transactions Processed') %]</th>
155 <th ts-criteria="end_time|parseInt">[% l('Date Completed') %]</th>
161 ng-repeat="ses in sessions track by $index"
162 ng-click="setSession(ses, $index)"
163 ng-class="{'bg-info':current_session_index==$index}"
166 <td>{{ses.creator}}</td>
167 <td>{{ses.description}}</td>
168 <td>{{createDate(ses.create_time, true) | date:'short'}}</td>
169 <td>{{ses.total}}</td>
170 <td>{{ses.num_complete}}</td>
171 <td>{{createDate(ses.end_time, true) | date:'short'}}</td>
174 class="btn btn-info btn-xs"
175 ng-disabled="!logged_in || pending_xacts.length == 0 || ses.end_time"
176 ng-click="uploadPending(ses, $index)"
177 >[% l('Upload') %]</button>
179 class="btn btn-warning btn-xs"
180 ng-disabled="!logged_in || ses.total == 0 || ses.end_time"
181 ng-click="processSession(ses, $index)"
182 >[% l('Process') %]</button>
190 <div class="col-md-12"><hr/></div>
193 <div class="col-md-12"><h2>[% l('Exception List') %]</h2></div>
196 <div class="col-md-12">
197 <table class="table">
200 <th>[% l('Workstation') %]</th>
201 <th>[% l('Type') %]</th>
202 <th>[% l('Timestamp') %]</th>
203 <th>[% l('Event Name') %]</th>
204 <th>[% l('Patron Barcode') %]</th>
205 <th>[% l('Item Barcode') %]</th>
206 <th>[% l('Non-cataloged Type') %]</th>
207 <th>[% l('Checkout Date') %]</th>
208 <th>[% l('Due Date') %]</th>
209 <th>[% l('Checkin Date') %]</th>
214 <tr ng-repeat="xact in current_session.exceptions track by $index">
215 <td>{{xact.command._workstation}}</td>
216 <td>{{xact.command.type}}</td>
217 <td>{{createDate(xact.command.timestamp, true) | date:'short'}}</td>
218 <td>{{xact.event.textcode}}</td>
219 <td>{{xact.command.patron_barcode || xact.command.user.card.barcode}}</td>
220 <td>{{xact.command.barcode}}</td>
221 <td>{{lookupNoncatTypeName(xact.command.noncat_type)}}</td>
222 <td>{{createDate(xact.command.checkout_time) | date:'short'}}</td>
223 <td>{{createDate(xact.command.due_date) | date:'shortDate'}}</td>
224 <td>{{createDate(xact.command.backdate) | date:'shortDate'}}</td>
227 class="btn btn-info btn-xs"
228 ng-disabled="!logged_in || !xact.command.barcode"
229 ng-click="retrieveItem(xact.command.barcode)">[% l('Item') %]</button>
231 class="btn btn-info btn-xs"
232 ng-disabled="!logged_in || (!xact.command.patron_barcode && xact.command.user.card.barcode)"
233 ng-click="retrievePatron(xact.command.patron_barcode)">[% l('Patron') %]</button>
235 class="btn btn-info btn-xs"
236 ng-disabled="!logged_in"
237 ng-click="retrieveDetails(xact)">[% l('Debug') %]</button>
248 <uib-tab index="'checkout'" heading="[% l('Checkout') %]">
252 <!-- left-hand side -->
253 <div class="col-md-6" style="border-right:solid 1px;">
255 <div class="col-md-1"></div>
256 <div class="col-md-4">
259 <div class="col-md-4">
260 <eg-date-input id="co_duedate" ng-model="shared.due_date" out-of-range="shared.outOfRange" min-date="minDate"></eg-date-input>
262 <div class="col-md-3">
263 <select class="form-control" ng-model="shared.due_date_offset" ng-change="resetDueDate()">
264 <option value="">[% l('No Offset') %]</option>
265 <option value="3">[% l('Today + 3 days') %]</option>
266 <option value="7">[% l('Today + 7 days') %]</option>
267 <option value="14">[% l('Today + 14 days') %]</option>
268 <option value="30">[% l('Today + 30 days') %]</option>
273 <div class="row pad-vert">
274 <div class="col-md-1"></div>
275 <div class="col-md-4">
276 [% l('Patron barcode:') %]
278 <div class="col-md-7">
279 <input class="form-control" type="text" ng-model="checkout.patron_barcode" next-on-enter="co_barcode"/>
283 <div class="row pad-vert">
284 <div class="col-md-1">
285 <input type="radio" ng-model="barcode_type" value="barcode" id="bc_radio"/>
287 <div class="col-md-4">
288 <label style="font-weight:normal !important;" for="bc_radio">[% l('Item Barcode:') %]</label>
290 <div class="col-md-7">
291 <input id="co_barcode"
293 ng-init="barcode_type = 'barcode'"
294 ng-disabled="barcode_type != 'barcode'"
296 ng-model="checkout.barcode"
297 eg-enter="!notEnough('checkout') && add('checkout')"
303 <div class="col-md-1">
304 <input type="radio" ng-model="barcode_type" value="noncat" id="nc_radio"/>
306 <div class="col-md-4">
307 <label style="font-weight:normal !important;" for="nc_radio">[% l('Non-cataloged Type:') %]</label>
309 <div class="col-md-5">
312 ng-disabled="barcode_type != 'noncat'"
313 ng-options="nct.id() as nct.name() for nct in noncats"
314 ng-model="checkout.noncat_type"
316 <option value="">[% l('Select Non-cataloged Type') %]</option>
319 <div class="col-md-2">
322 ng-disabled="barcode_type != 'noncat'"
326 ng-model="checkout.noncat_count"
331 <div class="row pad-vert">
332 <div class="col-md-2">
333 <button class="btn btn-warning" ng-click="clear('checkout')">[% l('Clear') %]</button>
335 <div class="col-md-4">
336 <input id="do_check_co" type="checkbox" ng-model="strict_barcode" ng-click="changeCheck()"></input>
337 <label for="do_check_co">[% l('Strict Barcode') %]</label>
339 <div class="col-md-6">
340 <input id="do_print_co" type="checkbox" ng-model="do_print" ng-click="changePrint()"></input>
341 <label for="do_print_co">[% l('Print receipt') %]</label>
342 <button class="btn btn-primary pull-right" ng-disabled="notEnough('checkout')" ng-click="add('checkout','co_barcode')">[% l('Checkout') %]</button>
348 <!-- right-hand side -->
349 <div class="col-md-6 container">
350 <table class="table">
353 <th>[% l('Patron barcode') %]</th>
354 <th>[% l('Item barcode') %]</th>
355 <th>[% l('Due date') %]</th>
359 <tr ng-repeat="xact in xact_page.checkout track by $index">
360 <td>{{xact.patron_barcode}}</td>
362 <div ng-if="xact.barcode">{{xact.barcode}}</div>
363 <div ng-if="!xact.barcode">{{lookupNoncatTypeName(xact.noncat_type)}} ({{xact.noncat_count}})</div>
365 <td>{{xact.due_date | date:'shortDate'}}</td>
374 <uib-tab index="'renew'" heading="[% l('Renew') %]">
378 <!-- left-hand side -->
379 <div class="col-md-6" style="border-right:solid 1px;">
381 <div class="col-md-1"></div>
382 <div class="col-md-4">
385 <div class="col-md-4">
386 <eg-date-input ng-model="shared.due_date" out-of-range="shared.outOfRange" min-date="minDate"></eg-date-input>
388 <div class="col-md-3">
389 <select class="form-control" ng-model="shared.due_date_offset" ng-change="resetDueDate()">
390 <option value="">[% l('No Offset') %]</option>
391 <option value="3">[% l('Today + 3 days') %]</option>
392 <option value="7">[% l('Today + 7 days') %]</option>
393 <option value="14">[% l('Today + 14 days') %]</option>
394 <option value="30">[% l('Today + 30 days') %]</option>
399 <div class="row pad-vert">
400 <div class="col-md-1"></div>
401 <div class="col-md-4">
402 [% l('Patron barcode:') %]
404 <div class="col-md-7">
405 <input class="form-control" type="text" ng-model="renew.patron_barcode" next-on-enter="re_barcode"/>
409 <div class="row pad-vert">
410 <div class="col-md-1"></div>
411 <div class="col-md-4">
412 [% l('Item Barcode:') %]
414 <div class="col-md-7">
415 <input class="form-control" type="text" ng-model="renew.barcode" id="re_barcode" eg-enter="!notEnough('renew') && add('renew')"/>
419 <div class="row pad-vert">
420 <div class="col-md-2">
421 <button class="btn btn-warning" ng-click="clear('renew')">[% l('Clear') %]</button>
423 <div class="col-md-4">
424 <input id="do_check_r" type="checkbox" ng-model="strict_barcode" ng-click="changeCheck()"></input>
425 <label for="do_check_r">[% l('Strict Barcode') %]</label>
427 <div class="col-md-6">
428 <input id="do_print_r" type="checkbox" ng-model="do_print" ng-click="changePrint()"></input>
429 <label for="do_print_r">[% l('Print receipt') %]</label>
430 <button class="btn btn-primary pull-right" ng-disabled="notEnough('renew')" ng-click="add('renew','re_barcode')">[% l('Renew') %]</button>
436 <!-- right-hand side -->
437 <div class="col-md-6 container">
438 <table class="table">
441 <th>[% l('Patron barcode') %]</th>
442 <th>[% l('Item barcode') %]</th>
443 <th>[% l('Due date') %]</th>
447 <tr ng-repeat="xact in xact_page.renew track by $index">
448 <td>{{xact.patron_barcode}}</td>
449 <td>{{xact.barcode}}</td>
450 <td>{{xact.due_date | date:'shortDate'}}</td>
459 <uib-tab index="'in_house_use'" heading="[% l('In-house Use') %]">
463 <!-- left-hand side -->
464 <div class="col-md-6 container" style="border-right:solid 1px;">
467 <div class="col-md-1"></div>
468 <div class="col-md-5">
469 [% l('Use count:') %]
471 <div class="col-md-6">
472 <input class="form-control" type="number" min="1" max="100" next-on-enter="ihu_barcode" ng-model="in_house_use.count"/>
476 <div class="row pad-vert">
477 <div class="col-md-1"></div>
478 <div class="col-md-5">
479 [% l('Item Barcode:') %]
481 <div class="col-md-6">
482 <input class="form-control" type="text" ng-model="in_house_use.barcode" eg-enter="add('in_house_use')" id="ihu_barcode"/>
486 <div class="row pad-vert">
487 <div class="col-md-2">
488 <button class="btn btn-warning" ng-click="clear('in_house_use')">[% l('Clear') %]</button>
490 <div class="col-md-4">
491 <input id="do_check_ihu" type="checkbox" ng-model="strict_barcode" ng-click="changeCheck()"></input>
492 <label for="do_check_ihu">[% l('Strict Barcode') %]</label>
494 <div class="col-md-6">
495 <input id="do_print_ihu" type="checkbox" ng-model="do_print" ng-click="changePrint()"></input>
496 <label for="do_print_ihu">[% l('Print receipt') %]</label>
497 <button class="btn btn-primary pull-right" ng-disabled="notEnough('in_house_use')" ng-click="add('in_house_use','ihu_barcode')">[% l('Record Use') %]</button>
503 <!-- right-hand side -->
504 <div class="col-md-6 container">
505 <table class="table">
508 <th>[% l('Item barcode') %]</th>
509 <th>[% l('Use count') %]</th>
513 <tr ng-repeat="xact in xact_page.in_house_use track by $index">
514 <td>{{xact.barcode}}</td>
515 <td>{{xact.count}}</td>
524 <uib-tab index="'checkin'" heading="[% l('Checkin') %]">
528 <!-- left-hand side -->
529 <div class="col-md-6" style="border-right:solid 1px;">
532 <div class="col-md-1"></div>
533 <div class="col-md-5">
534 [% l('Checkin Date:') %]
536 <div class="col-md-6">
537 <eg-date-input ng-model="checkin.backdate"></eg-date-input>
541 <div class="row pad-vert">
542 <div class="col-md-1"></div>
543 <div class="col-md-5">
544 [% l('Item Barcode:') %]
546 <div class="col-md-6">
547 <input id="ci_barcode" class="form-control" type="text" ng-model="checkin.barcode" eg-enter="!notEnough('checkin') && add('checkin')"/>
551 <div class="row pad-vert">
552 <div class="col-md-2">
553 <button class="btn btn-warning" ng-click="clear('checkin')">[% l('Clear') %]</button>
555 <div class="col-md-4">
556 <input id="do_check_ci" type="checkbox" ng-model="strict_barcode" ng-click="changeCheck()"></input>
557 <label for="do_check_ci">[% l('Strict Barcode') %]</label>
559 <div class="col-md-6">
560 <input id="do_print_ci" type="checkbox" ng-model="do_print" ng-click="changePrint()"></input>
561 <label for="do_print_ci">[% l('Print receipt') %]</label>
562 <button class="btn btn-primary pull-right" ng-disabled="notEnough('checkin')" ng-click="add('checkin','ci_barcode')">[% l('Checkin') %]</button>
569 <!-- right-hand side -->
570 <div class="col-md-6 container">
571 <table class="table">
574 <th>[% l('Item barcode') %]</th>
575 <th>[% l('Effective Checkin date') %]</th>
579 <tr ng-repeat="xact in xact_page.checkin track by $index">
580 <td>{{xact.barcode}}</td>
581 <td>{{xact.backdate | date:'shortDate'}}</td>
590 <uib-tab index="'register'" heading="[% l('Register Patron') %]">
591 <div ng-controller="PatronRegCtrl">
592 <div>[% INCLUDE 'staff/circ/patron/t_edit.tt2' %]</div>
602 <!-- offline page app -->
603 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/file.js"></script>
604 <script src="[% ctx.media_prefix %]/js/ui/default/staff/offline.js"></script>
606 angular.module('egCoreMod').run(['egStrings', function(s) {
607 s.OFFLINE_BLOCKLIST_SUCCESS = "[% l('Offline blocklist downloaded') %]";
608 s.OFFLINE_BLOCKLIST_FAIL = "[% l('Error downloading offline blocklist') %]";
609 s.DUPLICATE_BARCODE = "[% l('Duplicate item barcode') %]";
611 s.ALLOW = "[% l('Allow') %]";
612 s.REJECT = "[% l('Reject') %]";
614 s.REG_ADDR_TYPE = "[% l('Mailing') %]";
615 s.REG_INVALID_FIELDS =
616 "[% l('Please enter valid values for all required fields.') %]"
617 s.REG_ADDR_REQUIRED =
618 "[% l('An address is required during registration.') %]"
620 s.PATRON_BLOCKED_WHY = {};
621 s.PATRON_BLOCKED_WHY.D = "[% l('Patron has penalties') %]";
622 s.PATRON_BLOCKED_WHY.L = "[% l('Barcode is reported Lost') %]";
623 s.PATRON_BLOCKED_WHY.E = "[% l('Patron account is Expired') %]";
624 s.PATRON_BLOCKED_WHY.B = "[% l('Patron account is Barred') %]";
628 <link rel="stylesheet" href="[% ctx.base_path %]/staff/css/circ.css" />
629 <link rel="stylesheet" href="[% ctx.media_prefix %]/js/ui/default/staff/build/css/tablesort.css" />