SWGRL-DEC 168.13.49.1 168.13.49.254
SWGRL-MIL 168.13.50.1 168.13.50.254
SWGRL-SEM 168.13.51.1 168.13.51.254
+TCPLS-THOMAS 168.13.57.1 168.13.57.254
+TCPLS-MEIGS 168.13.55.1 168.13.55.254
+TCPLS-COOL 168.13.53.1 168.13.53.254
+TCPLS-BOS 168.13.52.1 168.13.52.254
+TCPLS-OCH 168.13.54.1 168.13.54.254
+TCPLS-PACO 168.13.56.1 168.13.56.254
TLLS-LS 168.13.161.1 168.13.161.254
TLLS-MV 168.13.162.1 168.13.162.254
TRRL-BRANT 168.13.113.1 168.13.113.254
To: ${EMAIL_RECIPIENT}
From: ${EMAIL_SENDER}
Reply-To: ${EMAIL_REPLY_TO}
+Errors-To: ${EMAIL_ERRORS_TO}
Subject: Overdue Materials Notification
${EMAIL_HEADERS}
${OVERDUE_ITEMS[
${TITLE} : ${AUTHOR} ${CALL_NUMBER}
-Due: ${DUE_DAY}/${DUE_MONTH}/${DUE_YEAR} ID: ${ITEM_BARCODE}
+Due: ${DUE_MONTH}/${DUE_DAY}/${DUE_YEAR} ID: ${ITEM_BARCODE}
]}
To: {TO}
From: {FROM}
Reply-To: {REPLY_TO}
-Subject: Report {REPORT_NAME} failed
+Subject: Report Failure Notification
-Your report, {REPORT_NAME}, schedued to run at {RUN_TIME} has failed with
-the following error message:
+Your report, named [{REPORT_NAME}], was scheduled to run at {RUN_TIME} has failed with the following error message:
-{ERROR_TEXT}
+ {ERROR_TEXT}
The SQL command attempted was:
-{SQL}
+ {SQL}
If you are unsure of the meaning of this message, please contact PINES staff
and give them both the error message and the SQL command.
To: {TO}
From: {FROM}
Reply-To: {REPLY_TO}
-Subject: Report {REPORT_NAME} complete
+Subject: Report Completion Notification
-Your report, {REPORT_NAME}, schedued to run at {RUN_TIME} completed
-at {COMPLETE_TIME} and is available for viewing a the following URL:
+Your report, named [{REPORT_NAME}], was scheduled to run at {RUN_TIME} and completed at {COMPLETE_TIME}.
+It is available for viewing at the following URL:
-{OUTPUT_URL}
+ {OUTPUT_URL}
If you have any general questions, please contact the PINES staff.
my @patron_data = fetch_patron_data($usr);
my @org_data = fetch_org_data($org);
+ return unless (@patron_data and @org_data);
+
my $email;
if( $email = $patron_data[0]->email
}
my $name = $org->name;
- my $email = $org->email;
my $phone = $org->phone;
+ my $email = $org->email;
+
my( $s1, $s2, $city, $state, $zip );
my $baddr = $org->billing_address || $org->mailing_address;
my $r = ($range eq '7day') ? 7 : 14;
- $org_email ||= $mail_sender;
+ # - default to the global sender for the errors-to header
+ my $errors_to = $mail_sender;
+
+ # if they have an org setting for errors-to, use that as the errors-to address
+ if( my $set = $e->search_actor_org_unit_setting(
+ { name => 'org.bounced_emails', org_unit => $org->id } )->[0] ) {
+
+ my $bemail = JSON->JSON2perl($set->value);
+ $errors_to = $bemail if $bemail;
+ }
+
$tmpl =~ s/\${EMAIL_RECIPIENT}/$pemail/;
- $tmpl =~ s/\${EMAIL_SENDER}/$mail_sender/o;
- $tmpl =~ s/\${EMAIL_REPLY_TO}/$org_email/;
- $tmpl =~ s/\${EMAIL_HEADERS}//;
+ $tmpl =~ s/\${EMAIL_SENDER}/$errors_to/o;
+ $tmpl =~ s/\${EMAIL_REPLY_TO}/$errors_to/;
+ $tmpl =~ s/\${EMAIL_ERRORS_TO}/$errors_to/;
+ $tmpl =~ s/\${EMAIL_HEADERS}//; # - we have no additional headers to add
$tmpl =~ s/\${RANGE}/$r/;
$tmpl =~ s/\${DATE}/$mon\/$day\/$year/;
my $evt = shift;
warn "OD_notice: ".Dumper($evt) . "\n";
$logger->error("OD_notice: ".Dumper($evt));
+ return undef;
}
RECIPIENT=$2;
DATE=$(date +%Y-%m-%d);
DAY=$(date +%u);
-BSCONFIG="/openils/conf/bootstrap.conf"
+BSCONFIG="/openils/conf/bootstrap_od.conf"
ODDIR="/openils/var/data/overdue";
export EG_OVERDUE_EMAIL_TEMPLATE="../extras/overdue_notice_email";
/* ------------------------------------------------------------------------------ */
function uEditFetchIdentTypes() {
_debug("uEditFetchIdentTypes()");
+ var s = fetchXULStash();
+ if (typeof s.list != 'undefined')
+ if (typeof s.list.cit != 'undefined') return s.list.cit;
var req = new Request(FETCH_ID_TYPES);
req.send(true);
return req.result();
function uEditFetchStatCats() {
_debug("uEditFetchStatCats()");
+ var s = fetchXULStash();
+ if (typeof s.list != 'undefined')
+ if (typeof s.list.my_actsc != 'undefined') return s.list.my_actsc;
var req = new Request(SC_FETCH_ALL, SESSION);
req.send(true);
return req.result();
function uEditFetchSurveys() {
_debug("uEditFetchSurveys()");
+ var s = fetchXULStash();
+ if (typeof s.list != 'undefined')
+ if (typeof s.list.asv != 'undefined') return s.list.asv;
var req = new Request(SV_FETCH_ALL, SESSION);
req.send(true);
return req.result();
function uEditFetchGroups() {
_debug("uEditFetchGroups()");
+ var s = fetchXULStash();
+ if (typeof s.tree != 'undefined')
+ if (typeof s.tree.pgt != 'undefined') return s.tree.pgt;
var req = new Request(FETCH_GROUPS);
req.send(true);
return req.result();
function uEditFetchNetLevels() {
_debug("uEditFetchNetLevels()");
+ var s = fetchXULStash();
+ if (typeof s.list != 'undefined')
+ if (typeof s.list.cnal != 'undefined') return s.list.cnal;
var req = new Request(FETCH_NET_LEVELS, SESSION);
req.send(true);
return req.result();
var cloneUser = fetchFleshedUser(clone);
patron.usrgroup(cloneUser.usrgroup());
- if( cloneUser.day_phone() )
+ if( cloneUser.day_phone() ) {
$('ue_day_phone').value = cloneUser.day_phone();
- if( cloneUser.evening_phone() )
+ $('ue_day_phone').onchange();
+ }
+
+ if( cloneUser.evening_phone() ) {
$('ue_night_phone').value = cloneUser.evening_phone();
- if( cloneUser.other_phone() )
- $('ue_other_phone').value = cloneUser.other_phone();
- setSelector($('ue_org_selector'), cloneUser.home_ou());
+ $('ue_night_phone').onchange();
+ }
+ if( cloneUser.other_phone() ) {
+ $('ue_other_phone').value = cloneUser.other_phone();
+ $('ue_other_phone').onchange();
+ }
+ setSelector($('ue_org_selector'), cloneUser.home_ou());
setSelector($('ue_profile'), cloneUser.profile());
/* force the expire date to be set */
$('ue_profile').onchange();
+ $('ue_org_selector').onchange();
for( var a in cloneUser.addresses() ) {
var addr = cloneUser.addresses()[a];
function() { window.xulG.spawn_editor({ses:cgi.param('ses'),usr:id}) };
if( userCache[id] ) {
+ var usr = userCache[id];
nnode.appendChild(text(
usr.first_given_name() + ' ' + usr.family_name()));
config:
@./config.sh
+default_config:
+ @./config.sh default
+
oldconfig: install.conf
install.conf:
from django.db import models
+from django.db.models import signals
+from django.dispatch import dispatcher
# Create your models here.
INTERVAL_HELP_TEXT = 'examples: "1 hour", "14 days", "3 months", "DD:HH:MM:SS.ms"'
+PG_SCHEMAS = "actor, permission, public, config"
+
+
+# ---------------------------------------------------------------------
+# Here we run some SQL to manually set the postgres schema search-paths
+# ---------------------------------------------------------------------
+def setSearchPath():
+ from django.db import connection
+ cursor = connection.cursor()
+ cursor.execute("SET search_path TO %s" % PG_SCHEMAS)
+dispatcher.connect(setSearchPath, signal=signals.class_prepared)
+dispatcher.connect(setSearchPath, signal=signals.pre_init)
+
class GrpTree(models.Model):
- name = models.CharField(maxlength=100)
- parent_id = models.ForeignKey('self', null=True, related_name='children', db_column='parent')
- description = models.CharField(blank=True, maxlength=200)
- perm_interval = models.CharField(blank=True, maxlength=100, help_text=INTERVAL_HELP_TEXT)
- application_perm = models.CharField(blank=True, maxlength=100)
- usergroup = models.BooleanField()
- class Admin:
- list_display = ('name', 'description')
- list_filter = ['parent_id']
- search_fields = ['name', 'description']
- class Meta:
- db_table = 'grp_tree'
- ordering = ['name']
- verbose_name = 'User Group'
- def __str__(self):
- return self.name
+ name = models.CharField(maxlength=100)
+ parent_id = models.ForeignKey('self', null=True, related_name='children', db_column='parent')
+ description = models.CharField(blank=True, maxlength=200)
+ perm_interval = models.CharField(blank=True, maxlength=100, help_text=INTERVAL_HELP_TEXT)
+ application_perm = models.CharField(blank=True, maxlength=100)
+ usergroup = models.BooleanField()
+ class Admin:
+ list_display = ('name', 'description')
+ list_filter = ['parent_id']
+ search_fields = ['name', 'description']
+ class Meta:
+ db_table = 'grp_tree'
+ ordering = ['name']
+ verbose_name = 'User Group'
+ def __str__(self):
+ return self.name
class OrgUnitType(models.Model):
- name = models.CharField(maxlength=100)
- opac_label = models.CharField(maxlength=100)
- depth = models.IntegerField()
- parent_id = models.ForeignKey('self', null=True, related_name='children', db_column='parent')
- can_have_vols = models.BooleanField()
- can_have_users = models.BooleanField()
- class Meta:
- db_table = 'org_unit_type'
- verbose_name = 'Library Type'
- class Admin:
- list_display = ('name', 'depth')
- list_filter = ['parent_id']
- ordering = ['depth']
- def __str__(self):
- return self.name
+ name = models.CharField(maxlength=100)
+ opac_label = models.CharField(maxlength=100)
+ depth = models.IntegerField()
+ parent_id = models.ForeignKey('self', null=True, related_name='children', db_column='parent')
+ can_have_vols = models.BooleanField()
+ can_have_users = models.BooleanField()
+ class Meta:
+ db_table = 'org_unit_type'
+ verbose_name = 'Library Type'
+ class Admin:
+ list_display = ('name', 'depth')
+ list_filter = ['parent_id']
+ ordering = ['depth']
+ def __str__(self):
+ return self.name
class PermList(models.Model):
- code = models.CharField(maxlength=100)
- description = models.CharField(blank=True, maxlength=200)
- class Admin:
- list_display = ('code','description')
- search_fields = ['code']
- class Meta:
- db_table = 'perm_list'
- ordering = ['code']
- verbose_name = 'Permission'
- def __str__(self):
- return self.code
+ code = models.CharField(maxlength=100)
+ description = models.CharField(blank=True, maxlength=200)
+ class Admin:
+ list_display = ('code','description')
+ search_fields = ['code']
+ class Meta:
+ db_table = 'perm_list'
+ ordering = ['code']
+ verbose_name = 'Permission'
+ def __str__(self):
+ return self.code
class GrpPermMap(models.Model):
- grp_id = models.ForeignKey(GrpTree, db_column='grp')
- perm_id = models.ForeignKey(PermList, db_column='perm')
- depth_id = models.ForeignKey(OrgUnitType, to_field='depth', db_column='depth')
- grantable = models.BooleanField()
- class Admin:
- list_filter = ['grp_id']
- search_fields = ['grp_id', 'perm_id']
- list_display = ('grp_id', 'perm_id')
- class Meta:
- db_table = 'grp_perm_map'
- ordering = ['grp_id']
- verbose_name = 'Permission Setting'
- def __str__(self):
- return str(self.grp_id)+' -> '+str(self.perm_id)
+ grp_id = models.ForeignKey(GrpTree, db_column='grp')
+ perm_id = models.ForeignKey(PermList, db_column='perm')
+ depth_id = models.ForeignKey(OrgUnitType, to_field='depth', db_column='depth')
+ grantable = models.BooleanField()
+ class Admin:
+ list_filter = ['grp_id']
+ list_display = ('perm_id', 'grp_id', 'depth_id')
+ class Meta:
+ db_table = 'grp_perm_map'
+ ordering = ['perm_id', 'grp_id']
+ verbose_name = 'Permission Setting'
+ def __str__(self):
+ return str(self.grp_id)+' -> '+str(self.perm_id)
+
+
+
+""" There's no way to do user-based mangling given the size of the data without custom handling.
+ When you try to create a new permission map, it tries to load all users into a dropdown selector :(
+
+class User(models.Model):
+ card_id = models.ForeignKey('Card', db_column='card')
+ profile_id = models.ForeignKey(GrpTree, db_column='profile')
+ usrname = models.CharField(blank=False, null=False, maxlength=200)
+ def __str__(self):
+ return "%s (%s)" % ( str(self.card_id), str(self.usrname))
+ class Meta:
+ db_table = 'usr'
+ verbose_name = 'User'
+
+class UsrPermMap(models.Model):
+ usr_id = models.ForeignKey(User, db_column='usr')
+ perm_id = models.ForeignKey(PermList, db_column='perm')
+ depth_id = models.ForeignKey(OrgUnitType, to_field='depth', db_column='depth')
+ grantable = models.BooleanField()
+ class Admin:
+ search_fields = ['usr_id', 'perm_id'] # we need text fields to search...
+ class Meta:
+ db_table = 'usr_perm_map'
+ verbose_name = 'User Permission'
+ def __str__(self):
+ return "%s -> %s" % ( str(self.usr_id), str(self.perm_id) )
+
+
+class Card(models.Model):
+ usr_id = models.ForeignKey(User, db_column='usr')
+ barcode = models.CharField(blank=False, null=False, maxlength=200)
+ active = models.BooleanField()
+ def __str__(self):
+ return self.barcode
+ class Meta:
+ db_table = 'card'
+ verbose_name = 'Card'
+"""
+
+
class OrgAddress(models.Model):
- valid = models.BooleanField()
- org_unit_id = models.ForeignKey('OrgUnit', db_column='org_unit')
- address_type = models.CharField(blank=False, maxlength=200, default='MAILING')
- street1 = models.CharField(blank=False, maxlength=200)
- street2 = models.CharField(maxlength=200)
- city = models.CharField(blank=False, maxlength=200)
- county = models.CharField(maxlength=200)
- state = models.CharField(blank=False, maxlength=200)
- country = models.CharField(blank=False, maxlength=200)
- post_code = models.CharField(blank=False, maxlength=200)
- class Admin:
- search_fields = ['street1', 'city', 'post_code']
- list_filter = ['org_unit_id']
- list_display = ('street1', 'street2', 'city', 'county', 'state', 'post_code')
- class Meta:
- ordering = ['city']
- db_table = 'org_address'
- verbose_name = 'Library Address'
- def __str__(self):
- return self.street1+' '+self.city+', '+self.state+' '+self.post_code
+ valid = models.BooleanField()
+ org_unit_id = models.ForeignKey('OrgUnit', db_column='org_unit')
+ address_type = models.CharField(blank=False, maxlength=200, default='MAILING')
+ street1 = models.CharField(blank=False, maxlength=200)
+ street2 = models.CharField(maxlength=200)
+ city = models.CharField(blank=False, maxlength=200)
+ county = models.CharField(maxlength=200)
+ state = models.CharField(blank=False, maxlength=200)
+ country = models.CharField(blank=False, maxlength=200)
+ post_code = models.CharField(blank=False, maxlength=200)
+ class Admin:
+ search_fields = ['street1', 'city', 'post_code']
+ list_filter = ['org_unit_id']
+ list_display = ('street1', 'street2', 'city', 'county', 'state', 'post_code')
+ class Meta:
+ ordering = ['city']
+ db_table = 'org_address'
+ verbose_name = 'Library Address'
+ def __str__(self):
+ return self.street1+' '+self.city+', '+self.state+' '+self.post_code
class OrgUnit(models.Model):
- parent_ou_id = models.ForeignKey('self', null=True, related_name='children', db_column='parent_ou')
- ou_type_id = models.ForeignKey(OrgUnitType, db_column='ou_type')
- shortname = models.CharField(maxlength=200)
- name = models.CharField(maxlength=200)
- email = models.EmailField(null=True, blank=True)
- phone = models.CharField(maxlength=200, null=True, blank=True)
- ill_address_id = models.ForeignKey(OrgAddress, db_column='ill_address', null=True, blank=True)
- holds_address_id = models.ForeignKey(OrgAddress, db_column='holds_address', null=True, blank=True)
- mailing_address_id = models.ForeignKey(OrgAddress, db_column='mailing_address', null=True, blank=True)
- billing_address_id = models.ForeignKey(OrgAddress, db_column='billing_address', null=True, blank=True)
- class Admin:
- search_fields = ['name', 'shortname']
- list_display = ('shortname', 'name')
- class Meta:
- db_table = 'org_unit'
- ordering = ['shortname']
- verbose_name = 'Library'
- def __str__(self):
- return self.shortname
+ parent_ou_id = models.ForeignKey('self', null=True, related_name='children', db_column='parent_ou')
+ ou_type_id = models.ForeignKey(OrgUnitType, db_column='ou_type')
+ shortname = models.CharField(maxlength=200)
+ name = models.CharField(maxlength=200)
+ email = models.EmailField(null=True, blank=True)
+ phone = models.CharField(maxlength=200, null=True, blank=True)
+ opac_visible = models.BooleanField(blank=True)
+ ill_address_id = models.ForeignKey(OrgAddress, db_column='ill_address', null=True, blank=True)
+ holds_address_id = models.ForeignKey(OrgAddress, db_column='holds_address', null=True, blank=True)
+ mailing_address_id = models.ForeignKey(OrgAddress, db_column='mailing_address', null=True, blank=True)
+ billing_address_id = models.ForeignKey(OrgAddress, db_column='billing_address', null=True, blank=True)
+ class Admin:
+ search_fields = ['name', 'shortname']
+ #list_filter = ['parent_ou_id'] # works, but shows all libs as options, so ruins the point
+ list_display = ('shortname', 'name')
+ class Meta:
+ db_table = 'org_unit'
+ ordering = ['shortname']
+ verbose_name = 'Library'
+ def __str__(self):
+ return self.shortname
class RuleCircDuration(models.Model):
- name = models.CharField(maxlength=200)
- extended = models.CharField(maxlength=200, help_text=INTERVAL_HELP_TEXT);
- normal = models.CharField(maxlength=200, help_text=INTERVAL_HELP_TEXT);
- shrt = models.CharField(maxlength=200, help_text=INTERVAL_HELP_TEXT);
- max_renewals = models.IntegerField()
- class Admin:
- search_fields = ['name']
- list_display = ('name','extended','normal','shrt','max_renewals')
- class Meta:
- db_table = 'rule_circ_duration'
- ordering = ['name']
- verbose_name = 'Circ Duration Rule'
- def __str__(self):
- return self.name
+ name = models.CharField(maxlength=200)
+ extended = models.CharField(maxlength=200, help_text=INTERVAL_HELP_TEXT);
+ normal = models.CharField(maxlength=200, help_text=INTERVAL_HELP_TEXT);
+ shrt = models.CharField(maxlength=200, help_text=INTERVAL_HELP_TEXT);
+ max_renewals = models.IntegerField()
+ class Admin:
+ search_fields = ['name']
+ list_display = ('name','extended','normal','shrt','max_renewals')
+ class Meta:
+ db_table = 'rule_circ_duration'
+ ordering = ['name']
+ verbose_name = 'Circ Duration Rule'
+ def __str__(self):
+ return self.name
class RuleMaxFine(models.Model):
- name = models.CharField(maxlength=200)
- amount = models.FloatField(max_digits=6, decimal_places=2)
- class Admin:
- search_fields = ['name']
- list_display = ('name','amount')
- class Meta:
- db_table = 'rule_max_fine'
- ordering = ['name']
- verbose_name = 'Circ Max Fine Rule'
- def __str__(self):
- return self.name
+ name = models.CharField(maxlength=200)
+ amount = models.FloatField(max_digits=6, decimal_places=2)
+ class Admin:
+ search_fields = ['name']
+ list_display = ('name','amount')
+ class Meta:
+ db_table = 'rule_max_fine'
+ ordering = ['name']
+ verbose_name = 'Circ Max Fine Rule'
+ def __str__(self):
+ return self.name
class RuleRecurringFine(models.Model):
- name = models.CharField(maxlength=200)
- high = models.FloatField(max_digits=6, decimal_places=2)
- normal = models.FloatField(max_digits=6, decimal_places=2)
- low = models.FloatField(max_digits=6, decimal_places=2)
- class Admin:
- search_fields = ['name']
- list_display = ('name','high', 'normal', 'low')
- class Meta:
- db_table = 'rule_recuring_fine'
- ordering = ['name']
- verbose_name = 'Circ Recurring Fine Rule'
- def __str__(self):
- return self.name
+ name = models.CharField(maxlength=200)
+ high = models.FloatField(max_digits=6, decimal_places=2)
+ normal = models.FloatField(max_digits=6, decimal_places=2)
+ low = models.FloatField(max_digits=6, decimal_places=2)
+ class Admin:
+ search_fields = ['name']
+ list_display = ('name','high', 'normal', 'low')
+ class Meta:
+ db_table = 'rule_recuring_fine'
+ ordering = ['name']
+ verbose_name = 'Circ Recurring Fine Rule'
+ def __str__(self):
+ return self.name
class IdentificationType(models.Model):
- name = models.CharField(maxlength=200)
- class Admin:
- search_fields = ['name']
- class Meta:
- db_table = 'identification_type'
- ordering = ['name']
- verbose_name = 'Identification Type'
- def __str__(self):
- return self.name
+ name = models.CharField(maxlength=200)
+ class Admin:
+ search_fields = ['name']
+ class Meta:
+ db_table = 'identification_type'
+ ordering = ['name']
+ verbose_name = 'Identification Type'
+ def __str__(self):
+ return self.name
class RuleAgeHoldProtect(models.Model):
- name = models.CharField(maxlength=200)
- age = models.CharField(blank=True, maxlength=100, help_text=INTERVAL_HELP_TEXT)
- prox = models.IntegerField()
- class Admin:
- search_fields = ['name']
- class Meta:
- db_table = 'rule_age_hold_protect'
- ordering = ['name']
- verbose_name = 'Hold Age Protection Rule'
- def __str__(self):
- return self.name
+ name = models.CharField(maxlength=200)
+ age = models.CharField(blank=True, maxlength=100, help_text=INTERVAL_HELP_TEXT)
+ prox = models.IntegerField()
+ class Admin:
+ search_fields = ['name']
+ class Meta:
+ db_table = 'rule_age_hold_protect'
+ ordering = ['name']
+ verbose_name = 'Hold Age Protection Rule'
+ def __str__(self):
+ return self.name
+
+class MetabibField(models.Model):
+ field_class_choices = (
+ ('title', 'Title'),
+ ('author', 'Author'),
+ ('subject', 'Subject'),
+ ('series', 'Series'),
+ ('keyword', 'Keyword'),
+ )
+ field_class = models.CharField(maxlength=200, choices=field_class_choices, null=False, blank=False)
+ name = models.CharField(maxlength=200, null=False, blank=False)
+ xpath = models.TextField(null=False, blank=False)
+ weight = models.IntegerField(null=False, blank=False)
+ format = models.CharField(maxlength=200, null=False, blank=False)
+ class Admin:
+ search_fields = ['name', 'format', 'field_class']
+ list_display = ('field_class', 'name', 'format')
+ class Meta:
+ db_table = 'metabib_field'
+ ordering = ['field_class', 'name']
+ verbose_name = 'Metabib Field'
+ def __str__(self):
+ return self.name
+
--- /dev/null
+# :vim set syntax apache
+
+LogLevel debug
+# - log locally
+CustomLog /var/log/apache2/access.log combined
+ErrorLog /var/log/apache2/error.log
+# - log to syslog
+# CustomLog "|/usr/bin/logger -p local7.info" common
+# ErrorLog syslog:local7
+
+
+# ----------------------------------------------------------------------------------
+# Set up Perl
+# ----------------------------------------------------------------------------------
+
+# - needed by CGIs
+SetEnv PERL5LIB /openils/lib/perl5
+PerlRequire /etc/apache2/startup.pl
+PerlChildInitHandler OpenILS::WWW::Reporter::child_init
+PerlChildInitHandler OpenILS::WWW::SuperCat::child_init
+PerlChildInitHandler OpenILS::WWW::AddedContent::child_init;
+
+
+# ----------------------------------------------------------------------------------
+# Set some defaults for our working directories
+# ----------------------------------------------------------------------------------
+<Directory /openils/var/web>
+ Order allow,deny
+ Allow from all
+</Directory>
+
+
+# ----------------------------------------------------------------------------------
+# XUL directory
+# ----------------------------------------------------------------------------------
+<Directory /openils/var/web/xul>
+ Options Indexes FollowSymLinks
+ AllowOverride None
+ Order allow,deny
+ Allow from all
+</Directory>
+
+
+# ----------------------------------------------------------------------------------
+# Remove the language portion from the URL
+# ----------------------------------------------------------------------------------
+AliasMatch ^/opac/.*/skin/(.*)/(.*)/(.*) /openils/var/web/opac/skin/$1/$2/$3
+
+
+# ----------------------------------------------------------------------------------
+# System config CGI scripts go here
+# ----------------------------------------------------------------------------------
+Alias /cgi-bin/ "/openils/var/cgi-bin/"
+<Directory "/openils/var/cgi-bin">
+ AddHandler cgi-script .cgi .pl
+ AllowOverride None
+ Options None
+ Order deny,allow
+ Deny from all
+ Allow from 10.0.0.0/8
+ Options FollowSymLinks ExecCGI Indexes
+</Directory>
+
+
+
+# ----------------------------------------------------------------------------------
+# OPTIONAL: Set up image caching - some of these options only work with apache2.2
+# ----------------------------------------------------------------------------------
+CacheRoot "/opt/cache/"
+CacheEnable disk /opac/extras/jacket/
+CacheMaxFileSize 1073741824
+CacheIgnoreCacheControl On
+CacheStorePrivate On
+CacheStoreNoStore On
+CacheIgnoreNoLastMod On
+CacheMaxExpire 86400
+CacheLastModifiedFactor 0.5
+CacheDefaultExpire 604800
+
+
+# ----------------------------------------------------------------------------------
+# OPTIONAL: Set how long the client will cache our content. Change to suit
+# ----------------------------------------------------------------------------------
+ExpiresActive On
+ExpiresDefault A2592000
+ExpiresByType text/html A64800
+ExpiresByType application/xhtml+xml A64800
+ExpiresByType application/x-javascript A64800
+ExpiresByType text/css A3000
+
+
+
+
+# ----------------------------------------------------------------------------------
+# Set up our main virtual host
+# ----------------------------------------------------------------------------------
+NameVirtualHost *:80
+<VirtualHost *:80>
+ ServerName localhost:80
+ ServerAlias 127.0.0.1:80
+ DocumentRoot /openils/var/web/
+ DirectoryIndex index.xml index.html
+ # - absorb the shared virtual host settings
+ Include eg_vhost.conf
+</VirtualHost>
+
+
+
+
+
+# ----------------------------------------------------------------------------------
+# Set up our SSL virtual host
+# ----------------------------------------------------------------------------------
+Listen 443
+NameVirtualHost *:443
+<VirtualHost *:443>
+ DocumentRoot "/openils/var/web"
+ ServerName localhost:443
+ ServerAlias 127.0.0.1:443
+ SSLEngine on
+ SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
+
+ # If you don't have an SSL cert, you can create self-signed
+ # certificate and key with:
+ # openssl req -new -x509 -nodes -out server.crt -keyout server.key
+ SSLCertificateFile ssl/server.crt
+ SSLCertificateKeyFile ssl/server.key
+
+ # - absorb the shared virtual host settings
+ Include eg_vhost.conf
+
+ # help IE along with SSL pages
+ BrowserMatch ".*MSIE.*" \
+ nokeepalive ssl-unclean-shutdown \
+ downgrade-1.0 force-response-1.0
+
+</VirtualHost>
+
+
--- /dev/null
+# ----------------------------------------------------------------------------------
+# This is the global Evergreen virtual host config. Anything you want published
+# through all virtual hosts (port 80, port 443, etc.) should live in here.
+# ----------------------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------------------
+# Point / to the opac
+# ----------------------------------------------------------------------------------
+RedirectMatch 301 ^/$ /opac/en-US/skin/default/xml/index.xml
+
+
+# ----------------------------------------------------------------------------------
+# Configure the gateway
+# ----------------------------------------------------------------------------------
+OSRFGatewayConfig /openils/conf/opensrf_core.xml
+
+
+# ----------------------------------------------------------------------------------
+# Set up the book jackets URL
+# XXX This pulls images from Amazon, don't use this in a production environment
+# ----------------------------------------------------------------------------------
+RewriteEngine on
+ProxyTimeout 2
+RewriteRule /opac/extras/jacket/small/(.*) \
+ http://images.amazon.com/images/P/$1.01._SCMZZZZZZZ_.jpg [P,L]
+RewriteRule /opac/extras/jacket/large/(.*) \
+ http://images.amazon.com/images/P/$1.01._SCLZZZZZZZ_.jpg [P,L]
+
+
+
+# ----------------------------------------------------------------------------------
+# Added content plugin
+# ----------------------------------------------------------------------------------
+<Location /opac/extras/ac/>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::AddedContent
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+
+
+# ----------------------------------------------------------------------------------
+# Configure the OPAC
+# ----------------------------------------------------------------------------------
+<LocationMatch /opac/>
+ AddType application/xhtml+xml .xml
+
+ # - configure mod_xmlent
+ XMLEntStripPI "yes"
+ XMLEntEscapeScript "no"
+ XMLEntStripComments "yes"
+ XMLEntContentType "text/html; charset=utf-8"
+ # forces quirks mode which we want for now
+ XMLEntStripDoctype "yes"
+
+ # - set up the include handlers
+ Options +Includes
+ AddOutputFilter INCLUDES .xsl
+ AddOutputFilter INCLUDES;XMLENT .xml
+
+ # add languages as necessary
+ SetEnvIf Request_URI "/en-US/" locale=en-US
+ SetEnvIf Request_URI "/fr/" locale=fr
+ SetEnvIf Request_URI ".*" OILS_OPAC_BASE=/opac/
+</LocationMatch>
+
+
+# ----------------------------------------------------------------------------------
+# Force SSL on the OPAC's "My Account" page
+# ----------------------------------------------------------------------------------
+<LocationMatch .*/myopac.xml>
+ SSLRequireSSL
+</LocationMatch>
+
+<LocationMatch /opac/extras/>
+ AddType application/xhtml+xml .xml
+</LocationMatch>
+
+<LocationMatch /opac/extras/slimpac/>
+ AddOutputFilter INCLUDES .html
+</LocationMatch>
+
+# ----------------------------------------------------------------------------------
+# Run server-side XUL through xmlent to load the correct XML entities
+# ----------------------------------------------------------------------------------
+<LocationMatch /xul/.*\.xul$>
+ Options +Includes
+ XMLEntContentType "application/vnd.mozilla.xul+xml"
+ AddOutputFilter INCLUDES;XMLENT .xul
+ allow from all
+</LocationMatch>
+
+# ----------------------------------------------------------------------------------
+# Supercat feeds
+# ----------------------------------------------------------------------------------
+<Location /opac/extras/oisbn>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::SuperCat::oisbn
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+<Location /opac/extras/supercat>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::SuperCat::supercat
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+<Location /opac/extras/unapi>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::SuperCat::unapi
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+<Location /opac/extras/feed/bookbag>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::SuperCat::bookbag_feed
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+<Location /opac/extras/opensearch>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::SuperCat::opensearch_feed
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+<Location /opac/extras/feed/freshmeat>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::SuperCat::changes_feed
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+<Location /opac/extras/browse>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::SuperCat::string_browse
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+
+# ----------------------------------------------------------------------------------
+# Module for processing staff-client offline scripts lives here
+# ----------------------------------------------------------------------------------
+<Directory "/openils/var/cgi-bin/offline">
+ AddHandler cgi-script .pl
+ AllowOverride None
+ Options +ExecCGI
+ allow from all
+</Directory>
+
+
+# ----------------------------------------------------------------------------------
+# OpenSRF JSON gateway
+# ----------------------------------------------------------------------------------
+<Location /gateway>
+ SetHandler osrf_json_gateway_module
+ allow from all
+</Location>
+
+
+# ----------------------------------------------------------------------------------
+# Reporting output lives here
+# ----------------------------------------------------------------------------------
+<Location /reporter/>
+ SetHandler perl-script
+ PerlHandler OpenILS::Reporter::Proxy
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+
+# ----------------------------------------------------------------------------------
+# Reports GUI
+# ----------------------------------------------------------------------------------
+<LocationMatch /reports/>
+ Options +Includes
+ AddOutputFilter INCLUDES .xhtml
+</LocationMatch>
+
+# ----------------------------------------------------------------------------------
+# XML-RPC gateway
+# ----------------------------------------------------------------------------------
+<Location /xml-rpc>
+ SetHandler perl-script
+ PerlHandler OpenILS::WWW::XMLRPCGateway
+ Options +ExecCGI
+ PerlSendHeader On
+ allow from all
+</Location>
+
+
+# ----------------------------------------------------------------------------------
+# Django admin interface (experimental)
+# - requires mod_python and django
+# - requires a symlink from WEBROOT/media to
+# /usr/lib/python2.4/site-packages/django/contrib/admin/media/ (or similar)
+# ----------------------------------------------------------------------------------
+#<Location /ils_setup/>
+# Order deny,allow
+# Deny from all
+# Allow from 10.0.0.0/8
+# SetHandler mod_python
+# PythonHandler django.core.handlers.modpython
+# SetEnv DJANGO_SETTINGS_MODULE ils_admin.settings
+# PythonDebug On
+# PythonPath "['/openils/var/admin/', '/usr/lib/python2.4/site-packages/'] +sys.path"
+# PythonAutoReload On
+#</Location>
+
+
--- /dev/null
+#!/usr/bin/perl
+use lib qw( /openils/lib/perl5 );
+use OpenILS::WWW::SuperCat qw( /openils/conf/bootstrap.conf );
+use OpenILS::WWW::AddedContent qw( /openils/conf/bootstrap.conf );
+use OpenILS::Reporter::Proxy ('/openils/conf/bootstrap.conf');
+
+
+
+1;
+
<field reporter:label="Transaction Payments" name="payments" oils_obj:array_position="28" oils_persist:virtual="true" />
<field reporter:label="Base Transaction" name="billable_transaction" oils_obj:array_position="29" oils_persist:virtual="true" />
<field reporter:label="Circulation Type" name="circ_type" oils_obj:array_position="30" oils_persist:virtual="true" />
+ <field reporter:label="Billing Totals" name="billing_total" oils_obj:array_position="31" oils_persist:virtual="true" />
+ <field reporter:label="Payment Totals" name="payment_total" oils_obj:array_position="32" oils_persist:virtual="true" />
</fields>
<links>
<link field="billable_transaction" reltype="might_have" key="id" map="" class="mbt"/>
<link field="max_fine_rule" reltype="has_a" key="name" map="" class="crmf"/>
<link field="recuring_fine_rule" reltype="has_a" key="name" map="" class="crrf"/>
<link field="circ_type" reltype="might_have" key="id" map="" class="rcirct"/>
+ <link field="billing_total" reltype="might_have" key="xact" map="" class="rxbt"/>
+ <link field="payment_total" reltype="might_have" key="xact" map="" class="rxpt"/>
</links>
</class>
<class id="ccnbi" controller="open-ils.cstore" oils_obj:fieldmapper="container::call_number_bucket_item" oils_persist:tablename="container.call_number_bucket_item">
<field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
<field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
<field name="status" oils_obj:array_position="3" oils_persist:virtual="true" />
- <field name="transit" oils_obj:array_position="4" oils_persist:virtual="true" />
+ <field reporter:label="Transit" name="transit" oils_obj:array_position="4" oils_persist:virtual="true" />
<field reporter:label="Capture Date/Time" name="capture_time" oils_obj:array_position="5" oils_persist:virtual="false" reporter:datatype="timestamp"/>
<field reporter:label="Currently Targeted Copy" name="current_copy" oils_obj:array_position="6" oils_persist:virtual="false" />
<field reporter:label="Notify by Email?" name="email_notify" oils_obj:array_position="7" oils_persist:virtual="false" reporter:datatype="bool"/>
<field reporter:label="Notifications Phone Number" name="phone_notify" oils_obj:array_position="15" oils_persist:virtual="false" />
<field reporter:label="Pickup Library" name="pickup_lib" oils_obj:array_position="16" oils_persist:virtual="false" />
<field reporter:label="Last Targeting Date/Time" name="prev_check_time" oils_obj:array_position="17" oils_persist:virtual="false" reporter:datatype="timestamp"/>
- <field name="request_lib" oils_obj:array_position="18" oils_persist:virtual="false" />
+ <field reporter:label="Requesting Library" name="request_lib" oils_obj:array_position="18" oils_persist:virtual="false" />
<field reporter:label="Request Date/Time" name="request_time" oils_obj:array_position="19" oils_persist:virtual="false" reporter:datatype="timestamp"/>
<field reporter:label="Requesting User" name="requestor" oils_obj:array_position="20" oils_persist:virtual="false" />
<field reporter:label="Item Selection Depth" name="selection_depth" oils_obj:array_position="21" oils_persist:virtual="false" />
<field reporter:label="Selection Locus" name="selection_ou" oils_obj:array_position="22" oils_persist:virtual="false" />
- <field name="target" oils_obj:array_position="23" oils_persist:virtual="false" />
- <field name="usr" oils_obj:array_position="24" oils_persist:virtual="false" />
+ <field reporter:label="Target Object ID" name="target" oils_obj:array_position="23" oils_persist:virtual="false" />
+ <field reporter:label="Hold User" name="usr" oils_obj:array_position="24" oils_persist:virtual="false" />
<field reporter:label="Hold Cancel Date/Time" name="cancel_time" oils_obj:array_position="25" oils_persist:virtual="false" reporter:datatype="timestamp"/>
<field name="notify_time" oils_obj:array_position="26" oils_persist:virtual="true" reporter:datatype="timestamp"/>
<field name="notify_count" oils_obj:array_position="27" oils_persist:virtual="true" reporter:datatype="int" />
- <field name="notifications" oils_obj:array_position="28" oils_persist:virtual="true" />
+ <field reporter:label="Notifications" name="notifications" oils_obj:array_position="28" oils_persist:virtual="true" />
+ <field reporter:label="Bib Record Link" name="bib_rec" oils_obj:array_position="29" oils_persist:virtual="true"/>
+ <field reporter:label="Eligible Copies" name="eligible_copies" oils_obj:array_position="30" oils_persist:virtual="true" />
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
<link field="selection_ou" reltype="has_a" key="id" map="" class="aou"/>
<link field="requestor" reltype="has_a" key="id" map="" class="au"/>
<link field="current_copy" reltype="has_a" key="id" map="" class="acp"/>
- <link reporter:label="Hold User" field="usr" reltype="has_a" key="id" map="" class="au"/>
- <link reporter:label="Requesting Library" field="request_lib" reltype="has_a" key="id" map="" class="aou"/>
- <link reporter:label="Transit" field="transit" reltype="might_have" key="hold" map="" class="ahtc"/>
- <link reporter:label="Notifications" field="notifications" reltype="has_many" key="hold" map="" class="ahn"/>
- <link reporter:label="Eligible Copies" field="eligible_copies" reltype="has_many" key="hold" map="target_copy" class="ahcm"/>
+ <link field="usr" reltype="has_a" key="id" map="" class="au"/>
+ <link field="request_lib" reltype="has_a" key="id" map="" class="aou"/>
+ <link field="transit" reltype="might_have" key="hold" map="" class="ahtc"/>
+ <link field="notifications" reltype="has_many" key="hold" map="" class="ahn"/>
+ <link field="eligible_copies" reltype="has_many" key="hold" map="target_copy" class="ahcm"/>
+ <link field="bib_rec" reltype="might_have" key="id" map="" class="rhrr"/>
</links>
</class>
<class id="aou" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_unit" oils_persist:tablename="actor.org_unit" reporter:label="Organizational Unit">
<field reporter:label="Short (Policy) Name" name="shortname" oils_obj:array_position="12" oils_persist:virtual="false" />
<field reporter:label="EMail Address" name="email" oils_obj:array_position="13" oils_persist:virtual="false" />
<field reporter:label="Phone Number" name="phone" oils_obj:array_position="14" oils_persist:virtual="false" />
+ <field reporter:label="OPAC Visible" name="opac_visible" oils_obj:array_position="15" oils_persist:virtual="false" reporter:datatype="bool"/>
</fields>
<links>
<link field="billing_address" reltype="has_a" key="id" map="" class="aoa"/>
<field name="billings" oils_obj:array_position="9" oils_persist:virtual="true" />
<field name="payments" oils_obj:array_position="10" oils_persist:virtual="true" />
<field name="billable_transaction" oils_obj:array_position="11" oils_persist:virtual="true" />
+ <field reporter:label="Billing Totals" name="billing_total" oils_obj:array_position="12" oils_persist:virtual="true" />
+ <field reporter:label="Payment Totals" name="payment_total" oils_obj:array_position="13" oils_persist:virtual="true" />
</fields>
<links>
<link field="usr" reltype="has_a" key="id" map="" class="au"/>
<link field="payments" reltype="has_many" key="xact" map="" class="mp"/>
<link field="billings" reltype="has_many" key="xact" map="" class="mb"/>
<link field="billing_location" reltype="has_a" key="id" map="" class="aou"/>
+ <link field="billing_total" reltype="might_have" key="xact" map="" class="rxbt"/>
+ <link field="payment_total" reltype="might_have" key="xact" map="" class="rxpt"/>
</links>
</class>
<class id="cbs" controller="open-ils.cstore" oils_obj:fieldmapper="config::bib_source" oils_persist:tablename="config.bib_source">
<field name="grocery" oils_obj:array_position="7" oils_persist:virtual="true" />
<field name="circulation" oils_obj:array_position="8" oils_persist:virtual="true" />
<field reporter:label="Billing Line Items" name="billings" oils_obj:array_position="9" oils_persist:virtual="true" />
- <field reporter:label="Payments" name="payments" oils_obj:array_position="10" oils_persist:virtual="true" />
+ <field reporter:label="Payment Line Items" name="payments" oils_obj:array_position="10" oils_persist:virtual="true" />
+ <field reporter:label="Billing Totals" name="billing_total" oils_obj:array_position="11" oils_persist:virtual="true" />
+ <field reporter:label="Payment Totals" name="payment_total" oils_obj:array_position="12" oils_persist:virtual="true" />
</fields>
<links>
<link field="grocery" reltype="might_have" key="id" map="" class="mg"/>
<link field="usr" reltype="has_a" key="id" map="" class="au"/>
<link field="payments" reltype="has_many" key="xact" map="" class="mp"/>
<link field="billings" reltype="has_many" key="xact" map="" class="mb"/>
+ <link field="billing_total" reltype="might_have" key="xact" map="" class="rxbt"/>
+ <link field="payment_total" reltype="might_have" key="xact" map="" class="rxpt"/>
</links>
</class>
<class id="actsce" controller="open-ils.cstore" oils_obj:fieldmapper="actor::stat_cat_entry" oils_persist:tablename="actor.stat_cat_entry" reporter:label="User Stat Cat Entry">
<link field="perm" reltype="has_a" key="id" map="" class="ppl"/>
</links>
</class>
- <class id="mp" controller="open-ils.cstore" oils_obj:fieldmapper="money::payment" oils_persist:tablename="money.payment_view">
+ <class id="mp" controller="open-ils.cstore" oils_obj:fieldmapper="money::payment" oils_persist:tablename="money.payment_view" reporter:core="true" reporter:label="Payments: All">
<fields oils_persist:primary="id" oils_persist:sequence="">
<field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
<field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
<field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
- <field name="amount" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="money" />
- <field name="id" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
- <field name="note" oils_obj:array_position="5" oils_persist:virtual="false" />
- <field name="payment_ts" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="timestamp"/>
- <field name="payment_type" oils_obj:array_position="7" oils_persist:virtual="false" />
- <field name="xact" oils_obj:array_position="8" oils_persist:virtual="false" />
- <field name="voided" oils_obj:array_position="9" oils_persist:virtual="false" reporter:datatype="bool"/>
- <field name="cash_payment" oils_obj:array_position="10" oils_persist:virtual="true" />
- <field name="credit_card_payment" oils_obj:array_position="11" oils_persist:virtual="true" />
- <field name="credit_payment" oils_obj:array_position="12" oils_persist:virtual="true" />
- <field name="check_payment" oils_obj:array_position="13" oils_persist:virtual="true" />
- <field name="work_payment" oils_obj:array_position="14" oils_persist:virtual="true" />
- <field name="forgive_payment" oils_obj:array_position="15" oils_persist:virtual="true" />
+ <field reporter:label="Amount" name="amount" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="money" />
+ <field reporter:label="Payment ID" name="id" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Note" name="note" oils_obj:array_position="5" oils_persist:virtual="false" />
+ <field reporter:label="Payment Date/Time" name="payment_ts" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="timestamp"/>
+ <field reporter:label="Payment Type" name="payment_type" oils_obj:array_position="7" oils_persist:virtual="false" />
+ <field reporter:label="Billable Transaction" name="xact" oils_obj:array_position="8" oils_persist:virtual="false" />
+ <field reporter:label="Voided?" name="voided" oils_obj:array_position="9" oils_persist:virtual="false" reporter:datatype="bool"/>
+ <field reporter:label="Cash Payment Detail" name="cash_payment" oils_obj:array_position="10" oils_persist:virtual="true" />
+ <field reporter:label="Credit Card Payment Detail" name="credit_card_payment" oils_obj:array_position="11" oils_persist:virtual="true" />
+ <field reporter:label="Credit Payment Detail" name="credit_payment" oils_obj:array_position="12" oils_persist:virtual="true" />
+ <field reporter:label="Check Payment Detail" name="check_payment" oils_obj:array_position="13" oils_persist:virtual="true" />
+ <field reporter:label="Work Payment Detail" name="work_payment" oils_obj:array_position="14" oils_persist:virtual="true" />
+ <field reporter:label="Forgive Payment Detail" name="forgive_payment" oils_obj:array_position="15" oils_persist:virtual="true" />
</fields>
<links>
<link field="cash_payment" reltype="might_have" key="id" map="" class="mcp"/>
<link field="xact" reltype="has_a" key="id" map="" class="mbt"/>
</links>
</class>
- <class id="mdp" controller="open-ils.cstore" oils_obj:fieldmapper="money::desk_payment" oils_persist:tablename="money.desk_payment_view">
+ <class id="mbp" controller="open-ils.cstore" oils_obj:fieldmapper="money::bnm_payment" oils_persist:tablename="money.bnm_payment_view" reporter:core="true" reporter:label="Payments: Brick-and-mortar">
<fields oils_persist:primary="id" oils_persist:sequence="">
<field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
<field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
<field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
- <field name="amount" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="money" />
- <field name="id" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
- <field name="note" oils_obj:array_position="5" oils_persist:virtual="false" />
- <field name="payment_ts" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="timestamp"/>
- <field name="payment_type" oils_obj:array_position="7" oils_persist:virtual="false" />
- <field name="xact" oils_obj:array_position="8" oils_persist:virtual="false" />
- <field name="accepting_usr" oils_obj:array_position="9" oils_persist:virtual="false" />
- <field name="cash_drawer" oils_obj:array_position="10" oils_persist:virtual="false" />
- <field name="voided" oils_obj:array_position="11" oils_persist:virtual="false" reporter:datatype="bool"/>
- <field name="cash_payment" oils_obj:array_position="12" oils_persist:virtual="true" />
- <field name="credit_card_payment" oils_obj:array_position="13" oils_persist:virtual="true" />
- <field name="check_payment" oils_obj:array_position="14" oils_persist:virtual="true" />
+ <field reporter:label="Amount" name="amount" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="money" />
+ <field reporter:label="Payment ID" name="id" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Note" name="note" oils_obj:array_position="5" oils_persist:virtual="false" />
+ <field reporter:label="Payment Date/Time" name="payment_ts" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="timestamp"/>
+ <field reporter:label="Payment Type" name="payment_type" oils_obj:array_position="7" oils_persist:virtual="false" />
+ <field reporter:label="Billable Transaction" name="xact" oils_obj:array_position="8" oils_persist:virtual="false" />
+ <field reporter:label="Voided?" name="voided" oils_obj:array_position="9" oils_persist:virtual="false" reporter:datatype="bool"/>
+ <field reporter:label="Cash Payment Detail" name="cash_payment" oils_obj:array_position="10" oils_persist:virtual="true" />
+ <field reporter:label="Credit Card Payment Detail" name="credit_card_payment" oils_obj:array_position="11" oils_persist:virtual="true" />
+ <field reporter:label="Credit Payment Detail" name="credit_payment" oils_obj:array_position="12" oils_persist:virtual="true" />
+ <field reporter:label="Check Payment Detail" name="check_payment" oils_obj:array_position="13" oils_persist:virtual="true" />
+ <field reporter:label="Work Payment Detail" name="work_payment" oils_obj:array_position="14" oils_persist:virtual="true" />
+ <field reporter:label="Forgive Payment Detail" name="forgive_payment" oils_obj:array_position="15" oils_persist:virtual="true" />
+ </fields>
+ <links>
+ <link field="cash_payment" reltype="might_have" key="id" map="" class="mcp"/>
+ <link field="credit_card_payment" reltype="might_have" key="id" map="" class="mccp"/>
+ <link field="credit_payment" reltype="might_have" key="id" map="" class="mcrp"/>
+ <link field="check_payment" reltype="might_have" key="id" map="" class="mckp"/>
+ <link field="work_payment" reltype="might_have" key="id" map="" class="mwp"/>
+ <link field="forgive_payment" reltype="might_have" key="id" map="" class="mfp"/>
+ <link field="xact" reltype="has_a" key="id" map="" class="mbt"/>
+ </links>
+ </class>
+ <class id="mndp" controller="open-ils.reporter" oils_obj:fieldmapper="money::non_drawer_payment" oils_persist:tablename="money.non_drawer_payment_view" reporter:core="true" reporter:label="Payments: Non-drawer Staff">
+ <fields oils_persist:primary="id" oils_persist:sequence="">
+ <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+ <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+ <field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+ <field reporter:label="Amount" name="amount" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="money" />
+ <field reporter:label="Payment ID" name="id" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Note" name="note" oils_obj:array_position="5" oils_persist:virtual="false" />
+ <field reporter:label="Payment Date/Time" name="payment_ts" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="timestamp"/>
+ <field reporter:label="Payment Type" name="payment_type" oils_obj:array_position="7" oils_persist:virtual="false" />
+ <field reporter:label="Billable Transaction" name="xact" oils_obj:array_position="8" oils_persist:virtual="false" />
+ <field reporter:label="Voided?" name="voided" oils_obj:array_position="9" oils_persist:virtual="false" reporter:datatype="bool"/>
+ <field reporter:label="Work Payment Detail" name="work_payment" oils_obj:array_position="10" oils_persist:virtual="true" />
+ <field reporter:label="Forgive Payment Detail" name="forgive_payment" oils_obj:array_position="11" oils_persist:virtual="true" />
+ </fields>
+ <links>
+ <link field="work_payment" reltype="might_have" key="id" map="" class="mwp"/>
+ <link field="forgive_payment" reltype="might_have" key="id" map="" class="mfp"/>
+ <link field="xact" reltype="has_a" key="id" map="" class="mbt"/>
+ </links>
+ </class>
+ <class id="mdp" controller="open-ils.cstore" oils_obj:fieldmapper="money::desk_payment" oils_persist:tablename="money.desk_payment_view" reporter:core="true" reporter:label="Payments: Desk">
+ <fields oils_persist:primary="id" oils_persist:sequence="">
+ <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+ <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+ <field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+ <field reporter:label="Amount" name="amount" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="money" />
+ <field reporter:label="Payment ID" name="id" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Note" name="note" oils_obj:array_position="5" oils_persist:virtual="false" />
+ <field reporter:label="Payment Date/Time" name="payment_ts" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="timestamp"/>
+ <field reporter:label="Payment Type" name="payment_type" oils_obj:array_position="7" oils_persist:virtual="false" />
+ <field reporter:label="Billable Transaction" name="xact" oils_obj:array_position="8" oils_persist:virtual="false" />
+ <field reporter:label="Accepting User" name="accepting_usr" oils_obj:array_position="9" oils_persist:virtual="false" />
+ <field reporter:label="Cash Drawer" name="cash_drawer" oils_obj:array_position="10" oils_persist:virtual="false" />
+ <field reporter:label="Voided?" name="voided" oils_obj:array_position="11" oils_persist:virtual="false" reporter:datatype="bool"/>
+ <field reporter:label="Cash Payment" name="cash_payment" oils_obj:array_position="12" oils_persist:virtual="true" />
+ <field reporter:label="Credit Card Payment" name="credit_card_payment" oils_obj:array_position="13" oils_persist:virtual="true" />
+ <field reporter:label="Check Payment" name="check_payment" oils_obj:array_position="14" oils_persist:virtual="true" />
</fields>
<links>
<link field="cash_payment" reltype="might_have" key="id" map="" class="mcp"/>
<link field="id" reltype="might_have" key="id" map="" class="circ"/>
</links>
</class>
+ <class id="rhrr" controller="open-ils.reporter-store" oils_obj:fieldmapper="reporter::hold_request_record" oils_persist:tablename="reporter.hold_request_record">
+ <fields oils_persist:primary="id">
+ <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+ <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+ <field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+ <field reporter:label="Hold ID" name="id" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Hold Target" name="target" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Hold Request Type" name="hold_type" oils_obj:array_position="5" oils_persist:virtual="false"/>
+ <field reporter:label="Target Bib Record" name="bib_record" oils_obj:array_position="6" oils_persist:virtual="false"/>
+ </fields>
+ <links>
+ <link field="id" reltype="might_have" key="id" map="" class="ahr"/>
+ <link field="bib_record" reltype="has_a" key="id" map="" class="bre"/>
+ </links>
+ </class>
+ <class id="rxbt" controller="open-ils.reporter-store" oils_obj:fieldmapper="reporter::xact_billing_totals" oils_persist:tablename="reporter.xact_billing_totals">
+ <fields oils_persist:primary="xact">
+ <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+ <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+ <field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+ <field reporter:label="Transaction ID" name="xact" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Unvoided Billing Amount" name="unvoided" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Voided Billing Amount" name="voided" oils_obj:array_position="5" oils_persist:virtual="false"/>
+ <field reporter:label="Total Billing Amount" name="total" oils_obj:array_position="6" oils_persist:virtual="false"/>
+ </fields>
+ <links>
+ <link field="xact" reltype="might_have" key="id" map="" class="mbt"/>
+ </links>
+ </class>
+ <class id="rxpt" controller="open-ils.reporter-store" oils_obj:fieldmapper="reporter::xact_paid_totals" oils_persist:tablename="reporter.xact_paid_totals">
+ <fields oils_persist:primary="xact">
+ <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+ <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+ <field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+ <field reporter:label="Transaction ID" name="xact" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Unvoided Paid Amount" name="unvoided" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int" />
+ <field reporter:label="Voided (Returned) Paid Amount" name="voided" oils_obj:array_position="5" oils_persist:virtual="false"/>
+ <field reporter:label="Total Paid Amount" name="total" oils_obj:array_position="6" oils_persist:virtual="false"/>
+ </fields>
+ <links>
+ <link field="xact" reltype="might_have" key="id" map="" class="mbt"/>
+ </links>
+ </class>
</IDL>
<!--
Example opensrf config file for OpenILS
-See opensrf.xml.example for core config documentation
-For non-core config info, see the inline documentation within this file
-->
-<opensrf version='0.0.1'>
-
-
- <default>
-
- <dirs>
- <log>/openils/var/log</log>
- <sock>/openils/var/sock</sock>
- <pid>/openils/var/pid</pid>
-
- <!-- xsl stylesheets go here -->
- <xsl>/openils/var/xsl</xsl>
- <conf>/openils/var/conf</conf>
- <script>/openils/var/data</script>
- <script_lib>/openils/var/data</script_lib>
- </dirs>
-
- <server_type>prefork</server_type>
-
- <!-- script for exception strings -->
- <ils_events>/openils/var/data/ils_events.xml</ils_events>
-
- <z3950>
- <default>oclc</default>
- <services>
- <oclc> <!-- service name -->
-
- <!-- connection info -->
- <host>zcat.oclc.org</host>
- <port>210</port>
- <db>OLUCWorldCat</db>
-
- <!-- search attributes -->
- <attrs>
- <tcn>
- <code>12</code> <!-- attribute code -->
- <format>6</format> <!-- search term format (word, date, etc.) -->
- </tcn>
- <isbn>
- <code>7</code>
- <format>6</format>
- </isbn>
- <lccn>
- <code>9</code>
- <format>3</format>
- </lccn>
- <author>
- <code>1003</code>
- <format>6</format>
- </author>
- <title>
- <code>4</code>
- <format>6</format>
- </title>
- <issn>
- <code>8</code>
- <format>1</format>
- </issn>
- <publisher>
- <code>1018</code>
- <format>6</format>
- </publisher>
- <pubdate>
- <code>31</code>
- <format>5</format>
- </pubdate>
- <item_type>
- <code>1001</code>
- <format>1</format>
- </item_type>
- <!--music/publisher numbers?? -->
- </attrs>
- </oclc>
-
- <loc>
- <name>loc</name>
- <host>z3950.loc.gov</host>
- <port>7090</port>
- <db>Voyager</db>
- <attrs>
- <isbn>
- <code>7</code>
- <format>1</format>
- </isbn>
- </attrs>
- </loc>
- </services>
- </z3950>
-
-
- <activeapps/>
-
- <cache>
- <global>
- <servers>
- <server>127.0.0.1:10101</server>
- </servers>
- <max_cache_time>86400</max_cache_time>
- </global>
- </cache>
-
- <apps>
-
- <opensrf.persist>
- <keepalive>1</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenSRF::Application::Persist</implementation>
- <max_requests>97</max_requests>
- <unix_config>
- <unix_sock>opensrf.persist_unix.sock</unix_sock>
- <unix_pid>opensrf.persist_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <unix_log>opensrf.persist_unix.log</unix_log>
- <min_children>5</min_children>
- <max_children>25</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
-
- <app_settings>
- <dbfile>/openils/var/db/persist.db</dbfile>
- </app_settings>
-
- </opensrf.persist>
-
- <!-- Authentication server -->
- <open-ils.auth>
- <keepalive>5</keepalive>
- <stateless>1</stateless>
- <language>C</language>
- <implementation>oils_auth.so</implementation>
- <max_requests>93</max_requests>
-
- <unix_config>
- <unix_sock>open-ils.auth_unix.sock</unix_sock>
- <unix_pid>open-ils.auth_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <unix_log>open-ils.auth_unix.log</unix_log>
- <min_children>5</min_children>
- <max_children>35</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
-
- <app_settings>
- <!-- if true, user sessions will be persisted via the OpenSRF persist
- server in addition to memcache -->
- <persist_users>0</persist_users>
-
- <!-- default session timeouts by login type -->
- <default_timeout>
- <opac>300</opac>
- <staff>28800</staff>
- <temp>300</temp> <!-- temporary login -->
- </default_timeout>
-
- </app_settings>
-
- </open-ils.auth>
-
-
- <!-- Generic search server -->
- <open-ils.search>
- <keepalive>5</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenILS::Application::Search</implementation>
- <max_requests>93</max_requests>
-
- <unix_config>
- <unix_sock>open-ils.search_unix.sock</unix_sock>
- <unix_pid>open-ils.search_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <unix_log>open-ils.search_unix.log</unix_log>
- <min_children>5</min_children>
- <max_children>35</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
-
- <app_settings>
- <memcache>127.0.0.1:10101</memcache>
- <max_cache_time>3600</max_cache_time>
- <marc_html_xsl>oilsMARC21slim2HTML.xsl</marc_html_xsl>
- <added_content>
- <!--
- Example added content handler. If this is not defined, the default
- content handler is used, which returns empty sets for all methods
- -->
- <!--
- <implementation>Evergreen::Application::Search::AddedContent::ContentCafe</implementation>
- <host>MY_CONTENT_HOST</host>
- <username>MY_CONTENT_USERNAME</username>
- <password>MY_CONTENT_PASSWORD</password>
- -->
- </added_content>
- <zips_file>/openils/var/data/zips.txt</zips_file>
- <spelling_dictionary>/openils/var/data/oils_authority.dict</spelling_dictionary>
- <cache_timeout>600</cache_timeout>
-
- </app_settings>
-
- </open-ils.search>
-
-
- <!-- server for accessing user info -->
- <open-ils.actor>
- <keepalive>5</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenILS::Application::Actor</implementation>
- <max_requests>93</max_requests>
-
- <unix_config>
- <unix_sock>open-ils.actor_unix.sock</unix_sock>
- <unix_pid>open-ils.actor_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <unix_log>open-ils.actor_unix.log</unix_log>
- <min_children>5</min_children>
- <max_children>35</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
-
- </open-ils.actor>
-
-
-
- <!-- server for editing title, etc... -->
- <open-ils.cat>
- <keepalive>5</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenILS::Application::Cat</implementation>
- <max_requests>199</max_requests>
-
- <unix_config>
- <unix_sock>open-ils.cat_unix.sock</unix_sock>
- <unix_pid>open-ils.cat_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <unix_log>open-ils.cat_unix.log</unix_log>
- <min_children>5</min_children>
- <max_children>25</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
-
- <app_settings>
- <marctemplates>
- <book>/path/to/templates/marc/book.xml</book>
- </marctemplates>
- </app_settings>
-
-
- </open-ils.cat>
-
-
- <opensrf.math>
- <keepalive>3</keepalive>
- <stateless>1</stateless>
- <language>C</language>
- <implementation>osrf_math.so</implementation>
- <max_requests>97</max_requests>
- <unix_config>
- <unix_sock>opensrf.math_unix.sock</unix_sock>
- <unix_pid>opensrf.math_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <unix_log>opensrf.math_unix.log</unix_log>
- <min_children>5</min_children>
- <max_children>15</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
- </opensrf.math>
-
- <opensrf.dbmath>
- <keepalive>3</keepalive>
- <stateless>1</stateless>
- <language>C</language>
- <implementation>osrf_dbmath.so</implementation>
- <max_requests>99</max_requests>
- <unix_config>
- <max_requests>1000</max_requests>
- <unix_log>opensrf.dbmath_unix.log</unix_log>
- <unix_sock>opensrf.dbmath_unix.sock</unix_sock>
- <unix_pid>opensrf.dbmath_unix.pid</unix_pid>
- <min_children>5</min_children>
- <max_children>15</max_children>
- <min_spare_children>2</min_spare_children> <max_spare_children>5</max_spare_children>
- </unix_config>
- </opensrf.dbmath>
-
-
- <!-- penalty server -->
- <open-ils.penalty>
- <keepalive>3</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenILS::Application::Penalty</implementation>
- <max_requests>99</max_requests>
- <unix_config>
- <max_requests>1000</max_requests>
- <unix_log>open-ils.penalty_unix.log</unix_log>
- <unix_sock>open-ils.penalty_unix.sock</unix_sock>
- <unix_pid>open-ils.penalty_unix.pid</unix_pid>
- <min_children>5</min_children>
- <max_children>25</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
- <app_settings>
- <patron_penalty>patron_penalty.js</patron_penalty>
- <script_path>/openils/var/penalty/</script_path>
- </app_settings>
- </open-ils.penalty>
-
-
-
- <!-- Circulation server -->
- <open-ils.circ>
- <keepalive>3</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenILS::Application::Circ</implementation>
- <max_requests>99</max_requests>
- <unix_config>
- <max_requests>1000</max_requests>
- <unix_log>open-ils.circ_unix.log</unix_log>
- <unix_sock>open-ils.circ_unix.sock</unix_sock>
- <unix_pid>open-ils.circ_unix.pid</unix_pid>
- <min_children>5</min_children>
- <max_children>25</max_children>
- <min_spare_children>2</min_spare_children> <max_spare_children>5</max_spare_children>
- </unix_config>
-
- <app_settings>
- <rules>
- <permission>permit_circ.rules</permission>
- <duration>calculate_duration.rules</duration>
- <recurring_fines>calculate_recurring_fines.rules</recurring_fines>
- <max_fines>calculate_max_fines.rules</max_fines>
- <permit_hold>permit_hold.rules</permit_hold>
- <permit_renew>permit_renew.rules</permit_renew>
- </rules>
-
- <script_path>/openils/var/circ/</script_path>
- <scripts>
- <circ_permit_patron>circ_permit_patron.js</circ_permit_patron>
- <circ_permit_copy>circ_permit_copy.js</circ_permit_copy>
- <circ_duration>circ_duration.js</circ_duration>
- <circ_recurring_fines>circ_recurring_fines.js</circ_recurring_fines>
- <circ_max_fines>circ_max_fines.js</circ_max_fines>
- <circ_permit_renew>circ_permit_renew.js</circ_permit_renew>
- <circ_permit_hold>circ_permit_hold.js</circ_permit_hold>
- </scripts>
-
- </app_settings>
-
- </open-ils.circ>
-
- <!-- Database storage server -->
- <open-ils.storage>
- <keepalive>3</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenILS::Application::Storage</implementation>
- <unix_config>
- <max_requests>1000</max_requests>
- <unix_log>storage_unix.log</unix_log>
- <unix_sock>storage_unix.sock</unix_sock>
- <unix_pid>storage_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <min_children>10</min_children>
- <max_children>50</max_children>
- <min_spare_children>2</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
-
- <app_settings>
- <databases>
- <driver>Pg</driver>
- <database>
- <type>master</type>
- <weight>2</weight>
- <user>postgres</user>
- <host>127.0.0.1</host>
- <pw>postgres</pw>
- <db>demo-dev</db>
- <client_encoding>SQL_ASCII</client_encoding>
- </database>
- </databases>
- </app_settings>
-
- </open-ils.storage>
-
- <opensrf.settings>
- <keepalive>1</keepalive>
- <stateless>1</stateless>
- <language>perl</language>
- <implementation>OpenSRF::Application::Settings</implementation>
- <max_requests>17</max_requests>
- <unix_config>
- <unix_sock>opensrf.settings_unix.sock</unix_sock>
- <unix_pid>opoensrf.settings_unix.pid</unix_pid>
- <max_requests>1000</max_requests>
- <unix_log>opensrf.settings_unix.log</unix_log>
- <min_children>5</min_children>
- <max_children>15</max_children>
- <min_spare_children>3</min_spare_children>
- <max_spare_children>5</max_spare_children>
- </unix_config>
- </opensrf.settings>
-
- </apps>
-
- </default>
-
- <hosts>
-
-
- <!-- single host install, everything goes into one host section -->
- <myhost.mydomain.com> <!-- must match 'hostname -f' -->
- <activeapps>
-
- <!-- opensrf builtin apps -->
- <appname>opensrf.math</appname>
- <appname>opensrf.dbmath</appname>
- <appname>opensrf.settings</appname>
-
- <!-- openils apps -->
- <appname>open-ils.cat</appname>
- <appname>open-ils.search</appname>
- <appname>open-ils.circ</appname>
- <appname>open-ils.penalty</appname>
- <appname>open-ils.actor</appname>
- <appname>open-ils.auth</appname>
- <appname>open-ils.storage</appname>
-
- </activeapps>
- </myhost.mydomain.com>
-
- </hosts>
+<opensrf version='0.0.2'>
+
+ <default>
+
+ <dirs>
+ <log>/openils/var/log</log> <!-- unix::server log files -->
+ <sock>/openils/var/sock</sock> <!-- unix::server sock files -->
+ <pid>/openils/var/pid</pid>
+ <xsl>/openils/var/xsl</xsl>
+ <script>/openils/var</script>
+ <script_lib>/openils/var</script_lib>
+ </dirs>
+
+ <IDL>/openils/conf/fm_IDL.xml</IDL> <!-- top level IDL file -->
+ <server_type>prefork</server_type> <!-- net::server type -->
+ <ils_events>/openils/var/data/ils_events.xml</ils_events> <!-- ILS events description file -->
+
+ <email_notify>
+ <!-- global email notification settings -->
+ <template>/openils/var/data/hold_notification_template.example</template>
+ <smtp_server>localhost</smtp_server>
+
+ <!-- in most cases, this is overridden by location
+ specific config settings. this is just the default -->
+ <sender_address>evergreen@localhost</sender_address>
+ </email_notify>
+
+
+ <reporter>
+ <!--
+ Settings for the reporter daemon process
+ -->
+ <setup>
+ <base_uri>https://localhost/reporter/</base_uri>
+ <database>
+ <driver>Pg</driver>
+ <host>localhost</host>
+ <port>5432</port>
+ <name>evergreen</name>
+ <user>postgres</user>
+ <password>postgres</password>
+ </database>
+ <files>
+ <!-- successfull report outputs go here -->
+ <output_base>/openils/var/reporter/output</output_base>
+ <success_template>/openils/var/data/report-success</success_template>
+ <fail_template>/openils/var/data/report-fail</fail_template>
+ </files>
+ </setup>
+ </reporter>
+
+
+
+ <xml-rpc>
+ <!-- XML-RPC gateway. Do NOT publish unprotected services here -->
+ <allowed_services>
+ <!-- list of published services -->
+ <service>opensrf.math</service>
+ <service>opensrf.dbmath</service>
+ <service>open-ils.cat</service>
+ <service>open-ils.search</service>
+ <service>open-ils.circ</service>
+ <service>open-ils.actor</service>
+ <service>open-ils.auth</service>
+ <service>open-ils.collections</service>
+ </allowed_services>
+ </xml-rpc>
+
+
+ <z3950>
+ <default>oclc</default>
+ <services>
+ <oclc>
+ <!-- Z3950 settings for OCLC. Note that OCLC requires username/password -->
+ <host>zcat.oclc.org</host>
+ <port>210</port>
+ <db>OLUCWorldCat</db>
+ <attrs>
+ <!--
+ These are directly from the Bib-1 Attribute Set
+ http://www.loc.gov/z3950/agency/defns/bib1.html
+ <code> is the "use attribute", <format> is the "structure attribute"
+ This just puts some friendly names on the data.
+ Just copy this chunk to the <attrs> section of <loc> and
+ uncomment the chunk to use the LoC Z server instead
+ -->
+ <tcn><code>12</code><format>1</format></tcn>
+ <isbn><code>7</code><format>6</format></isbn>
+ <lccn><code>9</code><format>1</format></lccn>
+ <author><code>1003</code><format>6</format></author>
+ <title><code>4</code><format>6</format></title>
+ <issn><code>8</code><format>1</format></issn>
+ <publisher><code>1018</code><format>6</format></publisher>
+ <pubdate><code>31</code><format>1</format></pubdate>
+ <item_type><code>1001</code><format>1</format></item_type>
+ </attrs>
+ </oclc>
+
+ <!--
+ <loc>
+ <name>loc</name>
+ <host>z3950.loc.gov</host>
+ <port>7090</port>
+ <db>Voyager</db>
+ <attrs>
+ </attrs>
+ </loc>
+ -->
+
+ </services>
+ </z3950>
+
+
+ <added_content>
+ <!-- configure an added content plugin -->
+ <module>OpenILS::WWW::AddedContent::Syndetic</module>
+ <userid>MY_USER_ID</userid>
+ <base_url>http://syndetics.com/index.aspx</base_url>
+ </added_content>
+
+
+
+ <!-- no apps are enabled globally by default -->
+ <activeapps/>
+
+ <cache>
+ <!-- memcache servers -->
+ <global>
+ <servers>
+ <server>localhost:11211</server>
+ </servers>
+ <max_cache_time>86400</max_cache_time>
+ </global>
+ </cache>
+
+ <apps>
+ <!-- Authentication server -->
+ <open-ils.auth>
+
+ <!-- how long to wait between stateful requests before the child process re-joins the pool -->
+ <keepalive>5</keepalive>
+
+ <!-- true if this service support stateless requests -->
+ <stateless>1</stateless>
+
+ <!-- implementation language -->
+ <language>c</language>
+
+ <!-- library to plugin -->
+ <implementation>oils_auth.so</implementation>
+
+ <!-- maximum required opensrf requests within a stateful connection -->
+ <max_requests>93</max_requests>
+
+ <unix_config>
+
+ <!-- Note that not all implementations use all settings -->
+
+ <!-- unix sock file -->
+ <unix_sock>open-ils.auth_unix.sock</unix_sock>
+
+ <!-- PID files -->
+ <unix_pid>open-ils.auth_unix.pid</unix_pid>
+
+ <!-- maximum number of top level requests coming to
+ this child before the child is recycled -->
+ <max_requests>1000</max_requests>
+
+ <!-- Perl net::server log -->
+ <unix_log>open-ils.auth_unix.log</unix_log>
+ <!-- min children to fork -->
+ <min_children>1</min_children>
+ <!-- max possible children to fork -->
+ <max_children>15</max_children>
+ <!-- min idle children -->
+ <min_spare_children>1</min_spare_children>
+ <!-- max idle children -->
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+
+ <app_settings>
+ <!-- defined app-specific settings here -->
+ <default_timeout>
+ <!-- default login timeouts based on login type -->
+ <opac>420</opac>
+ <staff>7200</staff>
+ <temp>300</temp>
+ </default_timeout>
+ </app_settings>
+ </open-ils.auth>
+
+
+ <!-- Generic search server -->
+ <open-ils.search>
+ <keepalive>5</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Search</implementation>
+ <max_requests>93</max_requests>
+ <unix_config>
+ <unix_sock>open-ils.search_unix.sock</unix_sock>
+ <unix_pid>open-ils.search_unix.pid</unix_pid>
+ <max_requests>1000</max_requests>
+ <unix_log>open-ils.search_unix.log</unix_log>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <marc_html_xsl>oilsMARC21slim2HTML.xsl</marc_html_xsl>
+ <!-- zip code database file -->
+ <!--<zips_file>/openils/var/data/zips.txt</zips_file>-->
+ </app_settings>
+ </open-ils.search>
+
+ <!-- server for accessing user info -->
+ <open-ils.actor>
+ <keepalive>5</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Actor</implementation>
+ <max_requests>93</max_requests>
+ <unix_config>
+ <unix_sock>open-ils.actor_unix.sock</unix_sock>
+ <unix_pid>open-ils.actor_unix.pid</unix_pid>
+ <max_requests>1000</max_requests>
+ <unix_log>open-ils.actor_unix.log</unix_log>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ </open-ils.actor>
+
+
+ <open-ils.cat>
+ <keepalive>5</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Cat</implementation>
+ <max_requests>199</max_requests>
+ <unix_config>
+ <unix_sock>open-ils.cat_unix.sock</unix_sock>
+ <unix_pid>open-ils.cat_unix.pid</unix_pid>
+ <max_requests>1000</max_requests>
+ <unix_log>open-ils.cat_unix.log</unix_log>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <marctemplates>
+ <K_book>/openils/var/templates/marc/k_book.xml</K_book>
+ </marctemplates>
+ </app_settings>
+ </open-ils.cat>
+
+ <open-ils.supercat>
+ <keepalive>5</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::SuperCat</implementation>
+ <max_requests>199</max_requests>
+ <unix_config>
+ <unix_sock>open-ils.supercat_unix.sock</unix_sock>
+ <unix_pid>open-ils.supercat_unix.pid</unix_pid>
+ <max_requests>1000</max_requests>
+ <unix_log>open-ils.supercat_unix.log</unix_log>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ </open-ils.supercat>
+
+
+ <opensrf.math>
+ <keepalive>3</keepalive>
+ <stateless>1</stateless>
+ <language>c</language>
+ <implementation>osrf_math.so</implementation>
+ <max_requests>97</max_requests>
+ <unix_config>
+ <unix_sock>opensrf.math_unix.sock</unix_sock>
+ <unix_pid>opensrf.math_unix.pid</unix_pid>
+ <max_requests>1000</max_requests>
+ <unix_log>opensrf.math_unix.log</unix_log>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ </opensrf.math>
+
+ <opensrf.dbmath>
+ <keepalive>3</keepalive>
+ <stateless>1</stateless>
+ <language>c</language>
+ <implementation>osrf_dbmath.so</implementation>
+ <max_requests>99</max_requests>
+ <unix_config>
+ <max_requests>1000</max_requests>
+ <unix_log>opensrf.dbmath_unix.log</unix_log>
+ <unix_sock>opensrf.dbmath_unix.sock</unix_sock>
+ <unix_pid>opensrf.dbmath_unix.pid</unix_pid>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ </opensrf.dbmath>
+
+ <open-ils.penalty>
+ <keepalive>3</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Penalty</implementation>
+ <max_requests>99</max_requests>
+ <unix_config>
+ <max_requests>1000</max_requests>
+ <unix_log>open-ils.penalty_unix.log</unix_log>
+ <unix_sock>open-ils.penalty_unix.sock</unix_sock>
+ <unix_pid>open-ils.penalty_unix.pid</unix_pid>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <patron_penalty>penalty/patron_penalty.js</patron_penalty>
+ <script_path>/openils/var</script_path>
+ <script_path>/openils/var/catalog</script_path>
+ </app_settings>
+ </open-ils.penalty>
+
+ <open-ils.circ>
+ <keepalive>3</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Circ</implementation>
+ <max_requests>99</max_requests>
+ <unix_config>
+ <max_requests>1000</max_requests>
+ <unix_log>open-ils.circ_unix.log</unix_log>
+ <unix_sock>open-ils.circ_unix.sock</unix_sock>
+ <unix_pid>open-ils.circ_unix.pid</unix_pid>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <notify_hold>
+ <email>false</email> <!-- set to true for hold notice emails -->
+ </notify_hold>
+
+ <!-- circulation policy scripts -->
+ <script_path>/openils/var</script_path>
+ <script_path>/openils/var/catalog</script_path>
+ <scripts>
+ <circ_permit_patron>circ/circ_permit_patron.js</circ_permit_patron>
+ <circ_permit_copy>circ/circ_permit_copy.js</circ_permit_copy>
+ <circ_duration>circ/circ_duration.js</circ_duration>
+ <circ_recurring_fines>circ/circ_recurring_fines.js</circ_recurring_fines>
+ <circ_max_fines>circ/circ_max_fines.js</circ_max_fines>
+ <circ_permit_renew>circ/circ_permit_renew.js</circ_permit_renew>
+ <circ_permit_hold>circ/circ_permit_hold.js</circ_permit_hold>
+ </scripts>
+
+ <circ_modifiers>
+ <mod>art</mod>
+ <mod>atlas</mod>
+ <mod>audiobook</mod>
+ <mod>av</mod>
+ <mod>new-av</mod>
+ <mod>bestseller</mod>
+ <mod>bestsellernh</mod>
+ <mod>book</mod>
+ <mod>cd</mod>
+ <mod>dvd</mod>
+ <mod>dvd-long</mod>
+ <mod>e-book</mod>
+ <mod>equipment</mod>
+ <mod>filmstrip</mod>
+ <mod>kit</mod>
+ <mod>magazine</mod>
+ <mod>map</mod>
+ <mod>microform</mod>
+ <mod>music</mod>
+ <mod>record</mod>
+ <mod>software</mod>
+ <mod>softwrlong</mod>
+ <mod>equip-long</mod>
+ <mod>talking book</mod>
+ <mod>toy</mod>
+ <mod>video</mod>
+ <mod>video-long</mod>
+ </circ_modifiers>
+
+ <billing_types>
+ <type>Miscellaneous</type>
+ <type>Overdue materials</type>
+ <type>Fee for placing a hold</type>
+ <type>Fee for checking out a book</type>
+ <type>Fee for library card</type>
+ <type>Miscellaneous charges</type>
+ <type>Lost materials</type>
+ <type>Damaged material</type>
+ <type>Overdue Reserves charge</type>
+ <type>Recall overdue</type>
+ <type>Fee for processing lost library materials</type>
+ <type>Fee for sending patron bills to collection agency</type>
+ <type>Fee for interlibrary loan</type>
+ <type>Fee for copies</type>
+ <type>Money advanced to pay for telephone use</type>
+ <type>Deposit fee</type>
+ <type>Fee for disk</type>
+ <type>Fee for faxing</type>
+ <type>Fee for laminating</type>
+ <type>Fee for room cleaning</type>
+ <type>Deposit returned; fee refund</type>
+ <type>Sale items</type>
+ <type>Fee for lost card</type>
+ <type>Long overdue items</type>
+ <type>Lost/Replacement Cassette</type>
+ <type>Returned Check</type>
+ </billing_types>
+ </app_settings>
+ </open-ils.circ>
+
+ <open-ils.ingest>
+ <keepalive>3</keepalive>
+ <stateless>1</stateless>
+ <implementation>OpenILS::Application::Ingest</implementation>
+ <language>perl</language>
+ <max_requests>1000000</max_requests>
+ <unix_config>
+ <max_requests>1000000</max_requests>
+ <unix_log>open-ils.ingest-unix.log</unix_log>
+ <unix_sock>open-ils.ingest-unix.sock</unix_sock>
+ <unix_pid>open-ils.ingest-unix.pid</unix_pid>
+ <min_children>5</min_children>
+ <max_children>20</max_children>
+ <min_spare_children>2</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <script_path>/openils/var/catalog/</script_path>
+ <script_path>/openils/var/web/opac/common/js/</script_path>
+ <scripts>
+ <biblio_fingerprint>biblio_fingerprint.js</biblio_fingerprint>
+ <biblio_descriptor>biblio_descriptor.js</biblio_descriptor>
+ </scripts>
+ </app_settings>
+ </open-ils.ingest>
+
+ <open-ils.storage>
+ <keepalive>10</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Storage</implementation>
+ <unix_config>
+ <max_requests>1000</max_requests>
+ <unix_log>storage_unix.log</unix_log>
+ <unix_sock>storage_unix.sock</unix_sock>
+ <unix_pid>storage_unix.pid</unix_pid>
+ <max_requests>400</max_requests>
+ <min_children>1</min_children>
+ <max_children>10</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <script_path>/openils/var/catalog/</script_path>
+ <scripts>
+ <biblio_fingerprint>biblio_fingerprint.js</biblio_fingerprint>
+ </scripts>
+ <databases>
+ <driver>Pg</driver>
+ <database>
+ <type>master</type>
+ <weight>2</weight>
+ <user>postgres</user>
+ <host>localhost</host>
+ <port>5432</port>
+ <pw>postgres</pw>
+ <db>evergreen</db>
+ <client_encoding>UTF-8</client_encoding>
+ </database>
+ </databases>
+ </app_settings>
+ </open-ils.storage>
+
+
+ <open-ils.cstore>
+ <keepalive>6</keepalive>
+ <stateless>1</stateless>
+ <language>C</language>
+ <implementation>oils_cstore.so</implementation>
+ <max_requests>95</max_requests>
+ <unix_config>
+ <unix_log>cstore.log</unix_log>
+ <unix_sock>cstore.sock</unix_sock>
+ <unix_pid>cstore.pid</unix_pid>
+ <max_requests>400</max_requests>
+ <min_children>1</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <IDL>/openils/conf/fm_IDL.xml</IDL> <!-- deprecated with 1.1.0-->
+ <driver>pgsql</driver>
+ <database>
+ <type>master</type>
+ <weight>2</weight>
+ <user>postgres</user>
+ <host>localhost</host>
+ <port>5432</port>
+ <pw>postgres</pw>
+ <db>evergreen</db>
+ <client_encoding>UTF-8</client_encoding>
+ </database>
+ </app_settings>
+ </open-ils.cstore>
+
+
+
+ <opensrf.settings>
+ <keepalive>1</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenSRF::Application::Settings</implementation>
+ <max_requests>17</max_requests>
+ <unix_config>
+ <unix_sock>opensrf.settings_unix.sock</unix_sock>
+ <unix_pid>opoensrf.settings_unix.pid</unix_pid>
+ <max_requests>300</max_requests>
+ <unix_log>opensrf.settings_unix.log</unix_log>
+ <min_children>5</min_children>
+ <max_children>15</max_children>
+ <min_spare_children>3</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ </opensrf.settings>
+
+ <open-ils.collections>
+ <keepalive>3</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Collections</implementation>
+ <max_requests>17</max_requests>
+ <unix_config>
+ <unix_sock>opensrf.collections_unix.sock</unix_sock>
+ <unix_pid>opoensrf.collections_unix.pid</unix_pid>
+ <max_requests>1000</max_requests>
+ <unix_log>opensrf.collections_unix.log</unix_log>
+ <min_children>1</min_children>
+ <max_children>10</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ </open-ils.collections>
+
+ <open-ils.reporter>
+ <keepalive>3</keepalive>
+ <stateless>1</stateless>
+ <language>perl</language>
+ <implementation>OpenILS::Application::Reporter</implementation>
+ <max_requests>99</max_requests>
+ <unix_config>
+ <unix_sock>opensrf.reporter_unix.sock</unix_sock>
+ <unix_pid>opoensrf.reporter_unix.pid</unix_pid>
+ <max_requests>1000</max_requests>
+ <unix_log>opensrf.reporter_unix.log</unix_log>
+ <min_children>1</min_children>
+ <max_children>10</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ </open-ils.reporter>
+
+
+ <open-ils.reporter-store>
+ <keepalive>6</keepalive>
+ <stateless>1</stateless>
+ <language>C</language>
+ <implementation>oils_rstore.so</implementation>
+ <max_requests>95</max_requests>
+ <unix_config>
+ <unix_log>rstore.log</unix_log>
+ <unix_sock>rstore.sock</unix_sock>
+ <unix_pid>rstore.pid</unix_pid>
+ <max_requests>400</max_requests>
+ <min_children>1</min_children>
+ <max_children>10</max_children>
+ <min_spare_children>1</min_spare_children>
+ <max_spare_children>5</max_spare_children>
+ </unix_config>
+ <app_settings>
+ <IDL>/openils/conf/fm_IDL.xml</IDL> <!-- deprecated with 1.1.0 -->
+ <driver>pgsql</driver>
+ <database>
+ <type>master</type>
+ <weight>2</weight>
+ <user>postgres</user>
+ <host>localhost</host>
+ <port>5432</port>
+ <pw>postgres</pw>
+ <db>evergreen</db>
+ <client_encoding>UTF-8</client_encoding>
+ </database>
+ </app_settings>
+ </open-ils.reporter-store>
+
+
+ </apps>
+ </default>
+
+ <hosts>
+ <localhost> <!-- must match "hostname -f" of the hosting machine -->
+ <activeapps>
+ <!-- services hosted on this machine -->
+ <appname>opensrf.settings</appname>
+ <appname>opensrf.math</appname>
+ <appname>opensrf.dbmath</appname>
+ <appname>open-ils.cat</appname>
+ <appname>open-ils.supercat</appname>
+ <appname>open-ils.search</appname>
+ <appname>open-ils.circ</appname>
+ <appname>open-ils.actor</appname>
+ <appname>open-ils.auth</appname>
+ <appname>open-ils.storage</appname>
+ <appname>open-ils.penalty</appname>
+ <appname>open-ils.cstore</appname>
+ <appname>open-ils.collections</appname>
+ <appname>open-ils.ingest</appname>
+ <appname>open-ils.reporter</appname>
+ <appname>open-ils.reporter-store</appname>
+ </activeapps>
+ </localhost>
+ </hosts>
</opensrf>
export TMPDIR = $(TMP)/opensrf
-export LDFLAGS = -L $(TMPDIR) -L .
-export CFLAGS = -pipe -g -Wall -O2 -fPIC -I$(LIBXML2_HEADERS) -I$(APACHE2_HEADERS) -I$(APR_HEADERS) \
+export LDFLAGS += -L $(TMPDIR) -L .
+export CFLAGS += -pipe -g -Wall -O2 -fPIC -I$(LIBXML2_HEADERS) -I$(APACHE2_HEADERS) -I$(APR_HEADERS) \
-I$(LIBXML2_HEADERS)/libxml -I$(TMP) -I$(TMPDIR)
export INCDIR = "$(INCLUDEDIR)/openils/"
webcore-install:
@echo $@
echo "Copying web into $(WEBDIR)"
+ mkdir -p $(ADMINDIR)
+ cp -r ../admin/* $(ADMINDIR)
mkdir -p $(WEBDIR)
mkdir -p $(WEBDIR)/opac/extras/xsl/
mkdir -p $(WEBDIR)/opac/extras/slimpac/
reporter-install:
@echo $@
- @echo "Installing Reporter templates to $(REPORTERDIR) and example configs to $(ETCDIR)"
- cp reporter/report_base.example.xml $(ETCDIR)/reporter.example.xml
- cp reporter/tables.example.xml $(ETCDIR)
- cp reporter/widgets.example.xml $(ETCDIR)
- mkdir -p $(REPORTERDIR)
- cp -r reporter/templates/* $(REPORTERDIR)
+# @echo "Installing Reporter templates to $(REPORTERDIR) and example configs to $(ETCDIR)"
+# cp reporter/report_base.example.xml $(ETCDIR)/reporter.example.xml
+# cp reporter/tables.example.xml $(ETCDIR)
+# cp reporter/widgets.example.xml $(ETCDIR)
+# mkdir -p $(REPORTERDIR)
+# cp -r reporter/templates/* $(REPORTERDIR)
# -----------------------------------------------------------------------------------
offline-install:
#define OBJECT_NS "http://open-ils.org/spec/opensrf/IDL/objects/v1"
#define BASE_NS "http://opensrf.org/spec/IDL/base/v1"
+#define SELECT_DISTINCT 1
+
int osrfAppChildInit();
int osrfAppInitialize();
+void osrfAppChildExit();
int verifyObjectClass ( osrfMethodContext*, jsonObject* );
int releaseSavepoint ( osrfMethodContext* );
int rollbackSavepoint ( osrfMethodContext* );
+int doJSONSearch ( osrfMethodContext* );
+
int dispatchCRUDMethod ( osrfMethodContext* );
jsonObject* doCreate ( osrfMethodContext*, int* );
jsonObject* doRetrieve ( osrfMethodContext*, int* );
jsonObject* doUpdate ( osrfMethodContext*, int* );
jsonObject* doDelete ( osrfMethodContext*, int* );
-jsonObject* doSearch ( osrfMethodContext*, osrfHash*, jsonObject*, int* );
-jsonObject* oilsMakeJSONFromResult( dbi_result, osrfHash* );
-
-char* searchWriteSimplePredicate ( osrfHash*, const char*, const char*, const char* );
-char* searchSimplePredicate ( const char*, osrfHash*, jsonObject* );
-char* searchFunctionPredicate ( osrfHash*, jsonObjectNode* );
-char* searchFieldTransform (osrfHash*, jsonObject*);
-char* searchFieldTransformPredicate ( osrfHash*, jsonObjectNode* );
-char* searchBETWEENPredicate ( osrfHash*, jsonObject* );
-char* searchINPredicate ( osrfHash*, jsonObject*, const char* );
-char* searchPredicate ( osrfHash*, jsonObject* );
+jsonObject* doFieldmapperSearch ( osrfMethodContext*, osrfHash*, jsonObject*, int* );
+jsonObject* oilsMakeFieldmapperFromResult( dbi_result, osrfHash* );
+jsonObject* oilsMakeJSONFromResult( dbi_result );
+
+char* searchWriteSimplePredicate ( const char*, osrfHash*, const char*, const char*, const char* );
+char* searchSimplePredicate ( const char*, const char*, osrfHash*, jsonObject* );
+char* searchFunctionPredicate ( const char*, osrfHash*, jsonObjectNode* );
+char* searchFieldTransform (const char*, osrfHash*, jsonObject*);
+char* searchFieldTransformPredicate ( const char*, osrfHash*, jsonObjectNode* );
+char* searchBETWEENPredicate ( const char*, osrfHash*, jsonObject* );
+char* searchINPredicate ( const char*, osrfHash*, jsonObject*, const char* );
+char* searchPredicate ( const char*, osrfHash*, jsonObject* );
+char* searchJOIN ( jsonObject*, osrfHash* );
+char* searchWHERE ( jsonObject*, osrfHash*, int );
char* buildSELECT ( jsonObject*, jsonObject*, osrfHash*, osrfMethodContext* );
+char* SELECT ( osrfMethodContext*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, jsonObject*, int );
+
void userDataFree( void* );
void sessionDataFree( char*, void* );
osrfHash readHandles;
jsonObject* jsonNULL = NULL; //
+/* called when this process is about to exit */
+void osrfAppChildExit() {
+ osrfLogDebug(OSRF_LOG_MARK, "Child is exiting, disconnecting from database...");
+
+ if (writehandle) {
+ dbi_conn_query(writehandle, "ROLLBACK;");
+ dbi_conn_close(writehandle);
+ writehandle = NULL;
+ }
+
+ if (dbhandle)
+ dbi_conn_close(dbhandle);
-/* parse and store the IDL here */
-osrfHash* idl;
+ // XXX add cleanup of readHandles whenever that gets used
+
+ return;
+}
int osrfAppInitialize() {
growing_buffer* method_name;
osrfLogInfo(OSRF_LOG_MARK, "Found file:");
osrfLogInfo(OSRF_LOG_MARK, idl_filename);
- idl = oilsIDLInit( idl_filename );
-
- if (!idl) {
+ if (!oilsIDLInit( idl_filename )) {
osrfLogError(OSRF_LOG_MARK, "Problem loading the IDL. Seacrest out!");
exit(1);
}
+ // Generic search thingy
+ method_name = buffer_init(64);
+ buffer_fadd(method_name, "%s.json_query", MODULENAME);
+ osrfAppRegisterMethod( MODULENAME, buffer_data(method_name), "doJSONSearch", "", 1, OSRF_METHOD_STREAMING );
+
// first we register all the transaction and savepoint methods
method_name = buffer_init(64);
buffer_fadd(method_name, "%s.transaction.begin", MODULENAME);
int c_index = 0;
char* classname;
- osrfStringArray* classes = osrfHashKeys( idl );
+ osrfStringArray* classes = osrfHashKeys( oilsIDL() );
osrfLogDebug(OSRF_LOG_MARK, "%d classes loaded", classes->size );
osrfLogDebug(OSRF_LOG_MARK, "At least %d methods will be generated", classes->size * global_methods->size);
while ( (classname = osrfStringArrayGetString(classes, c_index++)) ) {
osrfLogInfo(OSRF_LOG_MARK, "Generating class methods for %s", classname);
- osrfHash* idlClass = osrfHashGet(idl, classname);
+ osrfHash* idlClass = osrfHashGet(oilsIDL(), classname);
if (!osrfStringArrayContains( osrfHashGet(idlClass, "controller"), MODULENAME )) {
osrfLogInfo(OSRF_LOG_MARK, "%s is not listed as a controller for %s, moving on", MODULENAME, classname);
unsigned short type;
int i = 0;
char* classname;
- osrfStringArray* classes = osrfHashKeys( idl );
+ osrfStringArray* classes = osrfHashKeys( oilsIDL() );
while ( (classname = osrfStringArrayGetString(classes, i++)) ) {
- osrfHash* class = osrfHashGet( idl, classname );
+ osrfHash* class = osrfHashGet( oilsIDL(), classname );
osrfHash* fields = osrfHashGet( class, "fields" );
char* virt = osrfHashGet(class, "virtual");
if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "search")) {
- obj = doSearch(ctx, class_obj, ctx->params, &err);
+ obj = doFieldmapperSearch(ctx, class_obj, ctx->params, &err);
if(err) return err;
jsonObjectNode* cur;
osrfLogDebug(OSRF_LOG_MARK, "%s: Select qualifer set to [%s]", MODULENAME, _s);
free(_s);
- obj = doSearch(ctx, class_obj, _p, &err);
+ obj = doFieldmapperSearch(ctx, class_obj, _p, &err);
if(err) return err;
jsonObjectNode* cur;
jsonNewObject(id)
);
- jsonObject* list = doSearch( ctx,meta, fake_params, err);
+ jsonObject* list = doFieldmapperSearch( ctx,meta, fake_params, err);
if(*err) {
jsonObjectFree( fake_params );
if (order_hash) jsonObjectPush(fake_params, jsonObjectClone(order_hash) );
- jsonObject* list = doSearch( ctx,meta, fake_params, err);
+ jsonObject* list = doFieldmapperSearch( ctx,meta, fake_params, err);
if(*err) {
jsonObjectFree( fake_params );
return pred;
}
-char* searchINPredicate (osrfHash* field, jsonObject* node, const char* op) {
+char* searchINPredicate (const char* class, osrfHash* field, jsonObject* node, const char* op) {
growing_buffer* sql_buf = buffer_init(32);
buffer_fadd(
sql_buf,
- "%s ",
+ "\"%s\".%s ",
+ class,
osrfHashGet(field, "name")
);
return pred;
}
-char* searchFunctionPredicate (osrfHash* field, jsonObjectNode* node) {
+char* searchFunctionPredicate (const char* class, osrfHash* field, jsonObjectNode* node) {
growing_buffer* sql_buf = buffer_init(32);
char* val = searchValueTransform(node->item);
buffer_fadd(
sql_buf,
- "%s %s %s",
+ "\"%s\".%s %s %s",
+ class,
osrfHashGet(field, "name"),
node->key,
val
return pred;
}
-char* searchFieldTransform (osrfHash* field, jsonObject* node) {
+char* searchFieldTransform (const char* class, osrfHash* field, jsonObject* node) {
growing_buffer* sql_buf = buffer_init(32);
char* field_transform = jsonObjectToSimpleString( jsonObjectGetKey( node, "transform" ) );
buffer_fadd(
sql_buf,
- "%s(%s)",
+ "%s(\"%s\".%s)",
field_transform,
+ class,
osrfHashGet(field, "name")
);
return pred;
}
-char* searchFieldTransformPredicate (osrfHash* field, jsonObjectNode* node) {
+char* searchFieldTransformPredicate (const char* class, osrfHash* field, jsonObjectNode* node) {
growing_buffer* sql_buf = buffer_init(32);
- char* field_transform = searchFieldTransform( field, node->item );
+ char* field_transform = searchFieldTransform( class, field, node->item );
char* value = NULL;
if (jsonObjectGetKey( node->item, "value" )->type == JSON_ARRAY) {
return pred;
}
-char* searchSimplePredicate (const char* orig_op, osrfHash* field, jsonObject* node) {
+char* searchSimplePredicate (const char* orig_op, const char* class, osrfHash* field, jsonObject* node) {
char* val = NULL;
}
}
- char* pred = searchWriteSimplePredicate( field, osrfHashGet(field, "name"), orig_op, val );
+ char* pred = searchWriteSimplePredicate( class, field, osrfHashGet(field, "name"), orig_op, val );
if (val) free(val);
return pred;
}
-char* searchWriteSimplePredicate ( osrfHash* field, const char* left, const char* orig_op, const char* right ) {
+char* searchWriteSimplePredicate ( const char* class, osrfHash* field, const char* left, const char* orig_op, const char* right ) {
char* val = NULL;
char* op = NULL;
}
growing_buffer* sql_buf = buffer_init(16);
- buffer_fadd( sql_buf, "%s %s %s", left, op, val );
+ buffer_fadd( sql_buf, "\"%s\".%s %s %s", class, left, op, val );
free(val);
free(op);
}
-char* searchBETWEENPredicate (osrfHash* field, jsonObject* node) {
+char* searchBETWEENPredicate (const char* class, osrfHash* field, jsonObject* node) {
char* x_string;
char* y_string;
return pred;
}
-char* searchPredicate ( osrfHash* field, jsonObject* node ) {
+char* searchPredicate ( const char* class, osrfHash* field, jsonObject* node ) {
char* pred = NULL;
if (node->type == JSON_ARRAY) { // equality IN search
- pred = searchINPredicate( field, node, NULL );
+ pred = searchINPredicate( class, field, node, NULL );
} else if (node->type == JSON_HASH) { // non-equality search
jsonObjectNode* pred_node;
jsonObjectIterator* pred_itr = jsonNewObjectIterator( node );
while ( (pred_node = jsonObjectIteratorNext( pred_itr )) ) {
if ( !(strcasecmp( pred_node->key,"between" )) )
- pred = searchBETWEENPredicate( field, pred_node->item );
+ pred = searchBETWEENPredicate( class, field, pred_node->item );
else if ( !(strcasecmp( pred_node->key,"in" )) || !(strcasecmp( pred_node->key,"not in" )) )
- pred = searchINPredicate( field, pred_node->item, pred_node->key );
+ pred = searchINPredicate( class, field, pred_node->item, pred_node->key );
else if ( pred_node->item->type == JSON_ARRAY )
- pred = searchFunctionPredicate( field, pred_node );
+ pred = searchFunctionPredicate( class, field, pred_node );
else if ( pred_node->item->type == JSON_HASH )
- pred = searchFieldTransformPredicate( field, pred_node );
+ pred = searchFieldTransformPredicate( class, field, pred_node );
else
- pred = searchSimplePredicate( pred_node->key, field, pred_node->item );
+ pred = searchSimplePredicate( pred_node->key, class, field, pred_node->item );
break;
}
growing_buffer* _p = buffer_init(16);
buffer_fadd(
_p,
- "%s IS NULL",
+ "\"%s\".%s IS NULL",
+ class,
osrfHashGet(field, "name")
);
pred = buffer_data(_p);
buffer_free(_p);
} else { // equality search
- pred = searchSimplePredicate( "=", field, node );
+ pred = searchSimplePredicate( "=", class, field, node );
}
return pred;
}
-char* buildSELECT ( jsonObject* search_hash, jsonObject* order_hash, osrfHash* meta, osrfMethodContext* ctx ) {
- // XXX this will be used for joins, I think
- //osrfHash* links = osrfHashGet(meta, "links");
+/*
+
+join : {
+ acn : {
+ field : record,
+ fkey : id
+ type : left
+ filter_op : or
+ filter : { ... },
+ join : {
+ acp : {
+ field : call_number,
+ fkey : id,
+ filter : { ... },
+ },
+ },
+ },
+ mrd : {
+ field : record,
+ type : inner
+ fkey : id,
+ filter : { ... },
+ }
+}
+
+*/
- osrfHash* fields = osrfHashGet(meta, "fields");
- char* core_class = osrfHashGet(meta, "classname");
+char* searchJOIN ( jsonObject* join_hash, osrfHash* leftmeta ) {
+
+ if (join_hash->type == JSON_STRING) {
+ char* __tmp = jsonObjectToSimpleString( join_hash );
+ join_hash = jsonParseString("{}");
+ jsonObjectSetKey(join_hash, __tmp, NULL);
+ free(__tmp);
+ }
+
+ growing_buffer* join_buf = buffer_init(128);
+ char* leftclass = osrfHashGet(leftmeta, "classname");
- jsonObjectNode* node = NULL;
jsonObjectNode* snode = NULL;
- jsonObject* _tmp;
+ jsonObjectIterator* search_itr = jsonNewObjectIterator( join_hash );
+ while ( (snode = jsonObjectIteratorNext( search_itr )) ) {
+ osrfHash* idlClass = osrfHashGet( oilsIDL(), snode->key );
+
+ char* class = osrfHashGet(idlClass, "classname");
+ char* table = osrfHashGet(idlClass, "tablename");
+
+ char* type = jsonObjectToSimpleString( jsonObjectGetKey( snode->item, "type" ) );
+ char* filter_op = jsonObjectToSimpleString( jsonObjectGetKey( snode->item, "filter_op" ) );
+ char* fkey = jsonObjectToSimpleString( jsonObjectGetKey( snode->item, "fkey" ) );
+ char* field = jsonObjectToSimpleString( jsonObjectGetKey( snode->item, "field" ) );
+
+ jsonObject* filter = jsonObjectGetKey( snode->item, "filter" );
+ jsonObject* join_filter = jsonObjectGetKey( snode->item, "join" );
+
+ if (field && !fkey) {
+ fkey = (char*)oilsIDLFindPath("/%s/links/%s/key", class, field);
+ if (!fkey) {
+ osrfLogError(
+ OSRF_LOG_MARK,
+ "%s: JOIN failed. No link defined from %s.%s to %s",
+ MODULENAME,
+ class,
+ field,
+ leftclass
+ );
+ buffer_free(join_buf);
+ return NULL;
+ }
+ fkey = strdup( fkey );
+
+ } else if (!field && fkey) {
+ field = (char*)oilsIDLFindPath("/%s/links/%s/key", leftclass, fkey );
+ if (!field) {
+ osrfLogError(
+ OSRF_LOG_MARK,
+ "%s: JOIN failed. No link defined from %s.%s to %s",
+ MODULENAME,
+ leftclass,
+ fkey,
+ class
+ );
+ buffer_free(join_buf);
+ return NULL;
+ }
+ field = strdup( field );
+
+ } else if (!field && !fkey) {
+ osrfHash* _links = oilsIDLFindPath("/%s/links", leftclass);
+
+ int i = 0;
+ osrfStringArray* keys = osrfHashKeys( _links );
+ while ( (fkey = osrfStringArrayGetString(keys, i++)) ) {
+ fkey = strdup(osrfStringArrayGetString(keys, i++));
+ if ( !strcmp( (char*)oilsIDLFindPath("/%s/links/%s/class", leftclass, fkey), class) ) {
+ field = strdup( (char*)oilsIDLFindPath("/%s/links/%s/key", leftclass, fkey) );
+ break;
+ } else {
+ free(fkey);
+ }
+ }
+ osrfStringArrayFree(keys);
+
+ if (!field && !fkey) {
+ _links = oilsIDLFindPath("/%s/links", class);
+
+ i = 0;
+ keys = osrfHashKeys( _links );
+ while ( (field = osrfStringArrayGetString(keys, i++)) ) {
+ field = strdup(osrfStringArrayGetString(keys, i++));
+ if ( !strcmp( (char*)oilsIDLFindPath("/%s/links/%s/class", class, field), class) ) {
+ fkey = strdup( (char*)oilsIDLFindPath("/%s/links/%s/key", class, field) );
+ break;
+ } else {
+ free(field);
+ }
+ }
+ osrfStringArrayFree(keys);
+ }
+
+ if (!field && !fkey) {
+ osrfLogError(
+ OSRF_LOG_MARK,
+ "%s: JOIN failed. No link defined between %s and %s",
+ MODULENAME,
+ leftclass,
+ class
+ );
+ buffer_free(join_buf);
+ return NULL;
+ }
+
+ }
+
+ if (type) {
+ if ( !strcasecmp(type,"left") ) {
+ buffer_add(join_buf, " LEFT JOIN");
+ } else if ( !strcasecmp(type,"right") ) {
+ buffer_add(join_buf, " RIGHT JOIN");
+ } else if ( !strcasecmp(type,"full") ) {
+ buffer_add(join_buf, " FULL JOIN");
+ } else {
+ buffer_add(join_buf, " INNER JOIN");
+ }
+ } else {
+ buffer_add(join_buf, " INNER JOIN");
+ }
+
+ buffer_fadd(join_buf, " %s AS \"%s\" ON ( \"%s\".%s = \"%s\".%s", table, class, class, field, leftclass, fkey);
+
+ if (filter) {
+ if (filter_op) {
+ if (!strcasecmp("or",filter_op)) {
+ buffer_add( join_buf, " OR " );
+ } else {
+ buffer_add( join_buf, " AND " );
+ }
+ } else {
+ buffer_add( join_buf, " AND " );
+ }
+
+ char* jpred = searchWHERE( filter, idlClass, 0 );
+ buffer_fadd( join_buf, " %s", jpred );
+ free(jpred);
+ }
+
+ buffer_add(join_buf, " ) ");
+
+ if (join_filter) {
+ char* jpred = searchJOIN( join_filter, idlClass );
+ buffer_fadd( join_buf, " %s", jpred );
+ free(jpred);
+ }
+
+ free(type);
+ free(filter_op);
+ free(fkey);
+ free(field);
+ }
+
+ char* join_string = buffer_data(join_buf);
+ buffer_free(join_buf);
+ return join_string;
+}
+
+/*
+
+{ +class : { -or|-and : { field : { op : value }, ... }, ... }, ... }
+
+*/
+char* searchWHERE ( jsonObject* search_hash, osrfHash* meta, int opjoin_type ) {
growing_buffer* sql_buf = buffer_init(128);
- buffer_add(sql_buf, "SELECT");
+
+ jsonObjectNode* node = NULL;
int first = 1;
- if ( (_tmp = jsonObjectGetKey( order_hash, "select" )) ) {
+ jsonObjectIterator* search_itr = jsonNewObjectIterator( search_hash );
+ while ( (node = jsonObjectIteratorNext( search_itr )) ) {
- jsonObjectIterator* class_itr = jsonNewObjectIterator( _tmp );
- while ( (snode = jsonObjectIteratorNext( class_itr )) ) {
+ if (first) {
+ first = 0;
+ } else {
+ if (opjoin_type == 1) buffer_add(sql_buf, " OR ");
+ else buffer_add(sql_buf, " AND ");
+ }
+
+ if ( !strncmp("+",node->key,1) ) {
+ char* subpred = searchWHERE( node->item, osrfHashGet( oilsIDL(), node->key + 1 ), 0);
+ buffer_fadd(sql_buf, "( %s )", subpred);
+ free(subpred);
+ } else if ( !strcasecmp("-or",node->key) ) {
+ char* subpred = searchWHERE( node->item, meta, 1);
+ buffer_fadd(sql_buf, "( %s )", subpred);
+ free(subpred);
+ } else if ( !strcasecmp("-and",node->key) ) {
+ char* subpred = searchWHERE( node->item, meta, 0);
+ buffer_fadd(sql_buf, "( %s )", subpred);
+ free(subpred);
+ } else {
+
+ char* class = osrfHashGet(meta, "classname");
+ osrfHash* fields = osrfHashGet(meta, "fields");
+ osrfHash* field = osrfHashGet( fields, node->key );
+
+ if (!field) {
+ osrfLogError(
+ OSRF_LOG_MARK,
+ "%s: Attempt to reference non-existant column %s on table %s",
+ MODULENAME,
+ node->key,
+ osrfHashGet(meta, "tablename")
+ );
+ buffer_free(sql_buf);
+ return NULL;
+ }
- osrfHash* idlClass = osrfHashGet( idl, snode->key );
- if (!idlClass) continue;
- char* cname = osrfHashGet(idlClass, "classname");
+ char* subpred = searchPredicate( class, field, node->item );
+ buffer_add( sql_buf, subpred );
+ free(subpred);
+ }
+ }
- if (strcmp(core_class,snode->key)) continue;
+ jsonObjectIteratorFree(search_itr);
- jsonObjectIterator* select_itr = jsonNewObjectIterator( snode->item );
- while ( (node = jsonObjectIteratorNext( select_itr )) ) {
- osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), jsonObjectToSimpleString(node->item) );
- char* fname = osrfHashGet(field, "name");
+ char* pred = buffer_data(sql_buf);
+ buffer_free(sql_buf);
+
+ return pred;
+}
+
+char* SELECT (
+ /* method context */ osrfMethodContext* ctx,
+
+ /* SELECT */ jsonObject* selhash,
+ /* FROM */ jsonObject* join_hash,
+ /* WHERE */ jsonObject* search_hash,
+ /* ORDER BY */ jsonObject* order_hash,
+ /* LIMIT */ jsonObject* limit,
+ /* OFFSET */ jsonObject* offset,
+ /* flags */ int flags
+) {
+ // in case we don't get a select list
+ jsonObject* defaultselhash = NULL;
+
+ // general tmp objects
+ jsonObject* __tmp = NULL;
+ jsonObjectNode* selclass = NULL;
+ jsonObjectNode* selfield = NULL;
+ jsonObjectNode* snode = NULL;
+ jsonObjectNode* onode = NULL;
+ jsonObject* found = NULL;
+
+ char* string = NULL;
+ int first = 1;
+ int gfirst = 1;
+ //int hfirst = 1;
+
+ // return variable for the SQL
+ char* sql = NULL;
+
+ // the core search class
+ char* core_class = NULL;
+
+ // metadata about the core search class
+ osrfHash* core_meta = NULL;
+ osrfHash* core_fields = NULL;
+ osrfHash* idlClass = NULL;
+
+ // the query buffer
+ growing_buffer* sql_buf = buffer_init(128);
+ // temp buffer for the SELECT list
+ growing_buffer* select_buf = buffer_init(128);
+ growing_buffer* order_buf = buffer_init(128);
+ growing_buffer* group_buf = buffer_init(128);
+ growing_buffer* having_buf = buffer_init(128);
+
+ // punt if there's no core class
+ if (!join_hash || ( join_hash->type == JSON_HASH && !join_hash->size ))
+ return NULL;
+
+ // get the core class -- the only key of the top level FROM clause, or a string
+ if (join_hash->type == JSON_HASH) {
+ jsonObjectIterator* tmp_itr = jsonNewObjectIterator( join_hash );
+ snode = jsonObjectIteratorNext( tmp_itr );
+
+ core_class = strdup( snode->key );
+ join_hash = snode->item;
+
+ jsonObjectIteratorFree( tmp_itr );
+ snode = NULL;
+
+ } else if (join_hash->type == JSON_STRING) {
+ core_class = jsonObjectToSimpleString( join_hash );
+ join_hash = NULL;
+ }
+
+ // punt if we don't know about the core class
+ if (!(core_meta = osrfHashGet( oilsIDL(), core_class )))
+ return NULL;
+
+ core_fields = osrfHashGet(core_meta, "fields");
+
+ // if the select list is empty, or the core class field list is '*',
+ // build the default select list ...
+ if (!selhash) {
+ selhash = defaultselhash = jsonParseString( "{}" );
+ jsonObjectSetKey( selhash, core_class, jsonParseString( "[]" ) );
+ } else if ( (__tmp = jsonObjectGetKey( selhash, core_class )) && __tmp->type == JSON_STRING ) {
+ char* __x = jsonObjectToSimpleString( __tmp );
+ if (!strncmp( "*", __x, 1 )) {
+ jsonObjectRemoveKey( selhash, core_class );
+ jsonObjectSetKey( selhash, core_class, jsonParseString( "[]" ) );
+ }
+ free(__x);
+ }
+
+ // ... and if we /are/ building the default list, do that
+ if ( (__tmp = jsonObjectGetKey(selhash,core_class)) && !__tmp->size ) {
+
+ int i = 0;
+ char* field;
+
+ osrfStringArray* keys = osrfHashKeys( core_fields );
+ while ( (field = osrfStringArrayGetString(keys, i++)) ) {
+ if ( strncasecmp( "true", osrfHashGet( osrfHashGet( core_fields, field ), "virtual" ), 4 ) )
+ jsonObjectPush( __tmp, jsonNewObject( field ) );
+ }
+ osrfStringArrayFree(keys);
+ }
+
+ // Now we build the acutal select list
+ int sel_pos = 1;
+ jsonObject* is_agg = jsonObjectFindPath(selhash, "//aggregate");
+ first = 1;
+ gfirst = 1;
+ jsonObjectIterator* selclass_itr = jsonNewObjectIterator( selhash );
+ while ( (selclass = jsonObjectIteratorNext( selclass_itr )) ) {
+
+ // round trip through the idl, just to be safe
+ idlClass = osrfHashGet( oilsIDL(), selclass->key );
+ if (!idlClass) continue;
+ char* cname = osrfHashGet(idlClass, "classname");
+
+ // make sure the target relation is in the join tree
+ if (strcmp(core_class,cname)) {
+ if (!join_hash) continue;
+
+ if (join_hash->type == JSON_STRING) {
+ string = jsonObjectToSimpleString(join_hash);
+ found = strcmp(string,cname) ? NULL : jsonParseString("{\"1\":\"1\"}");
+ free(string);
+ } else {
+ found = jsonObjectFindPath(join_hash, "//%s", cname);
+ }
+
+ if (!found->size) {
+ jsonObjectFree(found);
+ continue;
+ }
+
+ jsonObjectFree(found);
+ }
+
+ // stitch together the column list ...
+ jsonObjectIterator* select_itr = jsonNewObjectIterator( selclass->item );
+ while ( (selfield = jsonObjectIteratorNext( select_itr )) ) {
+
+ char* __column = NULL;
+ char* __alias = NULL;
+
+ // ... if it's a sstring, just toss it on the pile
+ if (selfield->item->type == JSON_STRING) {
+
+ // again, just to be safe
+ char* _requested_col = jsonObjectToSimpleString(selfield->item);
+ osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), _requested_col );
+ free(_requested_col);
+
+ if (!field) continue;
+ __column = strdup(osrfHashGet(field, "name"));
+
+ if (first) {
+ first = 0;
+ } else {
+ buffer_add(select_buf, ",");
+ }
+
+ buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, __column, __column);
+
+ // ... but it could be an object, in which case we check for a Field Transform
+ } else {
+
+ __column = jsonObjectToSimpleString( jsonObjectGetKey( selfield->item, "column" ) );
+
+ // again, just to be safe
+ osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), __column );
if (!field) continue;
+ char* fname = osrfHashGet(field, "name");
if (first) {
first = 0;
} else {
- buffer_add(sql_buf, ",");
+ buffer_add(select_buf, ",");
+ }
+
+ if ((__tmp = jsonObjectGetKey( selfield->item, "alias" ))) {
+ __alias = jsonObjectToSimpleString( __tmp );
+ } else {
+ __alias = strdup(__column);
}
- buffer_fadd(sql_buf, " \"%s\".%s", cname, fname, cname, fname);
+ if (jsonObjectGetKey( selfield->item, "transform" )) {
+ free(__column);
+ __column = searchFieldTransform(cname, field, selfield->item);
+ buffer_fadd(select_buf, " %s AS \"%s\"", __column, __alias);
+ } else {
+ buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, fname, __alias);
+ }
}
+
+ if (is_agg->size || (flags & SELECT_DISTINCT)) {
+
+ if (!jsonBoolIsTrue( jsonObjectGetKey( selfield->item, "aggregate" ) )) {
+ if (gfirst) {
+ gfirst = 0;
+ } else {
+ buffer_add(group_buf, ",");
+ }
+
+ buffer_fadd(group_buf, " %d", sel_pos);
+ /*
+ } else if (is_agg = jsonObjectGetKey( selfield->item, "having" )) {
+ if (gfirst) {
+ gfirst = 0;
+ } else {
+ buffer_add(group_buf, ",");
+ }
+
+ __column = searchFieldTransform(cname, field, selfield->item);
+ buffer_fadd(group_buf, " %s", __column);
+ __column = searchFieldTransform(cname, field, selfield->item);
+ */
+ }
+ }
+
+ if (__column) free(__column);
+ if (__alias) free(__alias);
+
+ sel_pos++;
}
+ }
- if (first) buffer_add(sql_buf, " *");
+ if (is_agg) jsonObjectFree(is_agg);
- } else {
- buffer_add(sql_buf, " *");
+ char* col_list = buffer_data(select_buf);
+ buffer_free(select_buf);
+
+ // Put it all together
+ buffer_fadd(sql_buf, "SELECT %s FROM %s AS \"%s\" ", col_list, osrfHashGet(core_meta, "tablename"), core_class );
+ free(col_list);
+
+ // Now, walk the join tree and add that clause
+ if ( join_hash ) {
+ char* join_clause = searchJOIN( join_hash, core_meta );
+ buffer_add(sql_buf, join_clause);
+ free(join_clause);
}
- buffer_fadd(sql_buf, " FROM %s AS \"%s\" WHERE ", osrfHashGet(meta, "tablename"), core_class );
+ if ( search_hash ) {
+ buffer_add(sql_buf, " WHERE ");
+ // and it's on the the WHERE clause
+ char* pred = searchWHERE( search_hash, core_meta, 0 );
+ if (!pred) {
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Severe query error -- see error log for more details"
+ );
+ free(core_class);
+ buffer_free(sql_buf);
+ if (defaultselhash) jsonObjectFree(defaultselhash);
+ return NULL;
+ } else {
+ buffer_add(sql_buf, pred);
+ free(pred);
+ }
+ }
- char* pred;
first = 1;
- jsonObjectIterator* search_itr = jsonNewObjectIterator( search_hash );
- while ( (node = jsonObjectIteratorNext( search_itr )) ) {
- osrfHash* field = osrfHashGet( fields, node->key );
+ jsonObjectIterator* class_itr = jsonNewObjectIterator( order_hash );
+ while ( (snode = jsonObjectIteratorNext( class_itr )) ) {
- if (!field) {
- osrfLogError(
- OSRF_LOG_MARK,
- "%s: Attempt to reference non-existant column %s on table %s",
- MODULENAME,
- node->key,
- osrfHashGet(meta, "tablename")
- );
+ if (!jsonObjectGetKey(selhash,snode->key))
+ continue;
+
+ if ( snode->item->type == JSON_HASH ) {
+
+ jsonObjectIterator* order_itr = jsonNewObjectIterator( snode->item );
+ while ( (onode = jsonObjectIteratorNext( order_itr )) ) {
+
+ if (!oilsIDLFindPath( "/%s/fields/%s", snode->key, onode->key ))
+ continue;
+
+ char* direction = NULL;
+ if ( onode->item->type == JSON_HASH ) {
+ if ( jsonObjectGetKey( onode->item, "transform" ) ) {
+ string = searchFieldTransform(
+ snode->key,
+ oilsIDLFindPath( "/%s/fields/%s", snode->key, onode->key ),
+ onode->item
+ );
+ } else {
+ growing_buffer* field_buf = buffer_init(16);
+ buffer_fadd(field_buf, "\"%s\".%s", snode->key, onode->key);
+ string = buffer_data(field_buf);
+ buffer_free(field_buf);
+ }
+
+ if ( (__tmp = jsonObjectGetKey( onode->item, "direction" )) ) {
+ direction = jsonObjectToSimpleString(__tmp);
+ if (!strncasecmp(direction, "d", 1)) {
+ free(direction);
+ direction = " DESC";
+ } else {
+ free(direction);
+ direction = " ASC";
+ }
+ }
+
+ } else {
+ string = strdup(onode->key);
+ direction = jsonObjectToSimpleString(onode->item);
+ if (!strncasecmp(direction, "d", 1)) {
+ free(direction);
+ direction = " DESC";
+ } else {
+ free(direction);
+ direction = " ASC";
+ }
+ }
+
+ if (first) {
+ first = 0;
+ } else {
+ buffer_add(order_buf, ", ");
+ }
+
+ buffer_add(order_buf, string);
+ free(string);
+
+ if (direction) {
+ buffer_add(order_buf, direction);
+ }
+
+ }
+
+ } else if ( snode->item->type == JSON_ARRAY ) {
+
+ jsonObjectIterator* order_itr = jsonNewObjectIterator( snode->item );
+ while ( (onode = jsonObjectIteratorNext( order_itr )) ) {
+
+ char* _f = jsonObjectToSimpleString( onode->item );
+
+ if (!oilsIDLFindPath( "/%s/fields/%s", snode->key, _f))
+ continue;
+
+ if (first) {
+ first = 0;
+ } else {
+ buffer_add(order_buf, ", ");
+ }
+
+ buffer_add(order_buf, _f);
+ free(_f);
+
+ }
+
+ // IT'S THE OOOOOOOOOOOLD STYLE!
+ } else {
+ osrfLogError(OSRF_LOG_MARK, "%s: Possible SQL injection attempt; direct order by is not allowed", MODULENAME);
osrfAppSessionStatus(
ctx->session,
OSRF_STATUS_INTERNALSERVERERROR,
ctx->request,
"Severe query error -- see error log for more details"
);
+
+ free(core_class);
+ buffer_free(order_buf);
buffer_free(sql_buf);
+ if (defaultselhash) jsonObjectFree(defaultselhash);
return NULL;
}
- if (first) {
- first = 0;
- } else {
- buffer_add(sql_buf, " AND ");
+ }
+
+ string = buffer_data(group_buf);
+ buffer_free(group_buf);
+
+ if (strlen(string)) {
+ buffer_fadd(
+ sql_buf,
+ " GROUP BY %s",
+ string
+ );
+ }
+
+ free(string);
+
+ string = buffer_data(having_buf);
+ buffer_free(having_buf);
+
+ if (strlen(string)) {
+ buffer_fadd(
+ sql_buf,
+ " HAVING %s",
+ string
+ );
+ }
+
+ free(string);
+
+ string = buffer_data(order_buf);
+ buffer_free(order_buf);
+
+ if (strlen(string)) {
+ buffer_fadd(
+ sql_buf,
+ " ORDER BY %s",
+ string
+ );
+ }
+
+ free(string);
+
+ if ( limit ){
+ string = jsonObjectToSimpleString(limit);
+ buffer_fadd( sql_buf, " LIMIT %d", atoi(string) );
+ free(string);
+ }
+
+ if (offset) {
+ string = jsonObjectToSimpleString(offset);
+ buffer_fadd( sql_buf, " OFFSET %d", atoi(string) );
+ free(string);
+ }
+
+ buffer_add(sql_buf, ";");
+
+ sql = buffer_data(sql_buf);
+
+ free(core_class);
+ buffer_free(sql_buf);
+ if (defaultselhash) jsonObjectFree(defaultselhash);
+
+ return sql;
+
+}
+
+char* buildSELECT ( jsonObject* search_hash, jsonObject* order_hash, osrfHash* meta, osrfMethodContext* ctx ) {
+
+ osrfHash* fields = osrfHashGet(meta, "fields");
+ char* core_class = osrfHashGet(meta, "classname");
+
+ jsonObject* join_hash = jsonObjectGetKey( order_hash, "join" );
+
+ jsonObjectNode* node = NULL;
+ jsonObjectNode* snode = NULL;
+ jsonObjectNode* onode = NULL;
+ jsonObject* _tmp = NULL;
+ jsonObject* selhash = NULL;
+ jsonObject* defaultselhash = NULL;
+
+ growing_buffer* sql_buf = buffer_init(128);
+ growing_buffer* select_buf = buffer_init(128);
+
+ if ( !(selhash = jsonObjectGetKey( order_hash, "select" )) ) {
+ defaultselhash = jsonParseString( "{}" );
+ selhash = defaultselhash;
+ }
+
+ if ( !jsonObjectGetKey(selhash,core_class) ) {
+ jsonObjectSetKey( selhash, core_class, jsonParseString( "[]" ) );
+ jsonObject* flist = jsonObjectGetKey( selhash, core_class );
+
+ int i = 0;
+ char* field;
+
+ osrfStringArray* keys = osrfHashKeys( fields );
+ while ( (field = osrfStringArrayGetString(keys, i++)) ) {
+ if ( strcasecmp( "true", osrfHashGet( osrfHashGet( fields, field ), "virtual" ) ) )
+ jsonObjectPush( flist, jsonNewObject( field ) );
}
+ osrfStringArrayFree(keys);
+ }
- pred = searchPredicate( field, node->item);
- buffer_fadd( sql_buf, "%s", pred );
- free(pred);
+ int first = 1;
+ jsonObjectIterator* class_itr = jsonNewObjectIterator( selhash );
+ while ( (snode = jsonObjectIteratorNext( class_itr )) ) {
+
+ osrfHash* idlClass = osrfHashGet( oilsIDL(), snode->key );
+ if (!idlClass) continue;
+ char* cname = osrfHashGet(idlClass, "classname");
+
+ if (strcmp(core_class,snode->key)) {
+ if (!join_hash) continue;
+
+ jsonObject* found = jsonObjectFindPath(join_hash, "//%s", snode->key);
+ if (!found->size) {
+ jsonObjectFree(found);
+ continue;
+ }
+
+ jsonObjectFree(found);
+ }
+
+ jsonObjectIterator* select_itr = jsonNewObjectIterator( snode->item );
+ while ( (node = jsonObjectIteratorNext( select_itr )) ) {
+ osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), jsonObjectToSimpleString(node->item) );
+ char* fname = osrfHashGet(field, "name");
+
+ if (!field) continue;
+
+ if (first) {
+ first = 0;
+ } else {
+ buffer_add(select_buf, ",");
+ }
+
+ buffer_fadd(select_buf, " \"%s\".%s", cname, fname);
+ }
}
- jsonObjectIteratorFree(search_itr);
+ char* col_list = buffer_data(select_buf);
+ buffer_free(select_buf);
- if (order_hash) {
- char* string;
- if ( (_tmp = jsonObjectGetKey( jsonObjectGetKey( order_hash, "order_by" ), core_class ) ) ){
- string = jsonObjectToSimpleString(_tmp);
- buffer_fadd(
- sql_buf,
- " ORDER BY %s",
- string
+ buffer_fadd(sql_buf, "SELECT %s FROM %s AS \"%s\"", col_list, osrfHashGet(meta, "tablename"), core_class );
+
+ if ( join_hash ) {
+ char* join_clause = searchJOIN( join_hash, meta );
+ buffer_fadd(sql_buf, " %s", join_clause);
+ free(join_clause);
+ }
+
+ buffer_add(sql_buf, " WHERE ");
+
+ char* pred = searchWHERE( search_hash, meta, 0 );
+ if (!pred) {
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Severe query error -- see error log for more details"
);
+ buffer_free(sql_buf);
+ return NULL;
+ } else {
+ buffer_add(sql_buf, pred);
+ free(pred);
+ }
+
+ if (order_hash) {
+ char* string = NULL;
+ if ( (_tmp = jsonObjectGetKey( order_hash, "order_by" )) ){
+
+ growing_buffer* order_buf = buffer_init(128);
+
+ first = 1;
+ jsonObjectIterator* class_itr = jsonNewObjectIterator( _tmp );
+ while ( (snode = jsonObjectIteratorNext( class_itr )) ) {
+
+ if (!jsonObjectGetKey(selhash,snode->key))
+ continue;
+
+ if ( snode->item->type == JSON_HASH ) {
+
+ jsonObjectIterator* order_itr = jsonNewObjectIterator( snode->item );
+ while ( (onode = jsonObjectIteratorNext( order_itr )) ) {
+
+ if (!oilsIDLFindPath( "/%s/fields/%s", snode->key, onode->key ))
+ continue;
+
+ char* direction = NULL;
+ if ( onode->item->type == JSON_HASH ) {
+ if ( jsonObjectGetKey( onode->item, "transform" ) ) {
+ string = searchFieldTransform(
+ snode->key,
+ oilsIDLFindPath( "/%s/fields/%s", snode->key, onode->key ),
+ onode->item
+ );
+ } else {
+ growing_buffer* field_buf = buffer_init(16);
+ buffer_fadd(field_buf, "\"%s\".%s", snode->key, onode->key);
+ string = buffer_data(field_buf);
+ buffer_free(field_buf);
+ }
+
+ if ( (_tmp = jsonObjectGetKey( onode->item, "direction" )) ) {
+ direction = jsonObjectToSimpleString(_tmp);
+ if (!strncasecmp(direction, "d", 1)) {
+ free(direction);
+ direction = " DESC";
+ } else {
+ free(direction);
+ direction = " ASC";
+ }
+ }
+
+ } else {
+ string = strdup(onode->key);
+ direction = jsonObjectToSimpleString(onode->item);
+ if (!strncasecmp(direction, "d", 1)) {
+ free(direction);
+ direction = " DESC";
+ } else {
+ free(direction);
+ direction = " ASC";
+ }
+ }
+
+ if (first) {
+ first = 0;
+ } else {
+ buffer_add(order_buf, ", ");
+ }
+
+ buffer_add(order_buf, string);
+ free(string);
+
+ if (direction) {
+ buffer_add(order_buf, direction);
+ }
+
+ }
+
+ } else {
+ string = jsonObjectToSimpleString(snode->item);
+ buffer_add(order_buf, string);
+ free(string);
+ break;
+ }
+
+ }
+
+ string = buffer_data(order_buf);
+ buffer_free(order_buf);
+
+ if (strlen(string)) {
+ buffer_fadd(
+ sql_buf,
+ " ORDER BY %s",
+ string
+ );
+ }
+
free(string);
}
char* sql = buffer_data(sql_buf);
buffer_free(sql_buf);
+ if (defaultselhash) jsonObjectFree(defaultselhash);
return sql;
}
-jsonObject* doSearch ( osrfMethodContext* ctx, osrfHash* meta, jsonObject* params, int* err ) {
+int doJSONSearch ( osrfMethodContext* ctx ) {
+ OSRF_METHOD_VERIFY_CONTEXT(ctx);
+ osrfLogDebug(OSRF_LOG_MARK, "Recieved query request");
+
+ int err = 0;
+
+ // XXX for now...
+ dbhandle = writehandle;
+
+ jsonObject* hash = jsonObjectGetIndex(ctx->params, 0);
+
+ osrfLogDebug(OSRF_LOG_MARK, "Building SQL ...");
+ char* sql = SELECT(
+ ctx,
+ jsonObjectGetKey( hash, "select" ),
+ jsonObjectGetKey( hash, "from" ),
+ jsonObjectGetKey( hash, "where" ),
+ jsonObjectGetKey( hash, "order_by" ),
+ jsonObjectGetKey( hash, "limit" ),
+ jsonObjectGetKey( hash, "offset" ),
+ jsonBoolIsTrue(jsonObjectGetKey( hash, "distinct" )) ? SELECT_DISTINCT : 0
+ );
+
+ if (!sql) {
+ err = -1;
+ return err;
+ }
+
+ osrfLogDebug(OSRF_LOG_MARK, "%s SQL = %s", MODULENAME, sql);
+ dbi_result result = dbi_conn_query(dbhandle, sql);
+
+ if(result) {
+ osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
+
+ if (dbi_result_first_row(result)) {
+ /* JSONify the result */
+ osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
+
+ do {
+ osrfAppRespond( ctx, oilsMakeJSONFromResult( result ) );
+ } while (dbi_result_next_row(result));
+
+ } else {
+ osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
+ }
+
+ osrfAppRespondComplete( ctx, NULL );
+
+ /* clean up the query */
+ dbi_result_free(result);
+
+ } else {
+ err = -1;
+ osrfLogError(OSRF_LOG_MARK, "%s: Error with query [%s]", MODULENAME, sql);
+ osrfAppSessionStatus(
+ ctx->session,
+ OSRF_STATUS_INTERNALSERVERERROR,
+ "osrfMethodException",
+ ctx->request,
+ "Severe query error -- see error log for more details"
+ );
+ }
+
+ free(sql);
+ return err;
+}
+
+jsonObject* doFieldmapperSearch ( osrfMethodContext* ctx, osrfHash* meta, jsonObject* params, int* err ) {
// XXX for now...
dbhandle = writehandle;
osrfHash* links = osrfHashGet(meta, "links");
osrfHash* fields = osrfHashGet(meta, "fields");
char* core_class = osrfHashGet(meta, "classname");
+ char* pkey = osrfHashGet(meta, "primarykey");
jsonObject* _tmp;
jsonObject* obj;
osrfLogDebug(OSRF_LOG_MARK, "%s SQL = %s", MODULENAME, sql);
dbi_result result = dbi_conn_query(dbhandle, sql);
+ osrfHash* dedup = osrfNewHash();
jsonObject* res_list = jsonParseString("[]");
if(result) {
osrfLogDebug(OSRF_LOG_MARK, "Query returned with no errors");
/* JSONify the result */
osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row");
do {
- obj = oilsMakeJSONFromResult( result, meta );
- jsonObjectPush(res_list, obj);
+ obj = oilsMakeFieldmapperFromResult( result, meta );
+ int pkey_pos = atoi( osrfHashGet( osrfHashGet( fields, pkey ), "array_position" ) );
+ char* pkey_val = jsonObjectToSimpleString( jsonObjectGetIndex( obj, pkey_pos ) );
+ if ( osrfHashGet( dedup, pkey_val ) ) {
+ jsonObjectFree(obj);
+ } else {
+ osrfHashSet( dedup, pkey_val, pkey_val );
+ jsonObjectPush(res_list, obj);
+ }
} while (dbi_result_next_row(result));
} else {
osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
osrfHash* value_field = field;
- osrfHash* kid_idl = osrfHashGet(idl, osrfHashGet(kid_link, "class"));
+ osrfHash* kid_idl = osrfHashGet(oilsIDL(), osrfHashGet(kid_link, "class"));
if (!kid_idl) continue;
if (!(strcmp( osrfHashGet(kid_link, "reltype"), "has_many" ))) { // has_many
);
}
- jsonObject* kids = doSearch(ctx, kid_idl, fake_params, err);
+ jsonObject* kids = doFieldmapperSearch(ctx, kid_idl, fake_params, err);
if(*err) {
jsonObjectFree( fake_params );
osrfHashGet(
osrfHashGet(
osrfHashGet(
- idl,
+ oilsIDL(),
osrfHashGet(kid_link, "class")
),
"fields"
}
-jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
+jsonObject* oilsMakeFieldmapperFromResult( dbi_result result, osrfHash* meta) {
if(!(result && meta)) return jsonNULL;
jsonObject* object = jsonParseString("[]");
return object;
}
+jsonObject* oilsMakeJSONFromResult( dbi_result result ) {
+ if(!result) return jsonNULL;
+
+ jsonObject* object = jsonParseString("{}");
+
+ time_t _tmp_dt;
+ char dt_string[256];
+ struct tm gmdt;
+
+ int fmIndex;
+ int columnIndex = 1;
+ int attr;
+ unsigned short type;
+ const char* columnName;
+
+ /* cycle through the column list */
+ while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
+
+ osrfLogInternal(OSRF_LOG_MARK, "Looking for column named [%s]...", (char*)columnName);
+
+ fmIndex = -1; // reset the position
+
+ /* determine the field type and storage attributes */
+ type = dbi_result_get_field_type(result, columnName);
+ attr = dbi_result_get_field_attribs(result, columnName);
+
+ if (dbi_result_field_is_null(result, columnName)) {
+ jsonObjectSetKey( object, columnName, jsonNewObject(NULL) );
+ } else {
+
+ switch( type ) {
+
+ case DBI_TYPE_INTEGER :
+
+ if( attr & DBI_INTEGER_SIZE8 )
+ jsonObjectSetKey( object, columnName, jsonNewNumberObject(dbi_result_get_longlong(result, columnName)) );
+ else
+ jsonObjectSetKey( object, columnName, jsonNewNumberObject(dbi_result_get_long(result, columnName)) );
+ break;
+
+ case DBI_TYPE_DECIMAL :
+ jsonObjectSetKey( object, columnName, jsonNewNumberObject(dbi_result_get_double(result, columnName)) );
+ break;
+
+ case DBI_TYPE_STRING :
+ jsonObjectSetKey( object, columnName, jsonNewObject(dbi_result_get_string(result, columnName)) );
+ break;
+
+ case DBI_TYPE_DATETIME :
+
+ memset(dt_string, '\0', 256);
+ memset(&gmdt, '\0', sizeof(gmdt));
+ memset(&_tmp_dt, '\0', sizeof(_tmp_dt));
+
+ _tmp_dt = dbi_result_get_datetime(result, columnName);
+
+ localtime_r( &_tmp_dt, &gmdt );
+
+ if (!(attr & DBI_DATETIME_DATE)) {
+ strftime(dt_string, 255, "%T", &gmdt);
+ } else if (!(attr & DBI_DATETIME_TIME)) {
+ strftime(dt_string, 255, "%F", &gmdt);
+ } else {
+ strftime(dt_string, 255, "%FT%T%z", &gmdt);
+ }
+
+ jsonObjectSetKey( object, columnName, jsonNewObject(dt_string) );
+ break;
+
+ case DBI_TYPE_BINARY :
+ osrfLogError( OSRF_LOG_MARK,
+ "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
+ }
+ }
+ }
+
+ return object;
+}
# setup part
#-------------------------------------------------------------------------------
-my %org_cols = ( qw/id SysID name Name parent_ou Parent ou_type OrgUnitType shortname ShortName email Email phone Phone/ );
+my %org_cols = ( qw/id SysID name Name parent_ou Parent ou_type OrgUnitType shortname ShortName email Email phone Phone opac_visible OPACVisible/ );
-my @col_display_order = ( qw/id name shortname ou_type email phone parent_ou/ );
+my @col_display_order = ( qw/id name shortname ou_type email phone opac_visible parent_ou/ );
if (my $action = $cgi->param('action')) {
if ( $action eq 'Update' ) {
th($org_cols{email}),
td("<input type='text' name='email_$node' value=\"". $node->email() ."\">"),
);
+
print Tr(
th($org_cols{phone}),
td("<input type='text' name='phone_$node' value='". $node->phone() ."'>"),
);
print Tr(
+ th($org_cols{opac_visible} .'<span style="color:red">*</span>'),
+ td("<select name='opac_visible_$node'>".
+ do {
+ my $out = "<option value='t' ";
+ $out .= ($node->opac_visible =~ /^[y1t]+/i) ? "selected='yes'" : "";
+ $out .= ">True</option><option value='f' ";
+ $out .= ($node->opac_visible =~ /^[n0f]+/i) ? "selected='yes'" : "";
+ $out .= ">False</option>";
+ $out;
+ }."</select>"
+ ),
+ );
+
+ print Tr(
th($org_cols{parent_ou}),
td("<select name='parent_ou_$node'>".do{
my $out = '<option>-- Select One --</option>';
);
print Tr( "<td colspan='2'><input type='submit' name='action' value='Update'/></td>" );
- print "</table></form>";
+ print "</table><span style='color:red;'>*</span>".
+ "You must hide every OU you want hidden, not just an anscestor!</form>";
#-------------------------------------------------------------------------
# Hours of operation form
<desc xml:lang="en-US">The copy in question is not in an ideal status for deleting</desc>
</event>
+ <event code='1228' textcode='BIB_RECORD_DELETED'>
+ <desc xml:lang="en-US">The requested bib record is marked as deleted</desc>
+ </event>
+ <event code='1229' textcode='VOLUME_DELETED'>
+ <desc xml:lang="en-US">The requested volume is marked as deleted</desc>
+ </event>
+
<event code='1708' textcode='MONEY_COLLECTIONS_TRACKER_EXISTS'>
<desc xml:lang="en-US">A duplicate money.collections_tracker object already exists in the database</desc>
</event>
+ <event code='1709' textcode='MAX_HOLDS'>
+ <desc xml:lang="en-US">User has reached the maximum number of holds</desc>
+ </event>
+ <event code='1710' textcode='CONTAINER_EXISTS'>
+ <desc xml:lang="en-US">User has already created a bucket with the requested name</desc>
+ </event>
<event code='2000' textcode='BAD_PARAMS'>
use OpenILS::Utils::Fieldmapper;
use OpenSRF::Utils::SettingsClient;
-die "usage: perl org_tree_js.pl <bootstrap_config> <output_file>" unless $ARGV[1];
+die "usage: perl org_tree_html_options.pl <bootstrap_config> <output_file>" unless $ARGV[1];
OpenSRF::System->bootstrap_client(config_file => $ARGV[0]);
open FILE, ">$ARGV[1]";
sub print_option {
my $node = shift;
+ return unless ($node->opac_visible =~ /^[y1t]+/i);
my $depth = $node->ou_type - 1;
my $sname = $node->shortname;
my $name = $node->name;
my @array;
for my $o (@$tree) {
- my ($i,$t,$p,$n) = ($o->id,$o->ou_type,$o->parent_ou,$o->name);
- push @array, "[$i,$t,$p,\"$n\"]";
+ my ($i,$t,$p,$n,$v) = ($o->id,$o->ou_type,$o->parent_ou,$o->name,$o->opac_visible);
+ push @array, "[$i,$t,$p,\"$n\",\"$v\"]";
}
$pile .= join ',', @array;
$pile .= <<JS;
var rec_type = {
BKS : { Type : /[at]{1}/, BLvl : /[acdm]{1}/ },
- SER : { Type : /[a]{1}/, BLvl : /[bs]{1}/ },
- VIS : { Type : /[gkro]{1}/, BLvl : /[abcdms]{1}/ },
- MIX : { Type : /[p]{1}/, BLvl : /[cd]{1}/ },
- MAP : { Type : /[ef]{1}/, BLvl : /[abcdms]{1}/ },
- SCO : { Type : /[cd]{1}/, BLvl : /[abcdms]{1}/ },
- REC : { Type : /[ij]{1}/, BLvl : /[abcdms]{1}/ },
- COM : { Type : /[m]{1}/, BLvl : /[abcdms]{1}/ }
+ SER : { Type : /[a]{1}/, BLvl : /[bsi]{1}/ },
+ VIS : { Type : /[gkro]{1}/, BLvl : /[abcdmsi]{1}/ },
+ MIX : { Type : /[p]{1}/, BLvl : /[cdi]{1}/ },
+ MAP : { Type : /[ef]{1}/, BLvl : /[abcdmsi]{1}/ },
+ SCO : { Type : /[cd]{1}/, BLvl : /[abcdmsi]{1}/ },
+ REC : { Type : /[ij]{1}/, BLvl : /[abcdmsi]{1}/ },
+ COM : { Type : /[m]{1}/, BLvl : /[abcdmsi]{1}/ }
};
var ff_pos = {
var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
-/* statelib has some special circ rules */
-
-
if( isOrgDescendent('STATELIB', copy.circ_lib.id) ) {
+ if( circMod == 'book' )
+ result.durationRule = '35_days_1_renew';
if(isTrue(copy.ref))
result.durationRule = '14_days_2_renew';
-} else if( isOrgDescendent('NCLS', copy.circ_lib.id) && circMod == 'dvd' )
+} else if( isOrgDescendent('NCLS', copy.circ_lib.id) && ( circMod == 'dvd' || circMod == 'video' ) )
result.recurringFinesRule = '10_cent_per_day';
+/*
else if( isOrgDescendent('LEE', copy.circ_lib.id) && circMod == 'video' )
result.recurringFinesRule = '50_cent_per_day';
else if( isOrgDescendent('ECGR', copy.circ_lib.id) && circMod == 'video' )
result.recurringFinesRule = '50_cent_per_day';
+
+else if( isOrgDescendent('OHOOP', copy.circ_lib.id) && circMod == 'video' )
+ result.recurringFinesRule = '50_cent_per_day';
+
+else if( isOrgDescendent('ARL', copy.circ_lib.id) && circMod == 'video' )
+ result.recurringFinesRule = '50_cent_per_day';
+ */
checkDurationExceptions();
-log_debug(result.durationRule + ' : ' + result.recurringFinesRule + ' : ' + result.maxFine );
+log_info('final duration results: ' + result.durationRule + ' : ' + result.recurringFinesRule + ' : ' + result.maxFine );
} go();
}
}
-
SIPMediaType : '005',
magneticMedia : 'f',
durationRule : '7_days_0_renew',
- recurringFinesRule : '10_cent_per_day',
+ recurringFinesRule : '50_cent_per_day',
maxFine : 'overdue_mid'
},
/* Set up rules for legacy types */
CIRC_MOD_MAP['DEPOSIT'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['E-AUDIO'] = CIRC_MOD_MAP['book'];
-CIRC_MOD_MAP['EQUIP'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['FACNEWBK'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['MAG-CIRC'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['MAG-NOCIRC'] = CIRC_MOD_MAP['book'];
-CIRC_MOD_MAP['NEW-AV'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['NEW-BOOK'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['NEWSPAPER'] = CIRC_MOD_MAP['book'];
-CIRC_MOD_MAP['NILS-ITEM'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['OUTREACH'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['PAMPHLET'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['PAPERBACK'] = CIRC_MOD_MAP['book'];
-CIRC_MOD_MAP['REALIA'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['RESERVE'] = CIRC_MOD_MAP['book'];
CIRC_MOD_MAP['STATE-BOOK'] = {
SIPMediaType : '001',
provided circ_modifier, use that config. Otherwise fall back on the MARC item type
----------------------------------------------------------------------------------- */
var marcType = getMARCItemType();
- var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
var itemForm = (marcXMLDoc) ? extractFixedField(marcXMLDoc,'Form') : "";
+ //var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+ var circMod = copy.circ_modifier;
- var config;
-
- if( circMod && CIRC_MOD_MAP[circMod] ) {
- /* if we have a config for the given circ_modifier, use it */
- log_debug("a circ_mod config exists for the copy: " + circMod);
- config = CIRC_MOD_MAP[circMod];
-
- } else {
+ var config = null;
+
+ if( circMod ) {
+ config = CIRC_MOD_MAP[circMod];
+ if(!config)
+ config = CIRC_MOD_MAP[circMod.toLowerCase()]
+ if(config)
+ log_info("a circ_mod config exists for the copy with mod: " + circMod);
+ }
+
+ if(!config) {
/* otherwise, fall back on the MARC item type */
-
- if( circMod ) {
- log_debug("no circ_mod config found for "
- +circMod+", falling back to MARC");
- }
+ if( circMod )
+ log_info("no circ_mod config found for " +circMod+", falling back to MARC");
config = MARC_ITEM_TYPE_MAP[marcType];
}
return false;
}
+/* returns the number of unfulfilled holds open on this user */
+function userHoldCount(userid) {
+ var key = scratchKey();
+ __OILS_FUNC_userHoldCount(scratchPad(key), userid);
+ return getScratch(key);
+}
+
function hasCommonAncestor( org1, org2, depth ) {
var key = scratchKey();
__OILS_FUNC_hasCommonAncestor(scratchPad(key), org1, org2, depth);
if(patron) {
str += ' Patron=' + patron.id;
- str += ', Patron Username='+ patron.usrname;
- str += ', Patron Profile Group='+ patronProfile;
- str += ', Patron Fines=' + patronFines;
- str += ', Patron OverdueCount=' + patronOverdueCount;
- str += ', Patron Items Out=' + patronItemsOut;
+ str += ', Patron_Username='+ patron.usrname;
+ str += ', Patron_Profile Group='+ patronProfile;
+ str += ', Patron_Fines=' + patronFines;
+ str += ', Patron_OverdueCount=' + patronOverdueCount;
+ str += ', Patron_Items Out=' + patronItemsOut;
try {
- str += ', Patron Barcode=' + patron.card.barcode;
- str += ', Patron Library=' + patron.home_ou.name;
+ str += ', Patron_Barcode=' + patron.card.barcode;
+ str += ', Patron_Library=' + patron.home_ou.name;
} catch(e) {}
}
if(copy) {
str += ', Copy=' + copy.id;
- str += ', Copy Barcode=' + copy.barcode;
- str += ', Copy status=' + copyStatus;
+ str += ', Copy_Barcode=' + copy.barcode;
+ str += ', Copy_status=' + copyStatus;
+ str += (copy.circ_modifier) ? ', Circ_Mod=' + copy.circ_modifier : '';
try {
- str += ', Circ Lib=' + copy.circ_lib.shortname;
- str += ', Copy location=' + copy.location.name;
+ str += ', Circ_Lib=' + copy.circ_lib.shortname;
+ str += ', Copy_location=' + copy.location.name;
} catch(e) {}
}
if(title) str += ', Record=' + title.id;
if(recDescriptor) {
- str += ', Record Descriptor=' + recDescriptor.id;
- str += ', Item Type=' + recDescriptor.item_type;
- str += ', Item Form=' + recDescriptor.item_form;
- str += ', Item Lang=' + recDescriptor.item_lang;
- str += ', Item Audience=' + recDescriptor.audience;
+ str += ', Record_Descriptor=' + recDescriptor.id;
+ str += ', Item_Type=' + recDescriptor.item_type;
+ str += ', Item_Form=' + recDescriptor.item_form;
+ str += ', Item_Lang=' + recDescriptor.item_lang;
+ str += ', Item_Audience=' + recDescriptor.audience;
}
- str += ' Is Renewal: ' + ( (isTrue(isRenewal)) ? "yes" : "no" );
- str += ' Is Precat: ' + ( (isTrue(isPrecat)) ? "yes" : "no" );
- str += (holdRequestLib) ? ' Hold request lib is ' + holdRequestLib.shortname : '';
+ str += ', Is_Renewal: ' + ( (isTrue(isRenewal)) ? "yes" : "no" );
+ str += ', Is_Precat: ' + ( (isTrue(isPrecat)) ? "yes" : "no" );
+ str += (holdRequestLib) ? ', Hold_request_lib=' + holdRequestLib.shortname : '';
log_info(str);
}
load_lib('circ/circ_lib.js');
log_vars('circ_permit_hold');
+
+
+/* non-staff members are allowed 50 open holds at most */
+if( ! isGroupDescendant('Staff', patronProfile) ) {
+ var count = userHoldCount(patron.id);
+ log_info("patron has " + count + " open holds");
+ if( count >= 50 )
+ result.events.push('MAX_HOLDS');
+}
+
+
if( isTrue(patron.barred) )
result.events.push('PATRON_BARRED');
mod == 'music' ||
mod == 'audiobook' ||
mod == 'av' ||
+ mod == 'new-av' ||
mod == 'cd' ||
mod == 'kit' ||
mod == 'dvd' ||
'INTERNAL_SERVER_ERROR', payload => 'TOO MANY NON CATS');
}
+ if( $args->{barcode} ) {
+ my( $c, $e ) = $U->fetch_copy_by_barcode($args->{barcode});
+ return $e if $e;
+ }
+
return $U->simplereq(
'open-ils.circ', 'open-ils.circ.checkout', $authtoken, $args );
}
api_name => "open-ils.actor.patron.settings.retrieve",
);
sub user_settings {
- my( $self, $client, $user_session, $uid ) = @_;
+ my( $self, $client, $user_session, $uid, $setting ) = @_;
my( $staff, $user, $evt ) =
$apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
'open-ils.cstore',
'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
- return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
+ my $settings = { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
+
+ return $$settings{$setting} if $setting;
+ return $settings;
}
);
sub get_my_org_path {
- my( $self, $client, $user_session, $org_id ) = @_;
- my $user_obj = $apputils->check_user_session($user_session);
- if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
+ my( $self, $client, $auth, $org_id ) = @_;
+ my $e = new_editor(authtoken=>$auth);
+ return $e->event unless $e->checkauth;
+ $org_id = $e->requestor->ws_ou unless defined $org_id;
return $apputils->simple_scalar_request(
"open-ils.storage",
sub user_transaction_retrieve {
my( $self, $client, $login_session, $bill_id ) = @_;
+ # XXX I think I'm deprecated... make sure
+
my $trans = $apputils->simple_scalar_request(
"open-ils.cstore",
"open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
order_by => { mbt => 'xact_start DESC' },
}
- ]
+ ],
+ {substream => 1}
) };
$e->rollback;
return $org->shortname;
}
+__PACKAGE__->register_method(
+ method => 'session_safe_token',
+ api_name => 'open-ils.actor.session.safe_token',
+ signature => q/
+ Returns a hashed session ID that is safe for export to the world.
+ This safe token will expire after 1 hour of non-use.
+ @param auth Active authentication token
+ /
+);
+
+sub session_safe_token {
+ my( $self, $conn, $auth ) = @_;
+ my $e = new_editor(authtoken=>$auth);
+ return undef unless $e->checkauth;
+
+ my $safe_token = md5_hex($auth);
+
+ $cache ||= OpenSRF::Utils::Cache->new("global", 0);
+
+ # Add more like the following if needed...
+ $cache->put_cache(
+ "safe-token-home_lib-shortname-$safe_token",
+ $e->retrieve_actor_org_unit(
+ $e->requestor->home_ou
+ )->shortname,
+ 60 * 60
+ );
+
+ return $safe_token;
+}
+
+
+__PACKAGE__->register_method(
+ method => 'safe_token_home_lib',
+ api_name => 'open-ils.actor.safe_token.home_lib.shortname',
+ signature => q/
+ Returns the home library shortname from the session
+ asscociated with a safe token from generated by
+ open-ils.actor.session.safe_token.
+ @param safe_token Active safe token
+ /
+);
+
+sub safe_token_home_lib {
+ my( $self, $conn, $safe_token ) = @_;
+
+ $cache ||= OpenSRF::Utils::Cache->new("global", 0);
+ return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
+}
+
__PACKAGE__->register_method(
$bucket->clear_id;
- $logger->debug("creating bucket: " . Dumper($bucket));
+ my $evt = OpenILS::Event->new('CONTAINER_EXISTS',
+ payload => [$class, $bucket->owner, $bucket->btype, $bucket->name]);
+ my $search = {name => $bucket->name, owner => $bucket->owner, btype => $bucket->btype};
- my $stat;
+ my $obj;
if( $class eq 'copy' ) {
+ return $evt if $e->search_container_copy_bucket($search)->[0];
return $e->event unless
- $stat = $e->create_container_copy_bucket($bucket);
+ $obj = $e->create_container_copy_bucket($bucket);
}
if( $class eq 'callnumber' ) {
+ return $evt if $e->search_container_call_number_bucket($search)->[0];
return $e->event unless
- $stat = $e->create_container_call_number_bucket($bucket);
+ $obj = $e->create_container_call_number_bucket($bucket);
}
if( $class eq 'biblio' ) {
+ return $evt if $e->search_container_biblio_record_entry_bucket($search)->[0];
return $e->event unless
- $stat = $e->create_container_biblio_record_entry_bucket($bucket);
+ $obj = $e->create_container_biblio_record_entry_bucket($bucket);
}
if( $class eq 'user') {
+ return $evt if $e->search_container_user_bucket($search)->[0];
return $e->event unless
- $stat = $e->create_container_user_bucket($bucket);
+ $obj = $e->create_container_user_bucket($bucket);
}
$e->commit;
- return $stat->id;
+ return $obj->id;
}
Returns the new bucket object
NOTES
+# XXX pretty sure no one actually uses this method,
+# (see open-ils.actor.container.full_delete) -- should probably deprecate it
sub bucket_delete {
my( $self, $client, $authtoken, $class, $bucketid ) = @_;
my( $bucket, $evt );
return $evt if $evt;
if( $bucket->owner ne $e->requestor->id ) {
- return $e->event unless $e->allowed('DELETE_CONTAINER_ITEM');
+ my $owner = $e->retrieve_actor_user($bucket->owner)
+ or return $e->die_event;
+ return $e->event unless $e->allowed('DELETE_CONTAINER_ITEM', $owner->home_ou);
}
my $stat;
return $evt if $evt;
if( $container->owner ne $e->requestor->id ) {
- return $e->event unless $e->allowed('DELETE_CONTAINER');
+ my $owner = $e->retrieve_actor_user($container->owner)
+ or return $e->die_event;
+ return $e->event unless $e->allowed('DELETE_CONTAINER', $owner->home_ou);
}
my $items;
$u->start_mods_batch( $record->marc );
my $mods = $u->finish_mods_batch();
$mods->doc_id($record->id);
+ $mods->tcn($record->tcn_value);
return $mods;
}
sub retrieve_marc_template {
my( $self, $client, $type ) = @_;
-
return $marctemplates{$type} if defined($marctemplates{$type});
$marctemplates{$type} = _load_marc_template($type);
return $marctemplates{$type};
}
-sub _load_marc_template {
- my $type = shift;
+__PACKAGE__->register_method(
+ method => 'fetch_marc_template_types',
+ api_name => 'open-ils.cat.marc_template.types.retrieve'
+);
+
+my $marc_template_files;
+
+sub fetch_marc_template_types {
+ my( $self, $conn ) = @_;
+ __load_marc_templates();
+ return [ keys %$marc_template_files ];
+}
+sub __load_marc_templates {
+ return if $marc_template_files;
if(!$conf) { $conf = OpenSRF::Utils::SettingsClient->new; }
- my $template = $conf->config_value(
- "apps", "open-ils.cat","app_settings", "marctemplates", $type );
- warn "Opening template file $template\n";
+ $marc_template_files = $conf->config_value(
+ "apps", "open-ils.cat","app_settings", "marctemplates" );
+ $logger->info("Loaded marc templates: " . Dumper($marc_template_files));
+}
+
+sub _load_marc_template {
+ my $type = shift;
+
+ __load_marc_templates();
+
+ my $template = $$marc_template_files{$type};
open( F, $template ) or
throw OpenSRF::EX::ERROR ("Unable to open MARC template file: $template : $@");
my $name = shift;
$logger->debug("searching for bib source: $name");
- $__bib_sources = new_editor()->retrieve_all_config_bib_source()
- unless $__bib_sources;
+ fetch_bib_sources();
my ($s) = grep { lc($_->source) eq lc($name) } @$__bib_sources;
}
+__PACKAGE__->register_method(
+ method => 'fetch_bib_sources',
+ api_name => 'open-ils.cat.bib_sources.retrieve.all');
+
+sub fetch_bib_sources {
+ $__bib_sources = new_editor()->retrieve_all_config_bib_source()
+ unless $__bib_sources;
+ return $__bib_sources;
+}
+
+
__PACKAGE__->register_method(
method => "create_record_xml",
sub biblio_record_replace_marc {
my( $self, $conn, $auth, $recid, $newxml, $source ) = @_;
- my $e = OpenILS::Utils::Editor->new(authtoken=>$auth, xact=>1);
+ warn "Updating MARC with xml\n$newxml\n";
- return $e->event unless $e->checkauth;
- return $e->event unless $e->allowed('CREATE_MARC');
+ #my $e = OpenILS::Utils::Editor->new(authtoken=>$auth, xact=>1);
+ my $e = new_editor(authtoken=>$auth, xact=>1);
+
+ return $e->die_event unless $e->checkauth;
+ return $e->die_event unless $e->allowed('CREATE_MARC');
my $rec = $e->retrieve_biblio_record_entry($recid)
- or return $e->event;
+ or return $e->die_event;
my $fixtcn = 1 if $self->api_name =~ /replace/o;
# If we're not updating the TCN, all we care about it the marcdoc
my $override = $self->api_name =~ /override/;
+
my $storage = OpenSRF::AppSession->create('open-ils.storage');
+ # XXX should .update even bother with the tcn_info if it's not going to replace it?
+ # there is the potential for returning a TCN_EXISTS event, even though no replacement happens
+
my( $tcn, $tsource, $marcdoc, $evt) =
- _find_tcn_info($e->session, $newxml, $override, $recid);
+ _find_tcn_info($storage, $newxml, $override, $recid);
return $evt if $evt;
sub biblio_record_xml_import {
- my( $self, $client, $authtoken, $xml, $source) = @_;
+ my( $self, $client, $authtoken, $xml, $source, $auto_tcn) = @_;
my $override = 1 if $self->api_name =~ /override/;
my $session = $apputils->start_db_session();
- ( $tcn, $tcn_source, $marcdoc, $evt ) = _find_tcn_info($session, $xml, $override);
- return $evt if $evt;
+ if( $auto_tcn ) {
+ # auto_tcn forces a blank TCN value so the DB will have to generate one for us
+ $marcdoc = __make_marc_doc($xml);
+ } else {
+ ( $tcn, $tcn_source, $marcdoc, $evt ) = _find_tcn_info($session, $xml, $override);
+ return $evt if $evt;
+ }
- $logger->activity("user ".$requestor->id.
+ $logger->info("user ".$requestor->id.
" creating new biblio entry with tcn=$tcn and tcn_source $tcn_source");
my $record = Fieldmapper::biblio::record_entry->new;
return undef;
}
+sub __make_marc_doc {
+ my $xml = shift;
+ my $marcxml = XML::LibXML->new->parse_string( $xml );
+ $marcxml->documentElement->setNamespace(
+ "http://www.loc.gov/MARC21/slim", "marc", 1 );
+ return $marcxml;
+}
+
sub _find_tcn_info {
my $session = shift;
my $existing_rec = shift || 0;
# parse the XML
- my $marcxml = XML::LibXML->new->parse_string( $xml );
- $marcxml->documentElement->setNamespace(
- "http://www.loc.gov/MARC21/slim", "marc", 1 );
+ my $marcxml = __make_marc_doc($xml);
+# my $marcxml = XML::LibXML->new->parse_string( $xml );
+# $marcxml->documentElement->setNamespace(
+# "http://www.loc.gov/MARC21/slim", "marc", 1 );
my $xpath = '//marc:controlfield[@tag="001"]';
my $tcn = $marcxml->documentElement->findvalue($xpath);
# if we're overriding, try to find a different TCN to use
if( $override ) {
- $logger->activity("tcn value $tcn already exists, attempting to override");
+ # XXX Create ALLOW_ALT_TCN permission check support
+
+ $logger->info("tcn value $tcn already exists, attempting to override");
if(!$tcn) {
return (
}
-
-
-# XXX deprecated. Remove me.
-
-=head deprecated
-
-__PACKAGE__->register_method(
- method => "biblio_record_tree_retrieve",
- api_name => "open-ils.cat.biblio.record.tree.retrieve",
-);
-
-sub biblio_record_tree_retrieve {
-
- my( $self, $client, $recordid ) = @_;
-
- my $name = "open-ils.storage.direct.biblio.record_entry.retrieve";
- my $session = OpenSRF::AppSession->create( "open-ils.storage" );
- my $request = $session->request( $name, $recordid );
- my $marcxml = $request->gather(1);
-
- if(!$marcxml) {
- throw OpenSRF::EX::ERROR
- ("No record in database with id $recordid");
- }
-
- $session->disconnect();
- $session->kill_me();
-
- warn "turning into nodeset\n";
- my $nodes = OpenILS::Utils::FlatXML->new()->xml_to_nodeset( $marcxml->marc );
- warn "turning nodeset into tree\n";
- my $tree = $utils->nodeset2tree( $nodes->nodeset );
-
- $tree->owner_doc( $marcxml->id() );
-
- warn "returning tree\n";
-
- return $tree;
-}
-=cut
-
-
-=head deprecate
-__PACKAGE__->register_method(
- method => "biblio_record_xml_update",
- api_name => "open-ils.cat.biblio.record.xml.update",
- argc => 3, #(session_id, biblio_tree )
- notes => <<' NOTES');
- Updates the XML of a biblio record entry
- @param authtoken The session token for the staff updating the record
- @param docID The record entry ID to update
- @param xml The new MARCXML record
- NOTES
-
-sub biblio_record_xml_update {
-
- my( $self, $client, $user_session, $id, $xml ) = @_;
-
- my $user_obj = $apputils->check_user_session($user_session);
-
- if($apputils->check_user_perms(
- $user_obj->id, $user_obj->home_ou, "UPDATE_MARC")) {
- return OpenILS::Perm->new("UPDATE_MARC");
- }
-
- $logger->activity("user ".$user_obj->id." updating biblio record $id");
-
-
- my $session = OpenILS::Application::AppUtils->start_db_session();
-
- warn "Retrieving biblio record from storage for update\n";
-
- my $req1 = $session->request(
- "open-ils.storage.direct.biblio.record_entry.batch.retrieve", $id );
- my $biblio = $req1->gather(1);
-
- warn "retrieved doc $id\n";
-
- my $doc = XML::LibXML->new->parse_string($xml);
- throw OpenSRF::EX::ERROR ("Invalid XML in record update: $xml") unless $doc;
-
- $biblio->marc( entityize( $doc->documentElement->toString ) );
- $biblio->editor( $user_obj->id );
- $biblio->edit_date( 'now' );
-
- warn "Sending updated doc $id to db with xml ".$biblio->marc. "\n";
-
- my $req = $session->request(
- "open-ils.storage.direct.biblio.record_entry.update", $biblio );
-
- $req->wait_complete;
- my $status = $req->recv();
- if( !$status || $status->isa("Error") || ! $status->content) {
- OpenILS::Application::AppUtils->rollback_db_session($session);
- if($status->isa("Error")) { throw $status ($status); }
- throw OpenSRF::EX::ERROR ("Error updating biblio record");
- }
- $req->finish();
-
- # Send the doc to the wormer for wormizing
- warn "Starting worm session\n";
-
- my $success = 0;
- my $wresp;
-
- my $wreq = $session->request( "open-ils.worm.wormize.biblio", $id );
-
- my $w = 0;
- try {
- $w = $wreq->gather(1);
-
- } catch Error with {
- my $e = shift;
- warn "wormizing failed, rolling back\n";
- OpenILS::Application::AppUtils->rollback_db_session($session);
-
- if($e) { throw $e ($e); }
- throw OpenSRF::EX::ERROR ("Wormizing Failed for $id" );
- };
-
- warn "Committing db session...\n";
- OpenILS::Application::AppUtils->commit_db_session( $session );
-
-# $client->respond_complete($tree);
-
- warn "Done wormizing\n";
-
- #use Data::Dumper;
- #warn "Returning tree:\n";
- #warn Dumper $tree;
-
- return $biblio;
-
-}
-
-=cut
-
-
-
__PACKAGE__->register_method(
method => "biblio_record_record_metadata",
api_name => "open-ils.cat.biblio.record.metadata.retrieve",
$editor->update_asset_call_number($vol) or return $editor->event;
}
- # then delete the record this volume points to
- my $rec = $editor->retrieve_biblio_record_entry($vol->record)
- or return $editor->event;
-
- unless( $U->is_true($rec->deleted) ) {
- $rec->deleted('t');
- $rec->active('f');
- $editor->update_biblio_record_entry($rec) or return $editor->event;
- }
+ my $evt = delete_rec($editor, $vol->record);
+ return $evt if $evt;
} else {
return OpenILS::Event->new('TITLE_LAST_COPY', payload => $vol->record );
return undef;
}
+# marks a record as deleted
+sub delete_rec {
+ my( $editor, $rec_id ) = @_;
+
+ my $rec = $editor->retrieve_biblio_record_entry($rec_id)
+ or return $editor->event;
+
+ return undef if $U->is_true($rec->deleted);
+
+ $rec->deleted('t');
+ $rec->active('f');
+ $rec->editor( $editor->requestor->id );
+ $rec->edit_date('now');
+ $editor->update_biblio_record_entry($rec) or return $editor->event;
+
+ return undef;
+}
+
sub delete_copy {
my( $editor, $override, $vol, $copy ) = @_;
+ return $editor->event unless
+ $editor->allowed('DELETE_COPY',copy_perm_org($vol, $copy));
+
my $stat = $U->copy_status($copy->status)->id;
unless($override) {
return OpenILS::Event->new('ITEM_BARCODE_EXISTS') if @$existing;
+ # see if the volume this copy references is marked as deleted
+ my $evol = $editor->retrieve_asset_call_number($copy->call_number)
+ or return $editor->event;
+ return OpenILS::Event->new('VOLUME_DELETED', vol => $evol->id)
+ if $U->is_true($evol->deleted);
+
my $evt;
my $org = (ref $copy->circ_lib) ? $copy->circ_lib->id : $copy->circ_lib;
return $evt if ( $evt = org_cannot_have_vols($editor, $org) );
return $evt if ( $evt = org_cannot_have_vols($editor, $vol->owning_lib) );
+ # see if the record this volume references is marked as deleted
+ my $rec = $editor->retrieve_biblio_record_entry($vol->record)
+ or return $editor->event;
+ return OpenILS::Event->new('BIB_RECORD_DELETED', rec => $rec->id)
+ if $U->is_true($rec->deleted);
+
# first lets see if there are any collisions
my $vols = $editor->search_asset_call_number( {
owning_lib => $vol->owning_lib,
my $label = undef;
if(@$vols) {
+ # we've found an exising volume
if($override) {
$label = $vol->label;
} else {
}
}
- # create a temp label so we can create the volume, then de-dup it
- $vol->label( '__SYSTEM_TMP_'.time) if $label;
+ # create a temp label so we can create the new volume,
+ # then de-dup it with the existing volume
+ $vol->label( "__SYSTEM_TMP_$$".time) if $label;
$vol->creator($editor->requestor->id);
$vol->create_date('now');
my $vols = $e->batch_retrieve_asset_call_number($vol_ids);
my @seen;
+ my @rec_ids;
+
for my $vol (@$vols) {
# if we've already looked at this volume, go to the next
# take note of the fact that we've looked at this set of volumes
push( @seen, $_->id ) for @all;
+ push( @rec_ids, $_->record ) for @all;
# for each volume, see if there are any copies that have a
# remote circ_lib (circ_lib != vol->owning_lib and != $o_lib ).
}
# Now see if any empty records need to be deleted after all of this
- for(@all) {
- $evt = remove_empty_objects($e, $override, $_);
+
+ for(@rec_ids) {
+ $logger->debug("merge: seeing if we should delete record $_...");
+ $evt = delete_rec($e, $_) if title_is_empty($e, $_);
return $evt if $evt;
- }
+ }
+
+ #for(@all) {
+ # $evt = remove_empty_objects($e, $override, $_);
+ #}
}
$logger->info("merge: transfer succeeded");
$vol->owning_lib($org_id);
$vol->label($label);
$vol->record($record_id);
- $vol->creator($e->requestor->id);
- $vol->create_date('now');
- $vol->editor($e->requestor->id);
- $vol->edit_date('now');
- $e->create_asset_call_number($vol) or return $e->die_event;
+ #$vol->creator($e->requestor->id);
+ #$vol->create_date('now');
+ #$vol->editor($e->requestor->id);
+ #$vol->edit_date('now');
+ #$e->create_asset_call_number($vol) or return $e->die_event;
+
+ my $evt = create_volume( 0, $e, $vol );
+ return $evt if $evt;
+
$e->commit;
return $vol->id;
}
sub _make_bill {
my( $session, $amount, $type, $xactid ) = @_;
- $logger->activity("The system is charging $amount ".
+ $logger->info("The system is charging $amount ".
" [$type] for lost materials on circulation $xactid");
- my $bill = Fieldmapper::money::billing->new;
+ # -----------------------------------------------------------------
+ # make sure the transaction is not closed
+ my $e = new_editor(xact=>1);
+ my $xact = $e->retrieve_money_billable_transaction($xactid)
+ or return $e->die_event;
+
+ if( $xact->xact_finish ) {
+ my ($mbts) = $U->fetch_mbts($xactid, $e);
+ if( ($mbts->balance_owed + $amount) != 0 ) {
+ $logger->info("re-opening xact $xactid");
+ $xact->clear_xact_finish;
+ $e->update_money_billable_transaction($xact)
+ or return $e->die_event;
+ $e->commit;
+ }
+ }
+
+ $e->rollback; # has no effect if it's already been comitted
+ # -----------------------------------------------------------------
+
+ my $bill = Fieldmapper::money::billing->new;
$bill->xact($xactid);
$bill->amount($amount);
- $bill->billing_type($type); # - XXX these strings should be configurable some day
+ $bill->billing_type($type);
$bill->note('SYSTEM GENERATED');
my $id = $session->request(
api_name => 'open-ils.circ.copy_details.retrieve.barcode');
sub copy_details_barcode {
my( $self, $conn, $auth, $barcode ) = @_;
- return $self->copy_details( $conn, $auth,
- new_editor()->search_asset_copy({barcode=>$barcode,deleted=>'f'},{idlist=>1})->[0]);
+ my $e = new_editor();
+ my $cid = $e->search_asset_copy({barcode=>$barcode, deleted=>'f'}, {idlist=>1})->[0];
+ return $e->event unless $cid;
+ return $self->copy_details( $conn, $auth, $cid );
}
sub initialize {
- my $self = shift;
- my $conf = OpenSRF::Utils::SettingsClient->new;
- my @pfx2 = ( "apps", "open-ils.circ","app_settings" );
- my @pfx = ( @pfx2, "scripts" );
-
- my $p = $conf->config_value( @pfx, 'circ_permit_patron' );
- my $c = $conf->config_value( @pfx, 'circ_permit_copy' );
- my $d = $conf->config_value( @pfx, 'circ_duration' );
- my $f = $conf->config_value( @pfx, 'circ_recurring_fines' );
- my $m = $conf->config_value( @pfx, 'circ_max_fines' );
- my $pr = $conf->config_value( @pfx, 'circ_permit_renew' );
- my $lb = $conf->config_value( @pfx2, 'script_path' );
-
- $logger->error( "Missing circ script(s)" )
- unless( $p and $c and $d and $f and $m and $pr );
-
- $scripts{circ_permit_patron} = $p;
- $scripts{circ_permit_copy} = $c;
- $scripts{circ_duration} = $d;
- $scripts{circ_recurring_fines}= $f;
- $scripts{circ_max_fines} = $m;
- $scripts{circ_permit_renew} = $pr;
-
- $lb = [ $lb ] unless ref($lb);
- $script_libs = $lb;
-
- $logger->debug(
- "circulator: Loaded rules scripts for circ: " .
- "circ permit patron = $p, ".
- "circ permit copy = $c, ".
- "circ duration = $d, ".
- "circ recurring fines = $f, " .
- "circ max fines = $m, ".
- "circ renew permit = $pr. ".
- "lib paths = @$lb");
+ my $self = shift;
+ my $conf = OpenSRF::Utils::SettingsClient->new;
+ my @pfx2 = ( "apps", "open-ils.circ","app_settings" );
+ my @pfx = ( @pfx2, "scripts" );
+
+ my $p = $conf->config_value( @pfx, 'circ_permit_patron' );
+ my $c = $conf->config_value( @pfx, 'circ_permit_copy' );
+ my $d = $conf->config_value( @pfx, 'circ_duration' );
+ my $f = $conf->config_value( @pfx, 'circ_recurring_fines' );
+ my $m = $conf->config_value( @pfx, 'circ_max_fines' );
+ my $pr = $conf->config_value( @pfx, 'circ_permit_renew' );
+ my $lb = $conf->config_value( @pfx2, 'script_path' );
+
+ $logger->error( "Missing circ script(s)" )
+ unless( $p and $c and $d and $f and $m and $pr );
+
+ $scripts{circ_permit_patron} = $p;
+ $scripts{circ_permit_copy} = $c;
+ $scripts{circ_duration} = $d;
+ $scripts{circ_recurring_fines}= $f;
+ $scripts{circ_max_fines} = $m;
+ $scripts{circ_permit_renew} = $pr;
+
+ $lb = [ $lb ] unless ref($lb);
+ $script_libs = $lb;
+
+ $logger->debug(
+ "circulator: Loaded rules scripts for circ: " .
+ "circ permit patron = $p, ".
+ "circ permit copy = $c, ".
+ "circ duration = $d, ".
+ "circ recurring fines = $f, " .
+ "circ max fines = $m, ".
+ "circ renew permit = $pr. ".
+ "lib paths = @$lb");
}
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.checkout.permit",
- notes => q/
- Determines if the given checkout can occur
- @param authtoken The login session key
- @param params A trailing hash of named params including
- barcode : The copy barcode,
- patron : The patron the checkout is occurring for,
- renew : true or false - whether or not this is a renewal
- @return The event that occurred during the permit check.
- /);
+ method => "run_method",
+ api_name => "open-ils.circ.checkout.permit",
+ notes => q/
+ Determines if the given checkout can occur
+ @param authtoken The login session key
+ @param params A trailing hash of named params including
+ barcode : The copy barcode,
+ patron : The patron the checkout is occurring for,
+ renew : true or false - whether or not this is a renewal
+ @return The event that occurred during the permit check.
+ /);
__PACKAGE__->register_method (
- method => 'run_method',
- api_name => 'open-ils.circ.checkout.permit.override',
- signature => q/@see open-ils.circ.checkout.permit/,
+ method => 'run_method',
+ api_name => 'open-ils.circ.checkout.permit.override',
+ signature => q/@see open-ils.circ.checkout.permit/,
);
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.checkout",
- notes => q/
- Checks out an item
- @param authtoken The login session key
- @param params A named hash of params including:
- copy The copy object
- barcode If no copy is provided, the copy is retrieved via barcode
- copyid If no copy or barcode is provide, the copy id will be use
- patron The patron's id
- noncat True if this is a circulation for a non-cataloted item
- noncat_type The non-cataloged type id
- noncat_circ_lib The location for the noncat circ.
- precat The item has yet to be cataloged
- dummy_title The temporary title of the pre-cataloded item
- dummy_author The temporary authr of the pre-cataloded item
- Default is the home org of the staff member
- @return The SUCCESS event on success, any other event depending on the error
- /);
+ method => "run_method",
+ api_name => "open-ils.circ.checkout",
+ notes => q/
+ Checks out an item
+ @param authtoken The login session key
+ @param params A named hash of params including:
+ copy The copy object
+ barcode If no copy is provided, the copy is retrieved via barcode
+ copyid If no copy or barcode is provide, the copy id will be use
+ patron The patron's id
+ noncat True if this is a circulation for a non-cataloted item
+ noncat_type The non-cataloged type id
+ noncat_circ_lib The location for the noncat circ.
+ precat The item has yet to be cataloged
+ dummy_title The temporary title of the pre-cataloded item
+ dummy_author The temporary authr of the pre-cataloded item
+ Default is the home org of the staff member
+ @return The SUCCESS event on success, any other event depending on the error
+ /);
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.checkin",
- argc => 2,
- signature => q/
- Generic super-method for handling all copies
- @param authtoken The login session key
- @param params Hash of named parameters including:
- barcode - The copy barcode
- force - If true, copies in bad statuses will be checked in and give good statuses
- ...
- /
+ method => "run_method",
+ api_name => "open-ils.circ.checkin",
+ argc => 2,
+ signature => q/
+ Generic super-method for handling all copies
+ @param authtoken The login session key
+ @param params Hash of named parameters including:
+ barcode - The copy barcode
+ force - If true, copies in bad statuses will be checked in and give good statuses
+ ...
+ /
);
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.checkin.override",
- signature => q/@see open-ils.circ.checkin/
+ method => "run_method",
+ api_name => "open-ils.circ.checkin.override",
+ signature => q/@see open-ils.circ.checkin/
);
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.renew.override",
- signature => q/@see open-ils.circ.renew/,
+ method => "run_method",
+ api_name => "open-ils.circ.renew.override",
+ signature => q/@see open-ils.circ.renew/,
);
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.renew",
- notes => <<" NOTES");
- PARAMS( authtoken, circ => circ_id );
- open-ils.circ.renew(login_session, circ_object);
- Renews the provided circulation. login_session is the requestor of the
- renewal and if the logged in user is not the same as circ->usr, then
- the logged in user must have RENEW_CIRC permissions.
- NOTES
+ method => "run_method",
+ api_name => "open-ils.circ.renew",
+ notes => <<" NOTES");
+ PARAMS( authtoken, circ => circ_id );
+ open-ils.circ.renew(login_session, circ_object);
+ Renews the provided circulation. login_session is the requestor of the
+ renewal and if the logged in user is not the same as circ->usr, then
+ the logged in user must have RENEW_CIRC permissions.
+ NOTES
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.checkout.full");
+ method => "run_method",
+ api_name => "open-ils.circ.checkout.full");
__PACKAGE__->register_method(
- method => "run_method",
- api_name => "open-ils.circ.checkout.full.override");
+ method => "run_method",
+ api_name => "open-ils.circ.checkout.full.override");
sub run_method {
- my( $self, $conn, $auth, $args ) = @_;
- translate_legacy_args($args);
- my $api = $self->api_name;
-
- my $circulator =
- OpenILS::Application::Circ::Circulator->new($auth, %$args);
-
- return circ_events($circulator) if $circulator->bail_out;
-
- # --------------------------------------------------------------------------
- # Go ahead and load the script runner to make sure we have all
- # of the objects we need
- # --------------------------------------------------------------------------
- $circulator->is_renewal(1) if $api =~ /renew/;
- $circulator->is_checkin(1) if $api =~ /checkin/;
- $circulator->mk_script_runner;
- return circ_events($circulator) if $circulator->bail_out;
-
- $circulator->circ_permit_patron($scripts{circ_permit_patron});
- $circulator->circ_permit_copy($scripts{circ_permit_copy});
- $circulator->circ_duration($scripts{circ_duration});
- $circulator->circ_permit_renew($scripts{circ_permit_renew});
-
- $circulator->override(1) if $api =~ /override/o;
-
- if( $api =~ /checkout\.permit/ ) {
- $circulator->do_permit();
-
- } elsif( $api =~ /checkout.full/ ) {
-
- $circulator->do_permit();
- unless( $circulator->bail_out ) {
- $circulator->events([]);
- $circulator->do_checkout();
- }
-
- } elsif( $api =~ /checkout/ ) {
- $circulator->do_checkout();
-
- } elsif( $api =~ /checkin/ ) {
- $circulator->do_checkin();
-
- } elsif( $api =~ /renew/ ) {
- $circulator->is_renewal(1);
- $circulator->do_renew();
- }
-
- if( $circulator->bail_out ) {
-
- my @ee;
- # make sure no success event accidentally slip in
- $circulator->events(
- [ grep { $_->{textcode} ne 'SUCCESS' } @{$circulator->events} ]);
-
- # Log the events
- my @e = @{$circulator->events};
- push( @ee, $_->{textcode} ) for @e;
- $logger->info("circulator: bailing out with events: @ee");
-
- $circulator->editor->rollback;
-
- } else {
- $circulator->editor->commit;
- }
-
- $circulator->script_runner->cleanup;
-
- $conn->respond_complete(circ_events($circulator));
-
- unless($circulator->bail_out) {
- $circulator->do_hold_notify($circulator->notify_hold)
- if $circulator->notify_hold;
- }
+ my( $self, $conn, $auth, $args ) = @_;
+ translate_legacy_args($args);
+ my $api = $self->api_name;
+
+ my $circulator =
+ OpenILS::Application::Circ::Circulator->new($auth, %$args);
+
+ return circ_events($circulator) if $circulator->bail_out;
+
+ # --------------------------------------------------------------------------
+ # Go ahead and load the script runner to make sure we have all
+ # of the objects we need
+ # --------------------------------------------------------------------------
+ $circulator->is_renewal(1) if $api =~ /renew/;
+ $circulator->is_checkin(1) if $api =~ /checkin/;
+ $circulator->mk_script_runner;
+ return circ_events($circulator) if $circulator->bail_out;
+
+ $circulator->circ_permit_patron($scripts{circ_permit_patron});
+ $circulator->circ_permit_copy($scripts{circ_permit_copy});
+ $circulator->circ_duration($scripts{circ_duration});
+ $circulator->circ_permit_renew($scripts{circ_permit_renew});
+
+ $circulator->override(1) if $api =~ /override/o;
+
+ if( $api =~ /checkout\.permit/ ) {
+ $circulator->do_permit();
+
+ } elsif( $api =~ /checkout.full/ ) {
+
+ $circulator->do_permit();
+ unless( $circulator->bail_out ) {
+ $circulator->events([]);
+ $circulator->do_checkout();
+ }
+
+ } elsif( $api =~ /checkout/ ) {
+ $circulator->do_checkout();
+
+ } elsif( $api =~ /checkin/ ) {
+ $circulator->do_checkin();
+
+ } elsif( $api =~ /renew/ ) {
+ $circulator->is_renewal(1);
+ $circulator->do_renew();
+ }
+
+ if( $circulator->bail_out ) {
+
+ my @ee;
+ # make sure no success event accidentally slip in
+ $circulator->events(
+ [ grep { $_->{textcode} ne 'SUCCESS' } @{$circulator->events} ]);
+
+ # Log the events
+ my @e = @{$circulator->events};
+ push( @ee, $_->{textcode} ) for @e;
+ $logger->info("circulator: bailing out with events: @ee");
+
+ $circulator->editor->rollback;
+
+ } else {
+ $circulator->editor->commit;
+ }
+
+ $circulator->script_runner->cleanup;
+
+ $conn->respond_complete(circ_events($circulator));
+
+ unless($circulator->bail_out) {
+ $circulator->do_hold_notify($circulator->notify_hold)
+ if $circulator->notify_hold;
+ }
}
sub circ_events {
- my $circ = shift;
- my @e = @{$circ->events};
- # if we have multiple events, SUCCESS should not be one of them;
- @e = grep { $_->{textcode} ne 'SUCCESS' } @e if @e > 1;
- return (@e == 1) ? $e[0] : \@e;
+ my $circ = shift;
+ my @e = @{$circ->events};
+ # if we have multiple events, SUCCESS should not be one of them;
+ @e = grep { $_->{textcode} ne 'SUCCESS' } @e if @e > 1;
+ return (@e == 1) ? $e[0] : \@e;
}
sub translate_legacy_args {
- my $args = shift;
-
- if( $$args{barcode} ) {
- $$args{copy_barcode} = $$args{barcode};
- delete $$args{barcode};
- }
-
- if( $$args{copyid} ) {
- $$args{copy_id} = $$args{copyid};
- delete $$args{copyid};
- }
-
- if( $$args{patronid} ) {
- $$args{patron_id} = $$args{patronid};
- delete $$args{patronid};
- }
-
- if( $$args{patron} and !ref($$args{patron}) ) {
- $$args{patron_id} = $$args{patron};
- delete $$args{patron};
- }
-
-
- if( $$args{noncat} ) {
- $$args{is_noncat} = $$args{noncat};
- delete $$args{noncat};
- }
-
- if( $$args{precat} ) {
- $$args{is_precat} = $$args{precat};
- delete $$args{precat};
- }
+ my $args = shift;
+
+ if( $$args{barcode} ) {
+ $$args{copy_barcode} = $$args{barcode};
+ delete $$args{barcode};
+ }
+
+ if( $$args{copyid} ) {
+ $$args{copy_id} = $$args{copyid};
+ delete $$args{copyid};
+ }
+
+ if( $$args{patronid} ) {
+ $$args{patron_id} = $$args{patronid};
+ delete $$args{patronid};
+ }
+
+ if( $$args{patron} and !ref($$args{patron}) ) {
+ $$args{patron_id} = $$args{patron};
+ delete $$args{patron};
+ }
+
+
+ if( $$args{noncat} ) {
+ $$args{is_noncat} = $$args{noncat};
+ delete $$args{noncat};
+ }
+
+ if( $$args{precat} ) {
+ $$args{is_precat} = $$args{precat};
+ delete $$args{precat};
+ }
+
}
use OpenILS::Application::Circ::ScriptBuilder;
use OpenILS::Const qw/:const/;
-my $U = "OpenILS::Application::AppUtils";
-my $holdcode = "OpenILS::Application::Circ::Holds";
-my $transcode = "OpenILS::Application::Circ::Transit";
+my $U = "OpenILS::Application::AppUtils";
+my $holdcode = "OpenILS::Application::Circ::Holds";
+my $transcode = "OpenILS::Application::Circ::Transit";
sub DESTROY { }
# Add a pile of automagic getter/setter methods
# --------------------------------------------------------------------------
my @AUTOLOAD_FIELDS = qw/
- notify_hold
- penalty_request
- remote_hold
- backdate
- copy
- copy_id
- copy_barcode
- patron
- patron_id
- patron_barcode
- script_runner
- volume
- title
- is_renewal
- is_noncat
- is_precat
- is_checkin
- noncat_type
- editor
- events
- cache_handle
- override
- circ_permit_patron
- circ_permit_copy
- circ_duration
- circ_recurring_fines
- circ_max_fines
- circ_permit_renew
- circ
- transit
- hold
- permit_key
- noncat_circ_lib
- noncat_count
- checkout_time
- dummy_title
- dummy_author
- circ_lib
- barcode
+ notify_hold
+ penalty_request
+ remote_hold
+ backdate
+ copy
+ copy_id
+ copy_barcode
+ patron
+ patron_id
+ patron_barcode
+ script_runner
+ volume
+ title
+ is_renewal
+ is_noncat
+ is_precat
+ is_checkin
+ noncat_type
+ editor
+ events
+ cache_handle
+ override
+ circ_permit_patron
+ circ_permit_copy
+ circ_duration
+ circ_recurring_fines
+ circ_max_fines
+ circ_permit_renew
+ circ
+ transit
+ hold
+ permit_key
+ noncat_circ_lib
+ noncat_count
+ checkout_time
+ dummy_title
+ dummy_author
+ circ_lib
+ barcode
duration_level
recurring_fines_level
duration_rule
recurring_fines_rule
max_fine_rule
- renewal_remaining
- due_date
- fulfilled_holds
- transit
- checkin_changed
- force
- old_circ
- permit_override
- pending_checkouts
+ renewal_remaining
+ due_date
+ fulfilled_holds
+ transit
+ checkin_changed
+ force
+ old_circ
+ permit_override
+ pending_checkouts
+ cancelled_hold_transit
+ opac_renewal
+ phone_renewal
+ desk_renewal
/;
sub AUTOLOAD {
- my $self = shift;
- my $type = ref($self) or die "$self is not an object";
- my $data = shift;
- my $name = $AUTOLOAD;
- $name =~ s/.*://o;
-
- unless (grep { $_ eq $name } @AUTOLOAD_FIELDS) {
- $logger->error("circulator: $type: invalid autoload field: $name");
- die "$type: invalid autoload field: $name\n"
- }
-
- {
- no strict 'refs';
- *{"${type}::${name}"} = sub {
- my $s = shift;
- my $v = shift;
- $s->{$name} = $v if defined $v;
- return $s->{$name};
- }
- }
- return $self->$name($data);
+ my $self = shift;
+ my $type = ref($self) or die "$self is not an object";
+ my $data = shift;
+ my $name = $AUTOLOAD;
+ $name =~ s/.*://o;
+
+ unless (grep { $_ eq $name } @AUTOLOAD_FIELDS) {
+ $logger->error("circulator: $type: invalid autoload field: $name");
+ die "$type: invalid autoload field: $name\n"
+ }
+
+ {
+ no strict 'refs';
+ *{"${type}::${name}"} = sub {
+ my $s = shift;
+ my $v = shift;
+ $s->{$name} = $v if defined $v;
+ return $s->{$name};
+ }
+ }
+ return $self->$name($data);
}
sub new {
- my( $class, $auth, %args ) = @_;
- $class = ref($class) || $class;
- my $self = bless( {}, $class );
+ my( $class, $auth, %args ) = @_;
+ $class = ref($class) || $class;
+ my $self = bless( {}, $class );
+
+ $self->events([]);
+ $self->editor(
+ new_editor(xact => 1, authtoken => $auth) );
- $self->events([]);
- $self->editor(
- new_editor(xact => 1, authtoken => $auth) );
+ unless( $self->editor->checkauth ) {
+ $self->bail_on_events($self->editor->event);
+ return $self;
+ }
- unless( $self->editor->checkauth ) {
- $self->bail_on_events($self->editor->event);
- return $self;
- }
+ $self->cache_handle(OpenSRF::Utils::Cache->new('global'));
- $self->cache_handle(OpenSRF::Utils::Cache->new('global'));
+ $self->$_($args{$_}) for keys %args;
- $self->$_($args{$_}) for keys %args;
+ $self->circ_lib(
+ ($self->circ_lib) ? $self->circ_lib : $self->editor->requestor->ws_ou);
- $self->circ_lib(
- ($self->circ_lib) ? $self->circ_lib : $self->editor->requestor->ws_ou);
+ # if this is a renewal, default to desk_renewal
+ $self->desk_renewal(1) unless
+ $self->opac_renewal or $self->phone_renewal;
- return $self;
+ return $self;
}
# True if we should discontinue processing
# --------------------------------------------------------------------------
sub bail_out {
- my( $self, $bool ) = @_;
- if( defined $bool ) {
- $logger->info("circulator: BAILING OUT") if $bool;
- $self->{bail_out} = $bool;
- }
- return $self->{bail_out};
+ my( $self, $bool ) = @_;
+ if( defined $bool ) {
+ $logger->info("circulator: BAILING OUT") if $bool;
+ $self->{bail_out} = $bool;
+ }
+ return $self->{bail_out};
}
sub push_events {
- my( $self, @evts ) = @_;
- for my $e (@evts) {
- next unless $e;
- $logger->info("circulator: pushing event ".$e->{textcode});
- push( @{$self->events}, $e ) unless
- grep { $_->{textcode} eq $e->{textcode} } @{$self->events};
- }
+ my( $self, @evts ) = @_;
+ for my $e (@evts) {
+ next unless $e;
+ $logger->info("circulator: pushing event ".$e->{textcode});
+ push( @{$self->events}, $e ) unless
+ grep { $_->{textcode} eq $e->{textcode} } @{$self->events};
+ }
}
sub mk_permit_key {
- my $self = shift;
- my $key = md5_hex( time() . rand() . "$$" );
- $self->cache_handle->put_cache( "oils_permit_key_$key", 1, 300 );
- return $self->permit_key($key);
+ my $self = shift;
+ my $key = md5_hex( time() . rand() . "$$" );
+ $self->cache_handle->put_cache( "oils_permit_key_$key", 1, 300 );
+ return $self->permit_key($key);
}
sub check_permit_key {
- my $self = shift;
- my $key = $self->permit_key;
- return 0 unless $key;
- my $k = "oils_permit_key_$key";
- my $one = $self->cache_handle->get_cache($k);
- $self->cache_handle->delete_cache($k);
- return ($one) ? 1 : 0;
+ my $self = shift;
+ my $key = $self->permit_key;
+ return 0 unless $key;
+ my $k = "oils_permit_key_$key";
+ my $one = $self->cache_handle->get_cache($k);
+ $self->cache_handle->delete_cache($k);
+ return ($one) ? 1 : 0;
}
# objects we need
# --------------------------------------------------------------------------
sub mk_script_runner {
- my $self = shift;
- my $args = {};
+ my $self = shift;
+ my $args = {};
- my @fields =
- qw/copy copy_barcode copy_id patron
- patron_id patron_barcode volume title editor/;
+ my @fields =
+ qw/copy copy_barcode copy_id patron
+ patron_id patron_barcode volume title editor/;
- # Translate our objects into the ScriptBuilder args hash
- $$args{$_} = $self->$_() for @fields;
+ # Translate our objects into the ScriptBuilder args hash
+ $$args{$_} = $self->$_() for @fields;
- $args->{ignore_user_status} = 1 if $self->is_checkin;
- $$args{fetch_patron_by_circ_copy} = 1;
- $$args{fetch_patron_circ_info} = 1 unless $self->is_checkin;
+ $args->{ignore_user_status} = 1 if $self->is_checkin;
+ $$args{fetch_patron_by_circ_copy} = 1;
+ $$args{fetch_patron_circ_info} = 1 unless $self->is_checkin;
- if( my $pco = $self->pending_checkouts ) {
- $logger->info("circulator: we were given a pending checkouts number of $pco");
- $$args{patronItemsOut} = $pco;
- }
+ if( my $pco = $self->pending_checkouts ) {
+ $logger->info("circulator: we were given a pending checkouts number of $pco");
+ $$args{patronItemsOut} = $pco;
+ }
- # This fetches most of the objects we need
- $self->script_runner(
- OpenILS::Application::Circ::ScriptBuilder->build($args));
+ # This fetches most of the objects we need
+ $self->script_runner(
+ OpenILS::Application::Circ::ScriptBuilder->build($args));
- # Now we translate the ScriptBuilder objects back into self
- $self->$_($$args{$_}) for @fields;
+ # Now we translate the ScriptBuilder objects back into self
+ $self->$_($$args{$_}) for @fields;
- my @evts = @{$args->{_events}} if $args->{_events};
+ my @evts = @{$args->{_events}} if $args->{_events};
- $logger->debug("circulator: script builder returned events: @evts") if @evts;
+ $logger->debug("circulator: script builder returned events: @evts") if @evts;
- if(@evts) {
- # Anything besides ASSET_COPY_NOT_FOUND will stop processing
- if(!$self->is_noncat and
- @evts == 1 and
- $evts[0]->{textcode} eq 'ASSET_COPY_NOT_FOUND') {
- $self->is_precat(1);
+ if(@evts) {
+ # Anything besides ASSET_COPY_NOT_FOUND will stop processing
+ if(!$self->is_noncat and
+ @evts == 1 and
+ $evts[0]->{textcode} eq 'ASSET_COPY_NOT_FOUND') {
+ $self->is_precat(1);
- } else {
- my @e = grep { $_->{textcode} ne 'ASSET_COPY_NOT_FOUND' } @evts;
- return $self->bail_on_events(@e);
- }
- }
+ } else {
+ my @e = grep { $_->{textcode} ne 'ASSET_COPY_NOT_FOUND' } @evts;
+ return $self->bail_on_events(@e);
+ }
+ }
- $self->is_precat(1) if $self->copy
- and $self->copy->call_number == OILS_PRECAT_CALL_NUMBER;
+ $self->is_precat(1) if $self->copy
+ and $self->copy->call_number == OILS_PRECAT_CALL_NUMBER;
- # We can't renew if there is no copy
- return $self->bail_on_events(@evts) if
- $self->is_renewal and !$self->copy;
+ # We can't renew if there is no copy
+ return $self->bail_on_events(@evts) if
+ $self->is_renewal and !$self->copy;
- # Set some circ-specific flags in the script environment
- my $evt = "environment";
- $self->script_runner->insert("$evt.isRenewal", ($self->is_renewal) ? 1 : undef);
+ # Set some circ-specific flags in the script environment
+ my $evt = "environment";
+ $self->script_runner->insert("$evt.isRenewal", ($self->is_renewal) ? 1 : undef);
- if( $self->is_noncat ) {
+ if( $self->is_noncat ) {
$self->script_runner->insert("$evt.isNonCat", 1);
$self->script_runner->insert("$evt.nonCatType", $self->noncat_type);
- }
+ }
- if( $self->is_precat ) {
- $self->script_runner->insert("environment.isPrecat", 1, 1);
- }
+ if( $self->is_precat ) {
+ $self->script_runner->insert("environment.isPrecat", 1, 1);
+ }
- $self->script_runner->add_path( $_ ) for @$script_libs;
+ $self->script_runner->add_path( $_ ) for @$script_libs;
- return 1;
+ return 1;
}
# Does the circ permit work
# --------------------------------------------------------------------------
sub do_permit {
- my $self = shift;
-
- $self->log_me("do_permit()");
-
- unless( $self->editor->requestor->id == $self->patron->id ) {
- return $self->bail_on_events($self->editor->event)
- unless( $self->editor->allowed('VIEW_PERMIT_CHECKOUT') );
- }
-
- $self->check_captured_holds();
- $self->do_copy_checks();
- return if $self->bail_out;
- $self->run_patron_permit_scripts();
- $self->run_copy_permit_scripts()
- unless $self->is_precat or $self->is_noncat;
- $self->override_events() unless $self->is_renewal;
- return if $self->bail_out;
-
- if( $self->is_precat ) {
- $self->push_events(
- OpenILS::Event->new(
- 'ITEM_NOT_CATALOGED', payload => $self->mk_permit_key));
- return $self->bail_out(1) unless $self->is_renewal;
- }
-
- $self->push_events(
+ my $self = shift;
+
+ $self->log_me("do_permit()");
+
+ unless( $self->editor->requestor->id == $self->patron->id ) {
+ return $self->bail_on_events($self->editor->event)
+ unless( $self->editor->allowed('VIEW_PERMIT_CHECKOUT') );
+ }
+
+ $self->check_captured_holds();
+ $self->do_copy_checks();
+ return if $self->bail_out;
+ $self->run_patron_permit_scripts();
+ $self->run_copy_permit_scripts()
+ unless $self->is_precat or $self->is_noncat;
+ $self->override_events() unless $self->is_renewal;
+ return if $self->bail_out;
+
+ if( $self->is_precat ) {
+ $self->push_events(
+ OpenILS::Event->new(
+ 'ITEM_NOT_CATALOGED', payload => $self->mk_permit_key));
+ return $self->bail_out(1) unless $self->is_renewal;
+ }
+
+ $self->push_events(
OpenILS::Event->new(
- 'SUCCESS',
- payload => $self->mk_permit_key));
+ 'SUCCESS',
+ payload => $self->mk_permit_key));
}
my $copy = $self->copy;
my $patron = $self->patron;
- return undef unless $copy;
+ return undef unless $copy;
- my $s = $U->copy_status($copy->status)->id;
- return unless $s == OILS_COPY_STATUS_ON_HOLDS_SHELF;
- $logger->info("circulator: copy is on holds shelf, searching for the correct hold");
+ my $s = $U->copy_status($copy->status)->id;
+ return unless $s == OILS_COPY_STATUS_ON_HOLDS_SHELF;
+ $logger->info("circulator: copy is on holds shelf, searching for the correct hold");
- # Item is on the holds shelf, make sure it's going to the right person
- my $holds = $self->editor->search_action_hold_request(
- [
- {
- current_copy => $copy->id ,
- capture_time => { '!=' => undef },
- cancel_time => undef,
- fulfillment_time => undef
- },
- { limit => 1 }
- ]
- );
+ # Item is on the holds shelf, make sure it's going to the right person
+ my $holds = $self->editor->search_action_hold_request(
+ [
+ {
+ current_copy => $copy->id ,
+ capture_time => { '!=' => undef },
+ cancel_time => undef,
+ fulfillment_time => undef
+ },
+ { limit => 1 }
+ ]
+ );
- if( $holds and $$holds[0] ) {
- return undef if $$holds[0]->usr == $patron->id;
- }
+ if( $holds and $$holds[0] ) {
+ return undef if $$holds[0]->usr == $patron->id;
+ }
- $logger->info("circulator: this copy is needed by a different patron to fulfill a hold");
+ $logger->info("circulator: this copy is needed by a different patron to fulfill a hold");
- $self->push_events(OpenILS::Event->new('ITEM_ON_HOLDS_SHELF'));
+ $self->push_events(OpenILS::Event->new('ITEM_ON_HOLDS_SHELF'));
}
sub do_copy_checks {
- my $self = shift;
- my $copy = $self->copy;
- return unless $copy;
+ my $self = shift;
+ my $copy = $self->copy;
+ return unless $copy;
- my $stat = $U->copy_status($copy->status)->id;
+ my $stat = $U->copy_status($copy->status)->id;
- # We cannot check out a copy if it is in-transit
- if( $stat == OILS_COPY_STATUS_IN_TRANSIT ) {
- return $self->bail_on_events(OpenILS::Event->new('COPY_IN_TRANSIT'));
- }
+ # We cannot check out a copy if it is in-transit
+ if( $stat == OILS_COPY_STATUS_IN_TRANSIT ) {
+ return $self->bail_on_events(OpenILS::Event->new('COPY_IN_TRANSIT'));
+ }
- $self->handle_claims_returned();
- return if $self->bail_out;
+ $self->handle_claims_returned();
+ return if $self->bail_out;
- # no claims returned circ was found, check if there is any open circ
- unless( $self->is_renewal ) {
- my $circs = $self->editor->search_action_circulation(
- { target_copy => $copy->id, checkin_time => undef }
- );
+ # no claims returned circ was found, check if there is any open circ
+ unless( $self->is_renewal ) {
+ my $circs = $self->editor->search_action_circulation(
+ { target_copy => $copy->id, checkin_time => undef }
+ );
- return $self->bail_on_events(
- OpenILS::Event->new('OPEN_CIRCULATION_EXISTS')) if @$circs;
- }
+ return $self->bail_on_events(
+ OpenILS::Event->new('OPEN_CIRCULATION_EXISTS')) if @$circs;
+ }
}
sub send_penalty_request {
- my $self = shift;
- my $ses = OpenSRF::AppSession->create('open-ils.penalty');
- $self->penalty_request(
- $ses->request(
- 'open-ils.penalty.patron_penalty.calculate',
- { update => 1,
- authtoken => $self->editor->authtoken,
- patron => $self->patron } ) );
+ my $self = shift;
+ my $ses = OpenSRF::AppSession->create('open-ils.penalty');
+ $self->penalty_request(
+ $ses->request(
+ 'open-ils.penalty.patron_penalty.calculate',
+ { update => 1,
+ authtoken => $self->editor->authtoken,
+ patron => $self->patron } ) );
}
sub gather_penalty_request {
- my $self = shift;
- return [] unless $self->penalty_request;
- my $data = $self->penalty_request->recv;
- if( ref $data ) {
- throw $data if UNIVERSAL::isa($data,'Error');
- $data = $data->content;
- return $data->{fatal_penalties};
- }
- $logger->error("circulator: penalty request returned no data");
- return [];
+ my $self = shift;
+ return [] unless $self->penalty_request;
+ my $data = $self->penalty_request->recv;
+ if( ref $data ) {
+ throw $data if UNIVERSAL::isa($data,'Error');
+ $data = $data->content;
+ return $data->{fatal_penalties};
+ }
+ $logger->error("circulator: penalty request returned no data");
+ return [];
}
# ---------------------------------------------------------------------
# set bail_out for any events
# ---------------------------------------------------------------------
sub run_patron_permit_scripts {
- my $self = shift;
- my $runner = $self->script_runner;
- my $patronid = $self->patron->id;
+ my $self = shift;
+ my $runner = $self->script_runner;
+ my $patronid = $self->patron->id;
- $self->send_penalty_request() unless $self->is_renewal;
+ $self->send_penalty_request() unless $self->is_renewal;
- # ---------------------------------------------------------------------
- # Now run the patron permit script
- # ---------------------------------------------------------------------
- $runner->load($self->circ_permit_patron);
- my $result = $runner->run or
- throw OpenSRF::EX::ERROR ("Circ Permit Patron Script Died: $@");
+ # ---------------------------------------------------------------------
+ # Now run the patron permit script
+ # ---------------------------------------------------------------------
+ $runner->load($self->circ_permit_patron);
+ my $result = $runner->run or
+ throw OpenSRF::EX::ERROR ("Circ Permit Patron Script Died: $@");
- my $patron_events = $result->{events};
- my @allevents;
+ my $patron_events = $result->{events};
+ my @allevents;
- # ---------------------------------------------------------------------
- # this is policy directly in the code, not a good idea in general, but
- # the penalty server doesn't know anything about renewals, so we
- # have to strip the event out here
- my $penalties = ($self->is_renewal) ? [] : $self->gather_penalty_request();
- # ---------------------------------------------------------------------
+ # ---------------------------------------------------------------------
+ # this is policy directly in the code, not a good idea in general, but
+ # the penalty server doesn't know anything about renewals, so we
+ # have to strip the event out here
+ my $penalties = ($self->is_renewal) ? [] : $self->gather_penalty_request();
+ # ---------------------------------------------------------------------
- push( @allevents, OpenILS::Event->new($_)) for (@$penalties, @$patron_events);
+ push( @allevents, OpenILS::Event->new($_)) for (@$penalties, @$patron_events);
- $logger->info("circulator: permit_patron script returned events: @allevents") if @allevents;
+ $logger->info("circulator: permit_patron script returned events: @allevents") if @allevents;
- $self->push_events(@allevents);
+ $self->push_events(@allevents);
}
sub run_copy_permit_scripts {
- my $self = shift;
- my $copy = $self->copy || return;
- my $runner = $self->script_runner;
-
+ my $self = shift;
+ my $copy = $self->copy || return;
+ my $runner = $self->script_runner;
+
# ---------------------------------------------------------------------
# Capture all of the copy permit events
# ---------------------------------------------------------------------
$runner->load($self->circ_permit_copy);
my $result = $runner->run or
- throw OpenSRF::EX::ERROR ("Circ Permit Copy Script Died: $@");
+ throw OpenSRF::EX::ERROR ("Circ Permit Copy Script Died: $@");
my $copy_events = $result->{events};
# ---------------------------------------------------------------------
# Now collect all of the events together
# ---------------------------------------------------------------------
- my @allevents;
+ my @allevents;
push( @allevents, OpenILS::Event->new($_)) for @$copy_events;
- # See if this copy has an alert message
- my $ae = $self->check_copy_alert();
- push( @allevents, $ae ) if $ae;
+ # See if this copy has an alert message
+ my $ae = $self->check_copy_alert();
+ push( @allevents, $ae ) if $ae;
# uniquify the events
my %hash = map { ($_->{ilsevent} => $_) } @allevents;
for (@allevents) {
$_->{payload} = $copy if
- ($_->{textcode} eq 'COPY_NOT_AVAILABLE');
+ ($_->{textcode} eq 'COPY_NOT_AVAILABLE');
}
- $logger->info("circulator: permit_copy script returned events: @allevents") if @allevents;
+ $logger->info("circulator: permit_copy script returned events: @allevents") if @allevents;
- $self->push_events(@allevents);
+ $self->push_events(@allevents);
}
sub check_copy_alert {
- my $self = shift;
- return undef if $self->is_renewal;
- return OpenILS::Event->new(
- 'COPY_ALERT_MESSAGE', payload => $self->copy->alert_message)
- if $self->copy and $self->copy->alert_message;
- return undef;
+ my $self = shift;
+ return undef if $self->is_renewal;
+ return OpenILS::Event->new(
+ 'COPY_ALERT_MESSAGE', payload => $self->copy->alert_message)
+ if $self->copy and $self->copy->alert_message;
+ return undef;
}
# that are being force-checked out
# --------------------------------------------------------------------------
sub override_events {
- my $self = shift;
- my @events = @{$self->events};
- return unless @events;
+ my $self = shift;
+ my @events = @{$self->events};
+ return unless @events;
- if(!$self->override) {
- return $self->bail_out(1)
- if( @events > 1 or $events[0]->{textcode} ne 'SUCCESS' );
- }
+ if(!$self->override) {
+ return $self->bail_out(1)
+ if( @events > 1 or $events[0]->{textcode} ne 'SUCCESS' );
+ }
- $self->events([]);
-
+ $self->events([]);
+
for my $e (@events) {
my $tc = $e->{textcode};
next if $tc eq 'SUCCESS';
my $ov = "$tc.override";
$logger->info("circulator: attempting to override event: $ov");
- return $self->bail_on_events($self->editor->event)
- unless( $self->editor->allowed($ov) );
+ return $self->bail_on_events($self->editor->event)
+ unless( $self->editor->allowed($ov) );
}
}
-
+
# --------------------------------------------------------------------------
# If there is an open claimsreturn circ on the requested copy, close the
# circ if overriding, otherwise bail out
# --------------------------------------------------------------------------
sub handle_claims_returned {
- my $self = shift;
- my $copy = $self->copy;
+ my $self = shift;
+ my $copy = $self->copy;
- my $CR = $self->editor->search_action_circulation(
- {
- target_copy => $copy->id,
- stop_fines => OILS_STOP_FINES_CLAIMSRETURNED,
- checkin_time => undef,
- }
- );
+ my $CR = $self->editor->search_action_circulation(
+ {
+ target_copy => $copy->id,
+ stop_fines => OILS_STOP_FINES_CLAIMSRETURNED,
+ checkin_time => undef,
+ }
+ );
- return unless ($CR = $CR->[0]);
+ return unless ($CR = $CR->[0]);
- my $evt;
+ my $evt;
- # - If the caller has set the override flag, we will check the item in
- if($self->override) {
+ # - If the caller has set the override flag, we will check the item in
+ if($self->override) {
- $CR->checkin_time('now');
- $CR->checkin_lib($self->editor->requestor->ws_ou);
- $CR->checkin_staff($self->editor->requestor->id);
+ $CR->checkin_time('now');
+ $CR->checkin_lib($self->editor->requestor->ws_ou);
+ $CR->checkin_staff($self->editor->requestor->id);
- $evt = $self->editor->event
- unless $self->editor->update_action_circulation($CR);
+ $evt = $self->editor->event
+ unless $self->editor->update_action_circulation($CR);
- } else {
- $evt = OpenILS::Event->new('CIRC_CLAIMS_RETURNED');
- }
+ } else {
+ $evt = OpenILS::Event->new('CIRC_CLAIMS_RETURNED');
+ }
- $self->bail_on_events($evt) if $evt;
- return;
+ $self->bail_on_events($evt) if $evt;
+ return;
}
# This performs the checkout
# --------------------------------------------------------------------------
sub do_checkout {
- my $self = shift;
+ my $self = shift;
- $self->log_me("do_checkout()");
+ $self->log_me("do_checkout()");
- # make sure perms are good if this isn't a renewal
- unless( $self->is_renewal ) {
- return $self->bail_on_events($self->editor->event)
- unless( $self->editor->allowed('COPY_CHECKOUT') );
- }
+ # make sure perms are good if this isn't a renewal
+ unless( $self->is_renewal ) {
+ return $self->bail_on_events($self->editor->event)
+ unless( $self->editor->allowed('COPY_CHECKOUT') );
+ }
- # verify the permit key
- unless( $self->check_permit_key ) {
- if( $self->permit_override ) {
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->allowed('CIRC_PERMIT_OVERRIDE');
- } else {
- return $self->bail_on_events(OpenILS::Event->new('CIRC_PERMIT_BAD_KEY'))
- }
- }
+ # verify the permit key
+ unless( $self->check_permit_key ) {
+ if( $self->permit_override ) {
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->allowed('CIRC_PERMIT_OVERRIDE');
+ } else {
+ return $self->bail_on_events(OpenILS::Event->new('CIRC_PERMIT_BAD_KEY'))
+ }
+ }
- # if this is a non-cataloged circ, build the circ and finish
- if( $self->is_noncat ) {
- $self->checkout_noncat;
- $self->push_events(
- OpenILS::Event->new('SUCCESS',
- payload => { noncat_circ => $self->circ }));
- return;
- }
+ # if this is a non-cataloged circ, build the circ and finish
+ if( $self->is_noncat ) {
+ $self->checkout_noncat;
+ $self->push_events(
+ OpenILS::Event->new('SUCCESS',
+ payload => { noncat_circ => $self->circ }));
+ return;
+ }
- if( $self->is_precat ) {
- $self->script_runner->insert("environment.isPrecat", 1, 1);
- $self->make_precat_copy;
- return if $self->bail_out;
+ if( $self->is_precat ) {
+ $self->script_runner->insert("environment.isPrecat", 1, 1);
+ $self->make_precat_copy;
+ return if $self->bail_out;
- } elsif( $self->copy->call_number == OILS_PRECAT_CALL_NUMBER ) {
- return $self->bail_on_events(OpenILS::Event->new('ITEM_NOT_CATALOGED'));
- }
+ } elsif( $self->copy->call_number == OILS_PRECAT_CALL_NUMBER ) {
+ return $self->bail_on_events(OpenILS::Event->new('ITEM_NOT_CATALOGED'));
+ }
- $self->do_copy_checks;
- return if $self->bail_out;
+ $self->do_copy_checks;
+ return if $self->bail_out;
- $self->run_checkout_scripts();
- return if $self->bail_out;
+ $self->run_checkout_scripts();
+ return if $self->bail_out;
- $self->build_checkout_circ_object();
- return if $self->bail_out;
+ $self->build_checkout_circ_object();
+ return if $self->bail_out;
- $self->apply_modified_due_date();
- return if $self->bail_out;
+ $self->apply_modified_due_date();
+ return if $self->bail_out;
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->create_action_circulation($self->circ);
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->create_action_circulation($self->circ);
- # refresh the circ to force local time zone for now
- $self->circ($self->editor->retrieve_action_circulation($self->circ->id));
+ # refresh the circ to force local time zone for now
+ $self->circ($self->editor->retrieve_action_circulation($self->circ->id));
- $self->copy->status(OILS_COPY_STATUS_CHECKED_OUT);
- $self->update_copy;
- return if $self->bail_out;
+ $self->copy->status(OILS_COPY_STATUS_CHECKED_OUT);
+ $self->update_copy;
+ return if $self->bail_out;
- $self->handle_checkout_holds();
- return if $self->bail_out;
+ $self->handle_checkout_holds();
+ return if $self->bail_out;
# ------------------------------------------------------------------------------
# Update the patron penalty info in the DB. Run it for permit-overrides or
- # renewals since both of those cases do not require the penalty server to
- # run during the permit phase of the checkout
+ # renewals since both of those cases do not require the penalty server to
+ # run during the permit phase of the checkout
# ------------------------------------------------------------------------------
- if( $self->permit_override or $self->is_renewal ) {
- $U->update_patron_penalties(
- authtoken => $self->editor->authtoken,
- patron => $self->patron,
- background => 1,
- );
- }
-
- my $record = $U->record_to_mvr($self->title) unless $self->is_precat;
- $self->push_events(
- OpenILS::Event->new('SUCCESS',
- payload => {
- copy => $U->unflesh_copy($self->copy),
- circ => $self->circ,
- record => $record,
- holds_fulfilled => $self->fulfilled_holds,
- }
- )
- );
+ if( $self->permit_override or $self->is_renewal ) {
+ $U->update_patron_penalties(
+ authtoken => $self->editor->authtoken,
+ patron => $self->patron,
+ background => 1,
+ );
+ }
+
+ my $record = $U->record_to_mvr($self->title) unless $self->is_precat;
+ $self->push_events(
+ OpenILS::Event->new('SUCCESS',
+ payload => {
+ copy => $U->unflesh_copy($self->copy),
+ circ => $self->circ,
+ record => $record,
+ holds_fulfilled => $self->fulfilled_holds,
+ }
+ )
+ );
}
sub update_copy {
- my $self = shift;
- my $copy = $self->copy;
-
- my $stat = $copy->status if ref $copy->status;
- my $loc = $copy->location if ref $copy->location;
- my $circ_lib = $copy->circ_lib if ref $copy->circ_lib;
-
- $copy->status($stat->id) if $stat;
- $copy->location($loc->id) if $loc;
- $copy->circ_lib($circ_lib->id) if $circ_lib;
- $copy->editor($self->editor->requestor->id);
- $copy->edit_date('now');
- $copy->age_protect($copy->age_protect->id) if ref $copy->age_protect;
-
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->update_asset_copy($self->copy);
-
- $copy->status($U->copy_status($copy->status));
- $copy->location($loc) if $loc;
- $copy->circ_lib($circ_lib) if $circ_lib;
+ my $self = shift;
+ my $copy = $self->copy;
+
+ my $stat = $copy->status if ref $copy->status;
+ my $loc = $copy->location if ref $copy->location;
+ my $circ_lib = $copy->circ_lib if ref $copy->circ_lib;
+
+ $copy->status($stat->id) if $stat;
+ $copy->location($loc->id) if $loc;
+ $copy->circ_lib($circ_lib->id) if $circ_lib;
+ $copy->editor($self->editor->requestor->id);
+ $copy->edit_date('now');
+ $copy->age_protect($copy->age_protect->id) if ref $copy->age_protect;
+
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->update_asset_copy($self->copy);
+
+ $copy->status($U->copy_status($copy->status));
+ $copy->location($loc) if $loc;
+ $copy->circ_lib($circ_lib) if $circ_lib;
}
sub bail_on_events {
- my( $self, @evts ) = @_;
- $self->push_events(@evts);
- $self->bail_out(1);
+ my( $self, @evts ) = @_;
+ $self->push_events(@evts);
+ $self->bail_out(1);
}
sub handle_checkout_holds {
my $copy = $self->copy;
my $patron = $self->patron;
- my $holds = $self->editor->search_action_hold_request(
- {
- current_copy => $copy->id ,
- cancel_time => undef,
- fulfillment_time => undef
- }
- );
+ my $holds = $self->editor->search_action_hold_request(
+ {
+ current_copy => $copy->id ,
+ cancel_time => undef,
+ fulfillment_time => undef
+ }
+ );
my @fulfilled;
# if the hold was never officially captured, capture it.
$hold->capture_time('now') unless $hold->capture_time;
- # just make sure it's set correctly
+ # just make sure it's set correctly
$hold->current_copy($copy->id);
$hold->fulfillment_time('now');
- $hold->fulfillment_staff($self->editor->requestor->id);
- $hold->fulfillment_lib($self->editor->requestor->ws_ou);
+ $hold->fulfillment_staff($self->editor->requestor->id);
+ $hold->fulfillment_lib($self->editor->requestor->ws_ou);
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->update_action_hold_request($hold);
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->update_action_hold_request($hold);
- $holdcode->delete_hold_copy_maps($self->editor, $hold->id);
+ $holdcode->delete_hold_copy_maps($self->editor, $hold->id);
push( @fulfilled, $hold->id );
}
$logger->info("circulator: un-targeting hold ".$_->id.
" because copy ".$copy->id." is getting checked out");
- # - make the targeter process this hold at next run
+ # - make the targeter process this hold at next run
$_->clear_prev_check_time;
- # - clear out the targetted copy
+ # - clear out the targetted copy
$_->clear_current_copy;
$_->clear_capture_time;
- return $self->bail_on_event($self->editor->event)
- unless $self->editor->update_action_hold_request($_);
+ return $self->bail_on_event($self->editor->event)
+ unless $self->editor->update_action_hold_request($_);
}
}
- $self->fulfilled_holds(\@fulfilled);
+ $self->fulfilled_holds(\@fulfilled);
}
sub run_checkout_scripts {
- my $self = shift;
+ my $self = shift;
- my $evt;
+ my $evt;
my $runner = $self->script_runner;
$runner->load($self->circ_duration);
my $result = $runner->run or
- throw OpenSRF::EX::ERROR ("Circ Duration Script Died: $@");
+ throw OpenSRF::EX::ERROR ("Circ Duration Script Died: $@");
my $duration = $result->{durationRule};
my $recurring = $result->{recurringFinesRule};
my $max_fine = $result->{maxFine};
- if( $duration ne OILS_UNLIMITED_CIRC_DURATION ) {
+ if( $duration ne OILS_UNLIMITED_CIRC_DURATION ) {
- ($duration, $evt) = $U->fetch_circ_duration_by_name($duration);
- return $self->bail_on_events($evt) if $evt;
-
- ($recurring, $evt) = $U->fetch_recurring_fine_by_name($recurring);
- return $self->bail_on_events($evt) if $evt;
-
- ($max_fine, $evt) = $U->fetch_max_fine_by_name($max_fine);
- return $self->bail_on_events($evt) if $evt;
+ ($duration, $evt) = $U->fetch_circ_duration_by_name($duration);
+ return $self->bail_on_events($evt) if $evt;
+
+ ($recurring, $evt) = $U->fetch_recurring_fine_by_name($recurring);
+ return $self->bail_on_events($evt) if $evt;
+
+ ($max_fine, $evt) = $U->fetch_max_fine_by_name($max_fine);
+ return $self->bail_on_events($evt) if $evt;
- } else {
+ } else {
- # The item circulates with an unlimited duration
- $duration = undef;
- $recurring = undef;
- $max_fine = undef;
- }
+ # The item circulates with an unlimited duration
+ $duration = undef;
+ $recurring = undef;
+ $max_fine = undef;
+ }
$self->duration_rule($duration);
$self->recurring_fines_rule($recurring);
sub build_checkout_circ_object {
- my $self = shift;
+ my $self = shift;
my $circ = Fieldmapper::action::circulation->new;
my $duration = $self->duration_rule;
my $copy = $self->copy;
my $patron = $self->patron;
- if( $duration ) {
-
- my $dname = $duration->name;
- my $mname = $max->name;
- my $rname = $recurring->name;
-
- $logger->debug("circulator: building circulation ".
- "with duration=$dname, maxfine=$mname, recurring=$rname");
-
- $circ->duration( $duration->shrt )
- if $copy->loan_duration == OILS_CIRC_DURATION_SHORT;
- $circ->duration( $duration->normal )
- if $copy->loan_duration == OILS_CIRC_DURATION_NORMAL;
- $circ->duration( $duration->extended )
- if $copy->loan_duration == OILS_CIRC_DURATION_EXTENDED;
-
- $circ->recuring_fine( $recurring->low )
- if $copy->fine_level == OILS_REC_FINE_LEVEL_LOW;
- $circ->recuring_fine( $recurring->normal )
- if $copy->fine_level == OILS_REC_FINE_LEVEL_NORMAL;
- $circ->recuring_fine( $recurring->high )
- if $copy->fine_level == OILS_REC_FINE_LEVEL_HIGH;
-
- $circ->duration_rule( $duration->name );
- $circ->recuring_fine_rule( $recurring->name );
- $circ->max_fine_rule( $max->name );
- $circ->max_fine( $max->amount );
-
- $circ->fine_interval($recurring->recurance_interval);
- $circ->renewal_remaining( $duration->max_renewals );
-
- } else {
-
- $logger->info("circulator: copy found with an unlimited circ duration");
- $circ->duration_rule(OILS_UNLIMITED_CIRC_DURATION);
- $circ->recuring_fine_rule(OILS_UNLIMITED_CIRC_DURATION);
- $circ->max_fine_rule(OILS_UNLIMITED_CIRC_DURATION);
- $circ->renewal_remaining(0);
- }
+ if( $duration ) {
+
+ my $dname = $duration->name;
+ my $mname = $max->name;
+ my $rname = $recurring->name;
+
+ $logger->debug("circulator: building circulation ".
+ "with duration=$dname, maxfine=$mname, recurring=$rname");
+
+ $circ->duration( $duration->shrt )
+ if $copy->loan_duration == OILS_CIRC_DURATION_SHORT;
+ $circ->duration( $duration->normal )
+ if $copy->loan_duration == OILS_CIRC_DURATION_NORMAL;
+ $circ->duration( $duration->extended )
+ if $copy->loan_duration == OILS_CIRC_DURATION_EXTENDED;
+
+ $circ->recuring_fine( $recurring->low )
+ if $copy->fine_level == OILS_REC_FINE_LEVEL_LOW;
+ $circ->recuring_fine( $recurring->normal )
+ if $copy->fine_level == OILS_REC_FINE_LEVEL_NORMAL;
+ $circ->recuring_fine( $recurring->high )
+ if $copy->fine_level == OILS_REC_FINE_LEVEL_HIGH;
+
+ $circ->duration_rule( $duration->name );
+ $circ->recuring_fine_rule( $recurring->name );
+ $circ->max_fine_rule( $max->name );
+ $circ->max_fine( $max->amount );
+
+ $circ->fine_interval($recurring->recurance_interval);
+ $circ->renewal_remaining( $duration->max_renewals );
+
+ } else {
+
+ $logger->info("circulator: copy found with an unlimited circ duration");
+ $circ->duration_rule(OILS_UNLIMITED_CIRC_DURATION);
+ $circ->recuring_fine_rule(OILS_UNLIMITED_CIRC_DURATION);
+ $circ->max_fine_rule(OILS_UNLIMITED_CIRC_DURATION);
+ $circ->renewal_remaining(0);
+ }
$circ->target_copy( $copy->id );
$circ->usr( $patron->id );
$circ->circ_lib( $self->circ_lib );
if( $self->is_renewal ) {
- $circ->opac_renewal(1);
+ $circ->opac_renewal('t') if $self->opac_renewal;
+ $circ->phone_renewal('t') if $self->phone_renewal;
+ $circ->desk_renewal('t') if $self->desk_renewal;
$circ->renewal_remaining($self->renewal_remaining);
$circ->circ_staff($self->editor->requestor->id);
}
+
# if the user provided an overiding checkout time,
# (e.g. the checkout really happened several hours ago), then
# we apply that here. Does this need a perm??
- $circ->xact_start(clense_ISO8601($self->checkout_time))
- if $self->checkout_time;
+ $circ->xact_start(clense_ISO8601($self->checkout_time))
+ if $self->checkout_time;
# if a patron is renewing, 'requestor' will be the patron
$circ->circ_staff($self->editor->requestor->id);
- $circ->due_date( $self->create_due_date($circ->duration) ) if $circ->duration;
+ $circ->due_date( $self->create_due_date($circ->duration) ) if $circ->duration;
- $self->circ($circ);
+ $self->circ($circ);
}
sub apply_modified_due_date {
- my $self = shift;
- my $circ = $self->circ;
- my $copy = $self->copy;
+ my $self = shift;
+ my $circ = $self->circ;
+ my $copy = $self->copy;
if( $self->due_date ) {
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->allowed('CIRC_OVERRIDE_DUE_DATE', $self->circ_lib);
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->allowed('CIRC_OVERRIDE_DUE_DATE', $self->circ_lib);
$circ->due_date(clense_ISO8601($self->due_date));
# if the due_date lands on a day when the location is closed
return unless $copy and $circ->due_date;
- #my $org = (ref $copy->circ_lib) ? $copy->circ_lib->id : $copy->circ_lib;
+ #my $org = (ref $copy->circ_lib) ? $copy->circ_lib->id : $copy->circ_lib;
- # due-date overlap should be determined by the location the item
- # is checked out from, not the owning or circ lib of the item
- my $org = $self->editor->requestor->ws_ou;
+ # due-date overlap should be determined by the location the item
+ # is checked out from, not the owning or circ lib of the item
+ my $org = $self->editor->requestor->ws_ou;
$logger->info("circulator: circ searching for closed date overlap on lib $org".
- " with an item due date of ".$circ->due_date );
+ " with an item due date of ".$circ->due_date );
my $dateinfo = $U->storagereq(
'open-ils.storage.actor.org_unit.closed_date.overlap',
- $org, $circ->due_date );
+ $org, $circ->due_date );
if($dateinfo) {
$logger->info("circulator: $dateinfo : circ due data / close date overlap found : due_date=".
sub create_due_date {
- my( $self, $duration ) = @_;
+ my( $self, $duration ) = @_;
my ($sec,$min,$hour,$mday,$mon,$year) =
gmtime(OpenSRF::Utils->interval_to_seconds($duration) + int(time()));
$year += 1900; $mon += 1;
sub make_precat_copy {
- my $self = shift;
- my $copy = $self->copy;
+ my $self = shift;
+ my $copy = $self->copy;
if($copy) {
$logger->debug("ciculator: Pre-cat copy already exists in checkout: ID=" . $copy->id);
$copy->dummy_title($self->dummy_title);
$copy->dummy_author($self->dummy_author);
- $self->update_copy();
- return;
+ $self->update_copy();
+ return;
}
$logger->info("circulator: Creating a new precataloged ".
- "copy in checkout with barcode " . $self->copy_barcode);
+ "copy in checkout with barcode " . $self->copy_barcode);
$copy = Fieldmapper::asset::copy->new;
$copy->circ_lib($self->circ_lib);
$copy->dummy_title($self->dummy_title || "");
$copy->dummy_author($self->dummy_author || "");
- unless( $self->copy($self->editor->create_asset_copy($copy)) ) {
- $self->bail_out(1);
- $self->push_events($self->editor->event);
- return;
- }
+ unless( $self->copy($self->editor->create_asset_copy($copy)) ) {
+ $self->bail_out(1);
+ $self->push_events($self->editor->event);
+ return;
+ }
- # this is a little bit of a hack, but we need to
- # get the copy into the script runner
- $self->script_runner->insert("environment.copy", $copy, 1);
+ # this is a little bit of a hack, but we need to
+ # get the copy into the script runner
+ $self->script_runner->insert("environment.copy", $copy, 1);
}
sub checkout_noncat {
- my $self = shift;
+ my $self = shift;
- my $circ;
- my $evt;
+ my $circ;
+ my $evt;
- my $lib = $self->noncat_circ_lib || $self->editor->requestor->ws_ou;
- my $count = $self->noncat_count || 1;
- my $cotime = clense_ISO8601($self->checkout_time) || "";
+ my $lib = $self->noncat_circ_lib || $self->editor->requestor->ws_ou;
+ my $count = $self->noncat_count || 1;
+ my $cotime = clense_ISO8601($self->checkout_time) || "";
$logger->info("ciculator: circ creating $count noncat circs with checkout time $cotime");
( $circ, $evt ) = OpenILS::Application::Circ::NonCat::create_non_cat_circ(
$self->editor->requestor->id,
- $self->patron->id,
- $lib,
- $self->noncat_type,
- $cotime,
- $self->editor );
-
- if( $evt ) {
- $self->push_events($evt);
- $self->bail_out(1);
- return;
- }
- $self->circ($circ);
+ $self->patron->id,
+ $lib,
+ $self->noncat_type,
+ $cotime,
+ $self->editor );
+
+ if( $evt ) {
+ $self->push_events($evt);
+ $self->bail_out(1);
+ return;
+ }
+ $self->circ($circ);
}
}
sub do_checkin {
- my $self = shift;
- $self->log_me("do_checkin()");
-
-
- return $self->bail_on_events(
- OpenILS::Event->new('ASSET_COPY_NOT_FOUND'))
- unless $self->copy;
-
- if( $self->checkin_check_holds_shelf() ) {
- $self->bail_on_events(OpenILS::Event->new('NO_CHANGE'));
- $self->hold($U->fetch_open_hold_by_copy($self->copy->id));
- $self->checkin_flesh_events;
- return;
- }
-
- unless( $self->is_renewal ) {
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->allowed('COPY_CHECKIN');
- }
-
- $self->push_events($self->check_copy_alert());
- $self->push_events($self->check_checkin_copy_status());
-
- # the renew code will have already found our circulation object
- unless( $self->is_renewal and $self->circ ) {
- $self->circ(
- $self->editor->search_action_circulation(
- { target_copy => $self->copy->id, checkin_time => undef })->[0]);
- }
-
- # if the circ is marked as 'claims returned', add the event to the list
- $self->push_events(OpenILS::Event->new('CIRC_CLAIMS_RETURNED'))
- if ($self->circ and $self->circ->stop_fines
- and $self->circ->stop_fines eq OILS_STOP_FINES_CLAIMSRETURNED);
-
- # handle the overridable events
- $self->override_events unless $self->is_renewal;
- return if $self->bail_out;
-
- if( $self->copy ) {
- $self->transit(
- $self->editor->search_action_transit_copy(
- { target_copy => $self->copy->id, dest_recv_time => undef })->[0]);
- }
-
- if( $self->circ ) {
- $self->checkin_handle_circ;
- return if $self->bail_out;
- $self->checkin_changed(1);
-
- } elsif( $self->transit ) {
- my $hold_transit = $self->process_received_transit;
- $self->checkin_changed(1);
-
- if( $self->bail_out ) {
- $self->checkin_flesh_events;
- return;
- }
-
- if( my $e = $self->check_checkin_copy_status() ) {
- # If the original copy status is special, alert the caller
- my $ev = $self->events;
- $self->events([$e]);
- $self->override_events;
- return if $self->bail_out;
- $self->events($ev);
- }
-
- if( $hold_transit or
- $U->copy_status($self->copy->status)->id
- == OILS_COPY_STATUS_ON_HOLDS_SHELF ) {
- $self->hold(
- ($hold_transit) ?
- $self->editor->retrieve_action_hold_request($hold_transit->hold) :
- $U->fetch_open_hold_by_copy($self->copy->id)
- );
-
- $self->checkin_flesh_events;
- return;
- }
-
- } elsif( $U->copy_status($self->copy->status)->id == OILS_COPY_STATUS_IN_TRANSIT ) {
- $logger->warn("circulator: we have a copy ".$self->copy->barcode.
- " that is in-transit, but there is no transit.. repairing");
- $self->reshelve_copy(1);
- return if $self->bail_out;
- }
-
- if( $self->is_renewal ) {
- $self->push_events(OpenILS::Event->new('SUCCESS'));
- return;
- }
+ my $self = shift;
+ $self->log_me("do_checkin()");
+
+
+ return $self->bail_on_events(
+ OpenILS::Event->new('ASSET_COPY_NOT_FOUND'))
+ unless $self->copy;
+
+ if( $self->checkin_check_holds_shelf() ) {
+ $self->bail_on_events(OpenILS::Event->new('NO_CHANGE'));
+ $self->hold($U->fetch_open_hold_by_copy($self->copy->id));
+ $self->checkin_flesh_events;
+ return;
+ }
+
+ unless( $self->is_renewal ) {
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->allowed('COPY_CHECKIN');
+ }
+
+ $self->push_events($self->check_copy_alert());
+ $self->push_events($self->check_checkin_copy_status());
+
+ # the renew code will have already found our circulation object
+ unless( $self->is_renewal and $self->circ ) {
+ my $circs = $self->editor->search_action_circulation(
+ { target_copy => $self->copy->id, checkin_time => undef });
+ $self->circ($$circs[0]);
+
+ # for now, just warn if there are multiple open circs on a copy
+ $logger->warn("circulator: we have ".scalar(@$circs).
+ " open circs for copy " .$self->copy->id."!!") if @$circs > 1;
+ }
+
+ # if the circ is marked as 'claims returned', add the event to the list
+ $self->push_events(OpenILS::Event->new('CIRC_CLAIMS_RETURNED'))
+ if ($self->circ and $self->circ->stop_fines
+ and $self->circ->stop_fines eq OILS_STOP_FINES_CLAIMSRETURNED);
+
+ # handle the overridable events
+ $self->override_events unless $self->is_renewal;
+ return if $self->bail_out;
+
+ if( $self->copy ) {
+ $self->transit(
+ $self->editor->search_action_transit_copy(
+ { target_copy => $self->copy->id, dest_recv_time => undef })->[0]);
+ }
+
+ if( $self->circ ) {
+ $self->checkin_handle_circ;
+ return if $self->bail_out;
+ $self->checkin_changed(1);
+
+ } elsif( $self->transit ) {
+ my $hold_transit = $self->process_received_transit;
+ $self->checkin_changed(1);
+
+ if( $self->bail_out ) {
+ $self->checkin_flesh_events;
+ return;
+ }
+
+ if( my $e = $self->check_checkin_copy_status() ) {
+ # If the original copy status is special, alert the caller
+ my $ev = $self->events;
+ $self->events([$e]);
+ $self->override_events;
+ return if $self->bail_out;
+ $self->events($ev);
+ }
+
+ if( $hold_transit or
+ $U->copy_status($self->copy->status)->id
+ == OILS_COPY_STATUS_ON_HOLDS_SHELF ) {
+
+ my $hold;
+ if( $hold_transit ) {
+ $hold = $self->editor->retrieve_action_hold_request($hold_transit->hold);
+ } else {
+ ($hold) = $U->fetch_open_hold_by_copy($self->copy->id);
+ }
+
+ $self->hold($hold);
+
+ if( $hold and $hold->cancel_time ) { # this transited hold was cancelled mid-transit
+
+ $logger->info("circulator: we received a transit on a cancelled hold " . $hold->id);
+ $self->reshelve_copy(1);
+ $self->cancelled_hold_transit(1);
+ $self->notify_hold(0); # don't notify for cancelled holds
+ return if $self->bail_out;
+
+ } else {
+
+ # hold transited to correct location
+ $self->checkin_flesh_events;
+ return;
+ }
+ }
+
+ } elsif( $U->copy_status($self->copy->status)->id == OILS_COPY_STATUS_IN_TRANSIT ) {
+
+ $logger->warn("circulator: we have a copy ".$self->copy->barcode.
+ " that is in-transit, but there is no transit.. repairing");
+ $self->reshelve_copy(1);
+ return if $self->bail_out;
+ }
+
+ if( $self->is_renewal ) {
+ $self->push_events(OpenILS::Event->new('SUCCESS'));
+ return;
+ }
# ------------------------------------------------------------------------------
# Circulations and transits are now closed where necessary. Now go on to see if
# this copy can fulfill a hold or needs to be routed to a different location
# ------------------------------------------------------------------------------
- if( !$self->remote_hold and $self->attempt_checkin_hold_capture() ) {
- return if $self->bail_out;
+ if( !$self->remote_hold and $self->attempt_checkin_hold_capture() ) {
+ return if $self->bail_out;
} else { # not needed for a hold
+ my $circ_lib = (ref $self->copy->circ_lib) ?
+ $self->copy->circ_lib->id : $self->copy->circ_lib;
- my $circ_lib = (ref $self->copy->circ_lib) ?
- $self->copy->circ_lib->id : $self->copy->circ_lib;
-
- if( $self->remote_hold ) {
- $circ_lib = $self->remote_hold->pickup_lib;
- $logger->warn("circulator: Copy ".$self->copy->barcode.
- " is on a remote hold's shelf, sending to $circ_lib");
- }
+ if( $self->remote_hold ) {
+ $circ_lib = $self->remote_hold->pickup_lib;
+ $logger->warn("circulator: Copy ".$self->copy->barcode.
+ " is on a remote hold's shelf, sending to $circ_lib");
+ }
- $logger->debug("circulator: circlib=$circ_lib, workstation=".$self->editor->requestor->ws_ou);
+ $logger->debug("circulator: circlib=$circ_lib, workstation=".$self->editor->requestor->ws_ou);
if( $circ_lib == $self->editor->requestor->ws_ou ) {
- $self->checkin_handle_precat();
- return if $self->bail_out;
+ $self->checkin_handle_precat();
+ return if $self->bail_out;
} else {
- my $bc = $self->copy->barcode;
- $logger->info("circulator: copy $bc at the wrong location, sending to $circ_lib");
- $self->checkin_build_copy_transit($circ_lib);
- return if $self->bail_out;
- $self->push_events(OpenILS::Event->new('ROUTE_ITEM', org => $circ_lib));
+ my $bc = $self->copy->barcode;
+ $logger->info("circulator: copy $bc at the wrong location, sending to $circ_lib");
+ $self->checkin_build_copy_transit($circ_lib);
+ return if $self->bail_out;
+ $self->push_events(OpenILS::Event->new('ROUTE_ITEM', org => $circ_lib));
}
}
- $self->reshelve_copy;
- return if $self->bail_out;
+ $self->reshelve_copy;
+ return if $self->bail_out;
- unless($self->checkin_changed) {
+ unless($self->checkin_changed) {
- $self->push_events(OpenILS::Event->new('NO_CHANGE'));
- my $stat = $U->copy_status($self->copy->status)->id;
+ $self->push_events(OpenILS::Event->new('NO_CHANGE'));
+ my $stat = $U->copy_status($self->copy->status)->id;
- $self->hold($U->fetch_open_hold_by_copy($self->copy->id))
+ $self->hold($U->fetch_open_hold_by_copy($self->copy->id))
if( $stat == OILS_COPY_STATUS_ON_HOLDS_SHELF );
- $self->bail_out(1); # no need to commit anything
+ $self->bail_out(1); # no need to commit anything
- } else {
- $self->push_events(OpenILS::Event->new('SUCCESS'))
- unless @{$self->events};
- }
+ } else {
+
+ $self->push_events(OpenILS::Event->new('SUCCESS'))
+ unless @{$self->events};
+ }
# ------------------------------------------------------------------------------
patron => $self->patron,
background => 1 ) if $self->is_checkin;
- $self->checkin_flesh_events;
- return;
+ $self->checkin_flesh_events;
+ return;
}
sub reshelve_copy {
$stat != OILS_COPY_STATUS_IN_TRANSIT and
$stat != OILS_COPY_STATUS_RESHELVING )) {
- $copy->status( OILS_COPY_STATUS_RESHELVING );
- $self->update_copy;
- $self->checkin_changed(1);
- }
+ $copy->status( OILS_COPY_STATUS_RESHELVING );
+ $self->update_copy;
+ $self->checkin_changed(1);
+ }
}
# because it was transited there for a hold and the
# hold has not been fulfilled
sub checkin_check_holds_shelf {
- my $self = shift;
- return 0 unless $self->copy;
-
- return 0 unless
- $U->copy_status($self->copy->status)->id ==
- OILS_COPY_STATUS_ON_HOLDS_SHELF;
-
- # find the hold that put us on the holds shelf
- my $holds = $self->editor->search_action_hold_request(
- {
- current_copy => $self->copy->id,
- capture_time => { '!=' => undef },
- fulfillment_time => undef,
- cancel_time => undef,
- }
- );
-
- unless(@$holds) {
- $logger->warn("circulator: copy is on-holds-shelf, but there is no hold - reshelving");
- $self->reshelve_copy(1);
- return 0;
- }
-
- my $hold = $$holds[0];
-
- $logger->info("circulator: we found a captured, un-fulfilled hold [".
- $hold->id. "] for copy ".$self->copy->barcode);
-
- if( $hold->pickup_lib == $self->editor->requestor->ws_ou ) {
- $logger->info("circulator: hold is for here .. we're done: ".$self->copy->barcode);
- return 1;
- }
-
- $logger->info("circulator: hold is not for here..");
- $self->remote_hold($hold);
- return 0;
+ my $self = shift;
+ return 0 unless $self->copy;
+
+ return 0 unless
+ $U->copy_status($self->copy->status)->id ==
+ OILS_COPY_STATUS_ON_HOLDS_SHELF;
+
+ # find the hold that put us on the holds shelf
+ my $holds = $self->editor->search_action_hold_request(
+ {
+ current_copy => $self->copy->id,
+ capture_time => { '!=' => undef },
+ fulfillment_time => undef,
+ cancel_time => undef,
+ }
+ );
+
+ unless(@$holds) {
+ $logger->warn("circulator: copy is on-holds-shelf, but there is no hold - reshelving");
+ $self->reshelve_copy(1);
+ return 0;
+ }
+
+ my $hold = $$holds[0];
+
+ $logger->info("circulator: we found a captured, un-fulfilled hold [".
+ $hold->id. "] for copy ".$self->copy->barcode);
+
+ if( $hold->pickup_lib == $self->editor->requestor->ws_ou ) {
+ $logger->info("circulator: hold is for here .. we're done: ".$self->copy->barcode);
+ return 1;
+ }
+
+ $logger->info("circulator: hold is not for here..");
+ $self->remote_hold($hold);
+ return 0;
}
sub checkin_handle_precat {
- my $self = shift;
+ my $self = shift;
my $copy = $self->copy;
if( $self->is_precat and ($copy->status != OILS_COPY_STATUS_CATALOGING) ) {
$copy->status(OILS_COPY_STATUS_CATALOGING);
- $self->update_copy();
- $self->checkin_changed(1);
- $self->push_events(OpenILS::Event->new('ITEM_NOT_CATALOGED'));
+ $self->update_copy();
+ $self->checkin_changed(1);
+ $self->push_events(OpenILS::Event->new('ITEM_NOT_CATALOGED'));
}
}
sub checkin_build_copy_transit {
- my $self = shift;
- my $dest = shift;
- my $copy = $self->copy;
+ my $self = shift;
+ my $dest = shift;
+ my $copy = $self->copy;
my $transit = Fieldmapper::action::transit_copy->new;
- #$dest ||= (ref($copy->circ_lib)) ? $copy->circ_lib->id : $copy->circ_lib;
- $logger->info("circulator: transiting copy to $dest");
+ #$dest ||= (ref($copy->circ_lib)) ? $copy->circ_lib->id : $copy->circ_lib;
+ $logger->info("circulator: transiting copy to $dest");
$transit->source($self->editor->requestor->ws_ou);
$transit->dest($dest);
$transit->source_send_time('now');
$transit->copy_status( $U->copy_status($copy->status)->id );
- $logger->debug("circulator: setting copy status on transit: ".$transit->copy_status);
+ $logger->debug("circulator: setting copy status on transit: ".$transit->copy_status);
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->create_action_transit_copy($transit);
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->create_action_transit_copy($transit);
$copy->status(OILS_COPY_STATUS_IN_TRANSIT);
- $self->update_copy;
- $self->checkin_changed(1);
+ $self->update_copy;
+ $self->checkin_changed(1);
}
sub attempt_checkin_hold_capture {
- my $self = shift;
- my $copy = $self->copy;
-
- # See if this copy can fulfill any holds
- my ($hold) = $holdcode->find_nearest_permitted_hold(
- OpenSRF::AppSession->create('open-ils.storage'),
- $copy, $self->editor->requestor );
-
- if(!$hold) {
- $logger->debug("circulator: no potential permitted".
- "holds found for copy ".$copy->barcode);
- return undef;
- }
-
-
- $logger->info("circulator: found permitted hold ".
- $hold->id . " for copy, capturing...");
-
- $hold->current_copy($copy->id);
- $hold->capture_time('now');
-
- # prevent DB errors caused by fetching
- # holds from storage, and updating through cstore
- $hold->clear_fulfillment_time;
- $hold->clear_fulfillment_staff;
- $hold->clear_fulfillment_lib;
- $hold->clear_expire_time;
- $hold->clear_cancel_time;
- $hold->clear_prev_check_time unless $hold->prev_check_time;
-
- $self->bail_on_events($self->editor->event)
- unless $self->editor->update_action_hold_request($hold);
- $self->hold($hold);
- $self->checkin_changed(1);
-
- return 1 if $self->bail_out;
-
- if( $hold->pickup_lib == $self->editor->requestor->ws_ou ) {
-
- # This hold was captured in the correct location
- $copy->status(OILS_COPY_STATUS_ON_HOLDS_SHELF);
- $self->push_events(OpenILS::Event->new('SUCCESS'));
-
- #$self->do_hold_notify($hold->id);
- $self->notify_hold($hold->id);
-
- } else {
-
- # Hold needs to be picked up elsewhere. Build a hold
- # transit and route the item.
- $self->checkin_build_hold_transit();
- $copy->status(OILS_COPY_STATUS_IN_TRANSIT);
- return 1 if $self->bail_out;
- $self->push_events(
- OpenILS::Event->new('ROUTE_ITEM', org => $hold->pickup_lib));
- }
-
- # make sure we save the copy status
- $self->update_copy;
- return 1;
+ my $self = shift;
+ my $copy = $self->copy;
+
+ # See if this copy can fulfill any holds
+ my ($hold) = $holdcode->find_nearest_permitted_hold(
+ $self->editor, $copy, $self->editor->requestor );
+
+ if(!$hold) {
+ $logger->debug("circulator: no potential permitted".
+ "holds found for copy ".$copy->barcode);
+ return undef;
+ }
+
+
+ $logger->info("circulator: found permitted hold ".
+ $hold->id . " for copy, capturing...");
+
+ $hold->current_copy($copy->id);
+ $hold->capture_time('now');
+
+ # prevent DB errors caused by fetching
+ # holds from storage, and updating through cstore
+ $hold->clear_fulfillment_time;
+ $hold->clear_fulfillment_staff;
+ $hold->clear_fulfillment_lib;
+ $hold->clear_expire_time;
+ $hold->clear_cancel_time;
+ $hold->clear_prev_check_time unless $hold->prev_check_time;
+
+ $self->bail_on_events($self->editor->event)
+ unless $self->editor->update_action_hold_request($hold);
+ $self->hold($hold);
+ $self->checkin_changed(1);
+
+ return 1 if $self->bail_out;
+
+ if( $hold->pickup_lib == $self->editor->requestor->ws_ou ) {
+
+ # This hold was captured in the correct location
+ $copy->status(OILS_COPY_STATUS_ON_HOLDS_SHELF);
+ $self->push_events(OpenILS::Event->new('SUCCESS'));
+
+ #$self->do_hold_notify($hold->id);
+ $self->notify_hold($hold->id);
+
+ } else {
+
+ # Hold needs to be picked up elsewhere. Build a hold
+ # transit and route the item.
+ $self->checkin_build_hold_transit();
+ $copy->status(OILS_COPY_STATUS_IN_TRANSIT);
+ return 1 if $self->bail_out;
+ $self->push_events(
+ OpenILS::Event->new('ROUTE_ITEM', org => $hold->pickup_lib));
+ }
+
+ # make sure we save the copy status
+ $self->update_copy;
+ return 1;
}
sub do_hold_notify {
- my( $self, $holdid ) = @_;
+ my( $self, $holdid ) = @_;
+
+ $logger->info("circulator: running delayed hold notify process");
- $logger->info("circulator: running delayed hold notify process");
+# my $notifier = OpenILS::Application::Circ::HoldNotify->new(
+# hold_id => $holdid, editor => new_editor(requestor=>$self->editor->requestor));
- my $notifier = OpenILS::Application::Circ::HoldNotify->new(
- hold_id => $holdid, editor => new_editor(requestor=>$self->editor->requestor));
+ my $notifier = OpenILS::Application::Circ::HoldNotify->new(
+ hold_id => $holdid, requestor => $self->editor->requestor);
- $logger->debug("circulator: built hold notifier");
+ $logger->debug("circulator: built hold notifier");
- if(!$notifier->event) {
+ if(!$notifier->event) {
- $logger->info("ciculator: attempt at sending hold notification for hold $holdid");
+ $logger->info("ciculator: attempt at sending hold notification for hold $holdid");
- my $stat = $notifier->send_email_notify;
- if( $stat == '1' ) {
- $logger->info("ciculator: hold notify succeeded for hold $holdid");
- return;
- }
+ my $stat = $notifier->send_email_notify;
+ if( $stat == '1' ) {
+ $logger->info("ciculator: hold notify succeeded for hold $holdid");
+ return;
+ }
- $logger->warn("ciculator: * hold notify failed for hold $holdid");
+ $logger->warn("ciculator: * hold notify failed for hold $holdid");
- } else {
- $logger->info("ciculator: Not sending hold notification since the patron has no email address");
- }
+ } else {
+ $logger->info("ciculator: Not sending hold notification since the patron has no email address");
+ }
}
sub checkin_build_hold_transit {
- my $self = shift;
+ my $self = shift;
my $copy = $self->copy;
my $hold = $self->hold;
my $trans = Fieldmapper::action::hold_transit_copy->new;
- $logger->debug("circulator: building hold transit for ".$copy->barcode);
+ $logger->debug("circulator: building hold transit for ".$copy->barcode);
$trans->hold($hold->id);
$trans->source($self->editor->requestor->ws_ou);
$trans->source_send_time("now");
$trans->target_copy($copy->id);
- # when the copy gets to its destination, it will recover
- # this status - put it onto the holds shelf
+ # when the copy gets to its destination, it will recover
+ # this status - put it onto the holds shelf
$trans->copy_status(OILS_COPY_STATUS_ON_HOLDS_SHELF);
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->create_action_hold_transit_copy($trans);
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->create_action_hold_transit_copy($trans);
}
sub process_received_transit {
- my $self = shift;
- my $copy = $self->copy;
- my $copyid = $self->copy->id;
+ my $self = shift;
+ my $copy = $self->copy;
+ my $copyid = $self->copy->id;
- my $status_name = $U->copy_status($copy->status)->name;
- $logger->debug("circulator: attempting transit receive on ".
- "copy $copyid. Copy status is $status_name");
+ my $status_name = $U->copy_status($copy->status)->name;
+ $logger->debug("circulator: attempting transit receive on ".
+ "copy $copyid. Copy status is $status_name");
- my $transit = $self->transit;
+ my $transit = $self->transit;
- if( $transit->dest != $self->editor->requestor->ws_ou ) {
- my $tid = $transit->id;
- $logger->info("circulator: Fowarding transit on copy which is destined ".
- "for a different location. transit=$tid, copy=$copyid,current ".
- "location=".$self->editor->requestor->ws_ou.",destination location=".$transit->dest);
+ if( $transit->dest != $self->editor->requestor->ws_ou ) {
+ # - this item is in-transit to a different location
- return $self->bail_on_events(
- OpenILS::Event->new('ROUTE_ITEM', org => $transit->dest ));
- }
+ my $tid = $transit->id;
+ my $loc = $self->editor->requestor->ws_ou;
+ my $dest = $transit->dest;
+
+ $logger->info("circulator: Fowarding transit on copy which is destined ".
+ "for a different location. transit=$tid, copy=$copyid, current ".
+ "location=$loc, destination location=$dest");
+
+ my $evt = OpenILS::Event->new('ROUTE_ITEM', org => $dest, payload => {});
+
+ # grab the associated hold object if available
+ my $ht = $self->editor->retrieve_action_hold_transit_copy($tid);
+ $self->hold($self->editor->retrieve_action_hold_request($ht->hold)) if $ht;
+
+ return $self->bail_on_events($evt);
+ }
# The transit is received, set the receive time
$transit->dest_recv_time('now');
- $self->bail_on_events($self->editor->event)
- unless $self->editor->update_action_transit_copy($transit);
+ $self->bail_on_events($self->editor->event)
+ unless $self->editor->update_action_transit_copy($transit);
- my $hold_transit = $self->editor->retrieve_action_hold_transit_copy($transit->id);
+ my $hold_transit = $self->editor->retrieve_action_hold_transit_copy($transit->id);
- $logger->info("ciculator: Recovering original copy status in transit: ".$transit->copy_status);
+ $logger->info("circulator: Recovering original copy status in transit: ".$transit->copy_status);
$copy->status( $transit->copy_status );
- $self->update_copy();
- return if $self->bail_out;
-
- my $ishold = 0;
- if($hold_transit) {
- #$self->do_hold_notify($hold_transit->hold);
- $self->notify_hold($hold_transit->hold);
- $ishold = 1;
- }
-
- $self->push_events(
- OpenILS::Event->new(
- 'SUCCESS',
- ishold => $ishold,
+ $self->update_copy();
+ return if $self->bail_out;
+
+ my $ishold = 0;
+ if($hold_transit) {
+ #$self->do_hold_notify($hold_transit->hold);
+ $self->notify_hold($hold_transit->hold);
+ $ishold = 1;
+ }
+
+ $self->push_events(
+ OpenILS::Event->new(
+ 'SUCCESS',
+ ishold => $ishold,
payload => { transit => $transit, holdtransit => $hold_transit } ));
- return $hold_transit;
+ return $hold_transit;
}
sub checkin_handle_circ {
my $self = shift;
- $U->logmark;
+ $U->logmark;
my $circ = $self->circ;
my $copy = $self->copy;
# backdate the circ if necessary
if($self->backdate) {
- $self->checkin_handle_backdate;
- return if $self->bail_out;
+ $self->checkin_handle_backdate;
+ return if $self->bail_out;
}
if(!$circ->stop_fines) {
}
# see if there are any fines owed on this circ. if not, close it
- ($obt) = $U->fetch_mbts($circ->id, $self->editor);
+ ($obt) = $U->fetch_mbts($circ->id, $self->editor);
$circ->xact_finish('now') if( $obt and $obt->balance_owed == 0 );
- $logger->debug("circulator: ".$obt->balance_owed." is owed on this circulation");
+ $logger->debug("circulator: ".$obt->balance_owed." is owed on this circulation");
# Set the checkin vars since we have the item
- $circ->checkin_time('now');
+ $circ->checkin_time( ($self->backdate) ? $self->backdate : 'now' );
+
$circ->checkin_staff($self->editor->requestor->id);
$circ->checkin_lib($self->editor->requestor->ws_ou);
- my $circ_lib = (ref $self->copy->circ_lib) ?
- $self->copy->circ_lib->id : $self->copy->circ_lib;
- my $stat = $U->copy_status($self->copy->status)->id;
-
- # If the item is lost/missing and it needs to be sent home, don't
- # reshelve the copy, leave it lost/missing so the recipient will know
- if( ($stat == OILS_COPY_STATUS_LOST or $stat == OILS_COPY_STATUS_MISSING)
- and ($circ_lib != $self->editor->requestor->ws_ou) ) {
- $logger->info("circulator: not updating copy status on checkin because copy is lost/missing");
+ my $circ_lib = (ref $self->copy->circ_lib) ?
+ $self->copy->circ_lib->id : $self->copy->circ_lib;
+ my $stat = $U->copy_status($self->copy->status)->id;
- } else {
- $self->copy->status($U->copy_status(OILS_COPY_STATUS_RESHELVING));
- $self->update_copy;
- }
+ # If the item is lost/missing and it needs to be sent home, don't
+ # reshelve the copy, leave it lost/missing so the recipient will know
+ if( ($stat == OILS_COPY_STATUS_LOST or $stat == OILS_COPY_STATUS_MISSING)
+ and ($circ_lib != $self->editor->requestor->ws_ou) ) {
+ $logger->info("circulator: not updating copy status on checkin because copy is lost/missing");
+ } else {
+ $self->copy->status($U->copy_status(OILS_COPY_STATUS_RESHELVING));
+ $self->update_copy;
+ }
- return $self->bail_on_events($self->editor->event)
- unless $self->editor->update_action_circulation($circ);
+ return $self->bail_on_events($self->editor->event)
+ unless $self->editor->update_action_circulation($circ);
}
sub checkin_handle_backdate {
- my $self = shift;
-
- my $bd = $self->backdate;
- $bd =~ s/^(\d{4}-\d{2}-\d{2}).*/$1/og;
- $bd = "${bd}T23:59:59";
-
- my $bills = $self->editor->search_money_billing(
- {
- billing_ts => { '>=' => $bd },
- xact => $self->circ->id,
- billing_type => OILS_BILLING_TYPE_OVERDUE_MATERIALS
- }
- );
-
- $logger->debug("backdate found ".scalar(@$bills)." bills to void");
-
- for my $bill (@$bills) {
- unless( $U->is_true($bill->voided) ) {
- $logger->info("backdate voiding bill ".$bill->id);
- $bill->voided('t');
- $bill->void_time('now');
- $bill->voider($self->editor->requestor->id);
- my $n = $bill->note || "";
- $bill->note("$n\nSystem: VOIDED FOR BACKDATE");
-
- $self->bail_on_events($self->editor->event)
- unless $self->editor->update_money_billing($bill);
- }
- }
+ my $self = shift;
+
+ my $bd = $self->backdate;
+
+ # ------------------------------------------------------------------
+ # clean up the backdate for date comparison
+ # we want any bills created on or after the backdate
+ # ------------------------------------------------------------------
+ $bd =~ s/^(\d{4}-\d{2}-\d{2}).*/$1/og;
+ #$bd = "${bd}T23:59:59";
+
+ my $bills = $self->editor->search_money_billing(
+ {
+ billing_ts => { '>=' => $bd },
+ xact => $self->circ->id,
+ billing_type => OILS_BILLING_TYPE_OVERDUE_MATERIALS
+ }
+ );
+
+ $logger->debug("backdate found ".scalar(@$bills)." bills to void");
+
+ for my $bill (@$bills) {
+ unless( $U->is_true($bill->voided) ) {
+ $logger->info("backdate voiding bill ".$bill->id);
+ $bill->voided('t');
+ $bill->void_time('now');
+ $bill->voider($self->editor->requestor->id);
+ my $n = $bill->note || "";
+ $bill->note("$n\nSystem: VOIDED FOR BACKDATE");
+
+ $self->bail_on_events($self->editor->event)
+ unless $self->editor->update_money_billing($bill);
+ }
+ }
}
sub _checkin_handle_backdate {
my( $class, $backdate, $circ, $requestor, $session, $closecirc ) = @_;
- my $bd = $backdate;
- $bd =~ s/^(\d{4}-\d{2}-\d{2}).*/$1/og;
- $bd = "${bd}T23:59:59";
+ my $bd = $backdate;
+ $bd =~ s/^(\d{4}-\d{2}-\d{2}).*/$1/og;
+ $bd = "${bd}T23:59:59";
my $bills = $session->request(
"open-ils.storage.direct.money.billing.search_where.atomic",
- billing_ts => { '>=' => $bd },
- xact => $circ->id,
- billing_type => OILS_BILLING_TYPE_OVERDUE_MATERIALS
- )->gather(1);
+ billing_ts => { '>=' => $bd },
+ xact => $circ->id,
+ billing_type => OILS_BILLING_TYPE_OVERDUE_MATERIALS
+ )->gather(1);
- $logger->debug("backdate found ".scalar(@$bills)." bills to void");
+ $logger->debug("backdate found ".scalar(@$bills)." bills to void");
if($bills) {
for my $bill (@$bills) {
- unless( $U->is_true($bill->voided) ) {
- $logger->debug("voiding bill ".$bill->id);
- $bill->voided('t');
- $bill->void_time('now');
- $bill->voider($requestor->id);
- my $n = $bill->note || "";
- $bill->note($n . "\nSystem: VOIDED FOR BACKDATE");
- my $s = $session->request(
- "open-ils.storage.direct.money.billing.update", $bill)->gather(1);
- return $U->DB_UPDATE_FAILED($bill) unless $s;
- }
- }
+ unless( $U->is_true($bill->voided) ) {
+ $logger->debug("voiding bill ".$bill->id);
+ $bill->voided('t');
+ $bill->void_time('now');
+ $bill->voider($requestor->id);
+ my $n = $bill->note || "";
+ $bill->note($n . "\nSystem: VOIDED FOR BACKDATE");
+ my $s = $session->request(
+ "open-ils.storage.direct.money.billing.update", $bill)->gather(1);
+ return $U->DB_UPDATE_FAILED($bill) unless $s;
+ }
+ }
}
- return 100;
+ return 100;
}
=cut
sub find_patron_from_copy {
- my $self = shift;
- my $circs = $self->editor->search_action_circulation(
- { target_copy => $self->copy->id, checkin_time => undef });
- my $circ = $circs->[0];
- return unless $circ;
- my $u = $self->editor->retrieve_actor_user($circ->usr)
- or return $self->bail_on_events($self->editor->event);
- $self->patron($u);
+ my $self = shift;
+ my $circs = $self->editor->search_action_circulation(
+ { target_copy => $self->copy->id, checkin_time => undef });
+ my $circ = $circs->[0];
+ return unless $circ;
+ my $u = $self->editor->retrieve_actor_user($circ->usr)
+ or return $self->bail_on_events($self->editor->event);
+ $self->patron($u);
}
sub check_checkin_copy_status {
- my $self = shift;
+ my $self = shift;
my $copy = $self->copy;
my $islost = 0;
# On checkin, we need to return as many relevant objects as we can
# --------------------------------------------------------------------------
sub checkin_flesh_events {
- my $self = shift;
+ my $self = shift;
+
+ if( grep { $_->{textcode} eq 'SUCCESS' } @{$self->events}
+ and grep { $_->{textcode} eq 'ITEM_NOT_CATALOGED' } @{$self->events} ) {
+ $self->events([grep { $_->{textcode} eq 'ITEM_NOT_CATALOGED' } @{$self->events}]);
+ }
+
- if( grep { $_->{textcode} eq 'SUCCESS' } @{$self->events}
- and grep { $_->{textcode} eq 'ITEM_NOT_CATALOGED' } @{$self->events} ) {
- $self->events([grep { $_->{textcode} eq 'ITEM_NOT_CATALOGED' } @{$self->events}]);
- }
+ for my $evt (@{$self->events}) {
+ my $payload = {};
+ $payload->{copy} = $U->unflesh_copy($self->copy);
+ $payload->{record} = $U->record_to_mvr($self->title) if($self->title and !$self->is_precat);
+ $payload->{circ} = $self->circ;
+ $payload->{transit} = $self->transit;
+ $payload->{cancelled_hold_transit} = 1 if $self->cancelled_hold_transit;
- for my $evt (@{$self->events}) {
+ # $self->hold may or may not have been replaced with a
+ # valid hold after processing a cancelled hold
+ $payload->{hold} = $self->hold unless (not $self->hold or $self->hold->cancel_time);
- my $payload = {};
- $payload->{copy} = $U->unflesh_copy($self->copy);
- $payload->{record} = $U->record_to_mvr($self->title) if($self->title and !$self->is_precat);
- $payload->{circ} = $self->circ;
- $payload->{transit} = $self->transit;
- $payload->{hold} = $self->hold;
-
- $evt->{payload} = $payload;
- }
+ $evt->{payload} = $payload;
+ }
}
sub log_me {
- my( $self, $msg ) = @_;
- my $bc = ($self->copy) ? $self->copy->barcode :
- $self->barcode;
- $bc ||= "";
- my $usr = ($self->patron) ? $self->patron->id : "";
- $logger->info("circulator: $msg requestor=".$self->editor->requestor->id.
- ", recipient=$usr, copy=$bc");
+ my( $self, $msg ) = @_;
+ my $bc = ($self->copy) ? $self->copy->barcode :
+ $self->barcode;
+ $bc ||= "";
+ my $usr = ($self->patron) ? $self->patron->id : "";
+ $logger->info("circulator: $msg requestor=".$self->editor->requestor->id.
+ ", recipient=$usr, copy=$bc");
}
sub do_renew {
- my $self = shift;
- $self->log_me("do_renew()");
- $self->is_renewal(1);
-
- unless( $self->is_renewal ) {
- return $self->bail_on_events($self->editor->events)
- unless $self->editor->allowed('RENEW_CIRC');
- }
-
- # Make sure there is an open circ to renew that is not
- # marked as LOST, CLAIMSRETURNED, or LONGOVERDUE
- my $circ = $self->editor->search_action_circulation(
- { target_copy => $self->copy->id, stop_fines => undef } )->[0];
-
- if(!$circ) {
- $circ = $self->editor->search_action_circulation(
- {
- target_copy => $self->copy->id,
- stop_fines => OILS_STOP_FINES_MAX_FINES,
- checkin_time => undef
- }
- )->[0];
- }
-
- return $self->bail_on_events($self->editor->event) unless $circ;
-
- $self->push_events(OpenILS::Event->new('MAX_RENEWALS_REACHED'))
- if $circ->renewal_remaining < 1;
-
- # -----------------------------------------------------------------
-
- $self->renewal_remaining( $circ->renewal_remaining - 1 );
- $self->circ($circ);
-
- $self->run_renew_permit;
-
- # Check the item in
- $self->do_checkin();
- return if $self->bail_out;
-
- unless( $self->permit_override ) {
- $self->do_permit();
- return if $self->bail_out;
- $self->is_precat(1) if $self->have_event('ITEM_NOT_CATALOGED');
- $self->remove_event('ITEM_NOT_CATALOGED');
- }
-
- $self->override_events;
- return if $self->bail_out;
-
- $self->events([]);
- $self->do_checkout();
+ my $self = shift;
+ $self->log_me("do_renew()");
+ $self->is_renewal(1);
+
+ unless( $self->is_renewal ) {
+ return $self->bail_on_events($self->editor->events)
+ unless $self->editor->allowed('RENEW_CIRC');
+ }
+
+ # Make sure there is an open circ to renew that is not
+ # marked as LOST, CLAIMSRETURNED, or LONGOVERDUE
+ my $circ = $self->editor->search_action_circulation(
+ { target_copy => $self->copy->id, stop_fines => undef } )->[0];
+
+ if(!$circ) {
+ $circ = $self->editor->search_action_circulation(
+ {
+ target_copy => $self->copy->id,
+ stop_fines => OILS_STOP_FINES_MAX_FINES,
+ checkin_time => undef
+ }
+ )->[0];
+ }
+
+ return $self->bail_on_events($self->editor->event) unless $circ;
+
+ $self->push_events(OpenILS::Event->new('MAX_RENEWALS_REACHED'))
+ if $circ->renewal_remaining < 1;
+
+ # -----------------------------------------------------------------
+
+ $self->renewal_remaining( $circ->renewal_remaining - 1 );
+ $self->circ($circ);
+
+ $self->run_renew_permit;
+
+ # Check the item in
+ $self->do_checkin();
+ return if $self->bail_out;
+
+ unless( $self->permit_override ) {
+ $self->do_permit();
+ return if $self->bail_out;
+ $self->is_precat(1) if $self->have_event('ITEM_NOT_CATALOGED');
+ $self->remove_event('ITEM_NOT_CATALOGED');
+ }
+
+ $self->override_events;
+ return if $self->bail_out;
+
+ $self->events([]);
+ $self->do_checkout();
}
sub remove_event {
- my( $self, $evt ) = @_;
- $evt = (ref $evt) ? $evt->{textcode} : $evt;
- $logger->debug("circulator: removing event from list: $evt");
- my @events = @{$self->events};
- $self->events( [ grep { $_->{textcode} ne $evt } @events ] );
+ my( $self, $evt ) = @_;
+ $evt = (ref $evt) ? $evt->{textcode} : $evt;
+ $logger->debug("circulator: removing event from list: $evt");
+ my @events = @{$self->events};
+ $self->events( [ grep { $_->{textcode} ne $evt } @events ] );
}
sub have_event {
- my( $self, $evt ) = @_;
- $evt = (ref $evt) ? $evt->{textcode} : $evt;
- return grep { $_->{textcode} eq $evt } @{$self->events};
+ my( $self, $evt ) = @_;
+ $evt = (ref $evt) ? $evt->{textcode} : $evt;
+ return grep { $_->{textcode} eq $evt } @{$self->events};
}
sub run_renew_permit {
- my $self = shift;
+ my $self = shift;
my $runner = $self->script_runner;
$runner->load($self->circ_permit_renew);
my $result = $runner->run or
- throw OpenSRF::EX::ERROR ("Circ Permit Renew Script Died: $@");
+ throw OpenSRF::EX::ERROR ("Circ Permit Renew Script Died: $@");
my $events = $result->{events};
$logger->activity("ciculator: circ_permit_renew for user ".
$self->patron->id." returned events: @$events") if @$events;
- $self->push_events(OpenILS::Event->new($_)) for @$events;
-
- $logger->debug("circulator: re-creating script runner to be safe");
- $self->mk_script_runner;
+ $self->push_events(OpenILS::Event->new($_)) for @$events;
+
+ $logger->debug("circulator: re-creating script runner to be safe");
+ $self->mk_script_runner;
}
my $e = new_editor(authtoken => $auth);
return $e->event unless $e->checkauth;
return $e->event unless $e->allowed('CREATE_HOLD_NOTIFICATION');
- my $notifier = __PACKAGE__->new(editor=> $e, hold_id => $hold_id);
+ my $notifier = __PACKAGE__->new(requestor => $e->requestor, hold_id => $hold_id);
return $notifier->event if $notifier->event;
my $stat = $notifier->send_email_notify;
# $e->commit if $stat == '1';
my( $class, %args ) = @_;
$class = ref($class) || $class;
my $self = bless( {}, $class );
- $self->editor($args{editor});
+ $self->editor( new_editor( xact => 1, requestor => $args{requestor} ));
$logger->debug("circulator: creating new hold-notifier with requestor ".
$self->editor->requestor->id);
$self->fetch_data($args{hold_id});
return $self;
}
-
sub send_email_notify {
my $self = shift;
$logger->debug("hold_notify: email enabled setting = $setting");
if( !$setting or $setting ne 'true' ) {
+ $self->editor->rollback;
$logger->info("hold_notify: not sending hold notify - email notifications disabled");
return 0;
}
unless ($U->is_true($self->hold->email_notify)) {
+ $self->editor->rollback;
$logger->info("hold_notify: not sending hold notification becaue email_notify is false");
return 0;
}
- return OpenILS::Event->new('PATRON_NO_EMAIL_ADDRESS')
- unless $self->patron->email and
- $self->patron->email =~ /.+\@.+/; # see if it's remotely email-esque
+ unless( $self->patron->email and $self->patron->email =~ /.+\@.+/ ) { # see if it's remotely email-esque
+ $self->editor->rollback;
+ return OpenILS::Event->new('PATRON_NO_EMAIL_ADDRESS');
+ }
$logger->info("hold_notify: attempting email notify on hold ".$self->hold->id);
my $str = $self->flesh_template($self->load_template($template));
unless( $str ) {
+ $self->editor->rollback;
$logger->error("hold_notify: No email notifiy template found - cannot notify");
return 0;
}
+ my $reqr = $self->editor->requestor;
+ $self->editor->rollback; # we're done with this transaction
+
return 0 unless $self->send_email($str);
# ------------------------------------------------------------------
# transaction may have timed out. Create a one-off editor to write
# the notification to the DB.
# ------------------------------------------------------------------
- my $we = new_editor(xact=>1, requestor=>$self->editor->requestor);
+ my $we = new_editor(xact=>1, requestor=>$reqr);
my $notify = Fieldmapper::action::hold_notification->new;
$notify->hold($self->hold->id);
sub send_email {
my( $self, $text ) = @_;
+ # !!! $self->editor xact has been rolled back before we get here
+
my $smtp = $self->settings_client->config_value('email_notify', 'smtp_server');
$logger->info("hold_notify: sending email notice to ".
my $reply_to = $self->pickup_lib->email;
$reply_to ||= $sender;
+ # if they have an org setting for bounced emails, use that as the sender address
+ if( my $set = $self->editor->search_actor_org_unit_setting(
+ { name => OILS_SETTING_ORG_BOUNCED_EMAIL,
+ org_unit => $self->pickup_lib->id } )->[0] ) {
+
+ my $bemail = JSON->JSON2perl($set->value);
+ $sender = $bemail if $bemail;
+ }
$str =~ s/\${EMAIL_SENDER}/$sender/;
$str =~ s/\${EMAIL_RECIPIENT}/$email/;
}
}
+
+__PACKAGE__->register_method(
+ method => 'user_hold_count',
+ api_name => 'open-ils.circ.hold.user.count');
+
+sub user_hold_count {
+ my( $self, $conn, $auth, $userid ) = @_;
+ my $e = new_editor(authtoken=>$auth);
+ return $e->event unless $e->checkauth;
+ my $patron = $e->retrieve_actor_user($userid)
+ or return $e->event;
+ return $e->event unless $e->allowed('VIEW_HOLD', $patron->home_ou);
+ return $self->__user_hold_count($e, $userid);
+}
+
+sub __user_hold_count {
+ my( $self, $e, $userid ) = @_;
+ my $holds = $e->search_action_hold_request(
+ { usr => $userid ,
+ fulfillment_time => undef,
+ cancel_time => undef,
+ },
+ {idlist => 1}
+ );
+
+ return scalar(@$holds);
+}
+
+
__PACKAGE__->register_method(
method => "retrieve_holds_by_pickup_lib",
api_name => "open-ils.circ.holds.retrieve_by_pickup_lib",
or return $e->event;
if( $copy->status == OILS_COPY_STATUS_ON_HOLDS_SHELF ) {
- $logger->info("setting copy to status 'reshelving' on hold cancel");
- $copy->status(OILS_COPY_STATUS_RESHELVING);
- $copy->editor($e->requestor->id);
- $copy->edit_date('now');
- $e->update_asset_copy($copy) or return $e->event;
+ $logger->info("canceling hold $holdid whose item is on the holds shelf");
+# $logger->info("setting copy to status 'reshelving' on hold cancel");
+# $copy->status(OILS_COPY_STATUS_RESHELVING);
+# $copy->editor($e->requestor->id);
+# $copy->edit_date('now');
+# $e->update_asset_copy($copy) or return $e->event;
} elsif( $copy->status == OILS_COPY_STATUS_IN_TRANSIT ) {
if( $transid ) {
my $trans = $e->retrieve_action_transit_copy($transid);
+ # Leave the transit alive, but set the copy status to
+ # reshelving so it will be properly reshelved when it gets back home
if( $trans ) {
- $logger->info("Aborting transit [$transid] on hold [$hid] cancel...");
- my $evt = OpenILS::Application::Circ::Transit::__abort_transit($e, $trans, $copy, 1);
- $logger->info("Transit abort completed with result $evt");
- return $evt unless "$evt" eq 1;
+ $trans->copy_status( OILS_COPY_STATUS_RESHELVING );
+ $e->update_action_transit_copy($trans) or return $e->die_event;
}
}
-
- # We don't want the copy to remain "in transit" or to recover
- # any previous statuses
- $logger->info("setting copy back to reshelving in hold+transit cancel");
- $copy->status(OILS_COPY_STATUS_RESHELVING);
- $copy->editor($e->requestor->id);
- $copy->edit_date('now');
- $e->update_asset_copy($copy) or return $e->event;
}
}
}
-
-
-
-=head DEPRECATED
-__PACKAGE__->register_method(
- method => "capture_copy",
- api_name => "open-ils.circ.hold.capture_copy.barcode",
- notes => <<" NOTE");
- Captures a copy to fulfil a hold
- Params is login session and copy barcode
- Optional param is 'flesh'. If set, we also return the
- relevant copy and title
- login mus have COPY_CHECKIN permissions (since this is essentially
- copy checkin)
- NOTE
-
-# XXX deprecate me XXX
-
-sub capture_copy {
- my( $self, $client, $login_session, $params ) = @_;
- my %params = %$params;
- my $barcode = $params{barcode};
-
-
- my( $user, $target, $copy, $hold, $evt );
-
- ( $user, $evt ) = $apputils->checkses($login_session);
- return $evt if $evt;
-
- # am I allowed to checkin a copy?
- $evt = $apputils->check_perms($user->id, $user->home_ou, "COPY_CHECKIN");
- return $evt if $evt;
-
- $logger->info("Capturing copy with barcode $barcode");
-
- my $session = $apputils->start_db_session();
-
- ($copy, $evt) = $apputils->fetch_copy_by_barcode($barcode);
- return $evt if $evt;
-
- $logger->debug("Capturing copy " . $copy->id);
-
- #( $hold, $evt ) = _find_local_hold_for_copy($session, $copy, $user);
- ( $hold, $evt ) = $self->find_nearest_permitted_hold($session, $copy, $user);
- return $evt if $evt;
-
- warn "Found hold " . $hold->id . "\n";
- $logger->info("We found a hold " .$hold->id. "for capturing copy with barcode $barcode");
-
- $hold->current_copy($copy->id);
- $hold->capture_time("now");
-
- #update the hold
- my $stat = $session->request(
- "open-ils.storage.direct.action.hold_request.update", $hold)->gather(1);
- if(!$stat) { throw OpenSRF::EX::ERROR
- ("Error updating hold request " . $copy->id); }
-
- $copy->status(OILS_COPY_STATUS_ON_HOLDS_SHELF); #status on holds shelf
-
- # if the staff member capturing this item is not at the pickup lib
- if( $user->home_ou ne $hold->pickup_lib ) {
- $self->_build_hold_transit( $login_session, $session, $hold, $user, $copy );
- }
-
- $copy->editor($user->id);
- $copy->edit_date("now");
- $stat = $session->request(
- "open-ils.storage.direct.asset.copy.update", $copy )->gather(1);
- if(!$stat) { throw OpenSRF::EX ("Error updating copy " . $copy->id); }
-
- my $payload = { hold => $hold };
- $payload->{copy} = $copy if $params{flesh_copy};
-
- if($params{flesh_record}) {
- my $record;
- ($record, $evt) = $apputils->fetch_record_by_copy( $copy->id );
- return $evt if $evt;
- $record = $apputils->record_to_mvr($record);
- $payload->{record} = $record;
- }
-
- $apputils->commit_db_session($session);
-
- return OpenILS::Event->new('ROUTE_ITEM',
- route_to => $hold->pickup_lib, payload => $payload );
-}
-
-sub _build_hold_transit {
- my( $self, $login_session, $session, $hold, $user, $copy ) = @_;
- my $trans = Fieldmapper::action::hold_transit_copy->new;
-
- $trans->hold($hold->id);
- $trans->source($user->home_ou);
- $trans->dest($hold->pickup_lib);
- $trans->source_send_time("now");
- $trans->target_copy($copy->id);
- $trans->copy_status($copy->status);
-
- my $meth = $self->method_lookup("open-ils.circ.hold_transit.create");
- my ($stat) = $meth->run( $login_session, $trans, $session );
- if(!$stat) { throw OpenSRF::EX ("Error creating new hold transit"); }
- else { $copy->status(6); } #status in transit
-}
-
-
-
-__PACKAGE__->register_method(
- method => "create_hold_transit",
- api_name => "open-ils.circ.hold_transit.create",
- notes => <<" NOTE");
- Creates a new transit object
- NOTE
-
-sub create_hold_transit {
- my( $self, $client, $login_session, $transit, $session ) = @_;
-
- my( $user, $evt ) = $apputils->checkses($login_session);
- return $evt if $evt;
- $evt = $apputils->check_perms($user->id, $user->home_ou, "CREATE_TRANSIT");
- return $evt if $evt;
-
- my $ses;
- if($session) { $ses = $session; }
- else { $ses = OpenSRF::AppSession->create("open-ils.storage"); }
-
- return $ses->request(
- "open-ils.storage.direct.action.hold_transit_copy.create", $transit )->gather(1);
-}
-
-=cut
-
-
-sub find_local_hold {
- my( $class, $session, $copy, $user ) = @_;
- return $class->find_nearest_permitted_hold($session, $copy, $user);
-}
-
-
-
-
+#sub find_local_hold {
+# my( $class, $session, $copy, $user ) = @_;
+# return $class->find_nearest_permitted_hold($session, $copy, $user);
+#}
sub fetch_open_hold_by_current_copy {
@return ID of the new object on success, Event on error
/
);
-sub create_hold_notify {
+=head old
+sub __create_hold_notify {
my( $self, $conn, $authtoken, $notification ) = @_;
my( $requestor, $evt ) = $U->checkses($authtoken);
return $evt if $evt;
$logger->info("User ".$requestor->id." successfully created new hold notification $id");
return $id;
}
+=cut
+
+sub create_hold_notify {
+ my( $self, $conn, $auth, $note ) = @_;
+ my $e = new_editor(authtoken=>$auth, xact=>1);
+ return $e->die_event unless $e->checkauth;
+
+ my $hold = $e->retrieve_action_hold_request($note->hold)
+ or return $e->die_event;
+ my $patron = $e->retrieve_actor_user($hold->usr)
+ or return $e->die_event;
+
+ return $e->die_event unless
+ $e->allowed('CREATE_HOLD_NOTIFICATION', $patron->home_ou);
+
+ $note->notify_staff($e->requestor->id);
+ $e->create_action_hold_notification($note) or return $e->die_event;
+ $e->commit;
+ return $note->id;
+}
__PACKAGE__->register_method(
my $notices = $e->search_action_hold_notification(
[
{ hold => $hold->id },
- { order_by => { anh => { 'notify_time desc' } } },
+ { order_by => { anh => 'notify_time desc' } },
],
{idlist=>1}
);
$e->allowed('VIEW_HOLD_PERMIT', $patron->home_ou);
}
- return OpenILS::Event->new('PATRON_BARRED')
- if $patron->barred and
- ($patron->barred =~ /t/i or $patron->barred == 1);
+ return OpenILS::Event->new('PATRON_BARRED') if $U->is_true($patron->barred);
my $rangelib = $params{range_lib} || $patron->home_ou;
-sub _check_title_hold_is_possible {
+sub ___check_title_hold_is_possible {
my( $titleid, $rangelib, $depth, $request_lib, $patron, $requestor, $pickup_lib ) = @_;
my $limit = 10;
return 0;
}
+my %prox_cache;
+
+sub _check_title_hold_is_possible {
+ my( $titleid, $rangelib, $depth, $request_lib, $patron, $requestor, $pickup_lib ) = @_;
+
+ my $e = new_editor();
+
+ # this monster will grab the id and circ_lib of all of the "holdable" copies for the given record
+ my $copies = $e->json_query(
+ {
+ select => { acp => ['id', 'circ_lib'] },
+ from => {
+ acp => {
+ acn => {
+ field => 'id',
+ fkey => 'call_number',
+ 'join' => {
+ bre => {
+ field => 'id',
+ filter => { id => $titleid },
+ fkey => 'record'
+ }
+ }
+ },
+ acpl => { field => 'id', filter => { holdable => 't'}, fkey => 'location' },
+ ccs => { field => 'id', filter => { holdable => 't'}, fkey => 'status' }
+ }
+ },
+ where => {
+ '+acp' => { circulate => 't', deleted => 'f', holdable => 't' }
+ }
+ }
+ );
+
+ return $e->event unless defined $copies;
+ $logger->info("title possible found ".scalar(@$copies)." potential copies");
+ return 0 unless @$copies;
+
+ # -----------------------------------------------------------------------
+ # sort the copies into buckets based on their circ_lib proximity to
+ # the patron's home_ou.
+ # -----------------------------------------------------------------------
+
+ my $home_org = $patron->home_ou;
+ my $req_org = $request_lib->id;
+
+ my $home_prox =
+ ($prox_cache{$home_org}) ?
+ $prox_cache{$home_org} :
+ $prox_cache{$home_org} = $e->search_actor_org_unit_proximity({from_org => $home_org});
+
+ my %buckets;
+ my %hash = map { ($_->to_org => $_->prox) } @$home_prox;
+ push( @{$buckets{ $hash{$_->{circ_lib}} } }, $_->{id} ) for @$copies;
+
+ my @keys = sort { $a <=> $b } keys %buckets;
+
+
+ if( $home_org ne $req_org ) {
+ # -----------------------------------------------------------------------
+ # shove the copies close to the request_lib into the primary buckets
+ # directly before the farthest away copies. That way, they are not
+ # given priority, but they are checked before the farthest copies.
+ # -----------------------------------------------------------------------
+ my $req_prox =
+ ($prox_cache{$req_org}) ?
+ $prox_cache{$req_org} :
+ $prox_cache{$req_org} = $e->search_actor_org_unit_proximity({from_org => $req_org});
+
+ my %buckets2;
+ my %hash2 = map { ($_->to_org => $_->prox) } @$req_prox;
+ push( @{$buckets2{ $hash2{$_->{circ_lib}} } }, $_->{id} ) for @$copies;
+
+ my $highest_key = $keys[@keys - 1]; # the farthest prox in the exising buckets
+ my $new_key = $highest_key - 0.5; # right before the farthest prox
+ my @keys2 = sort { $a <=> $b } keys %buckets2;
+ for my $key (@keys2) {
+ last if $key >= $highest_key;
+ push( @{$buckets{$new_key}}, $_ ) for @{$buckets2{$key}};
+ }
+ }
+
+ @keys = sort { $a <=> $b } keys %buckets;
+
+ my $title;
+ my %seen;
+ for my $key (@keys) {
+ my @cps = @{$buckets{$key}};
+
+ $logger->info("looking at " . scalar(@{$buckets{$key}}). " copies in proximity bucket $key");
+
+ for my $copyid (@cps) {
+
+ next if $seen{$copyid};
+ $seen{$copyid} = 1; # there could be dupes given the merged buckets
+ my $copy = $e->retrieve_asset_copy($copyid) or return $e->event;
+ $logger->debug("looking at bucket_key=$key, copy $copyid : circ_lib = " . $copy->circ_lib);
+
+ unless($title) { # grab the title if we don't already have it
+ my $vol = $e->retrieve_asset_call_number(
+ [ $copy->call_number, { flesh => 1, flesh_fields => { acn => ['record'] } } ] );
+ $title = $vol->record;
+ }
+
+ return 1 if verify_copy_for_hold(
+ $patron, $requestor, $title, $copy, $pickup_lib, $request_lib );
+
+ }
+ }
+
+ return 0;
+}
+
+
sub _check_volume_hold_is_possible {
my( $vol, $title, $rangelib, $depth, $request_lib, $patron, $requestor, $pickup_lib ) = @_;
my $copies = new_editor->search_asset_copy({call_number => $vol->id});
sub find_nearest_permitted_hold {
my $class = shift;
- my $session = shift;
- my $copy = shift;
- my $user = shift;
+ my $editor = shift; # CStoreEditor object
+ my $copy = shift; # copy to target
+ my $user = shift; # hold recipient
+ my $check_only = shift; # do no updates, just see if the copy could fulfill a hold
my $evt = OpenILS::Event->new('ACTION_HOLD_REQUEST_NOT_FOUND');
- # first see if this copy has already been selected to fulfill a hold
- my $hold = $session->request(
- "open-ils.storage.direct.action.hold_request.search_where",
- { current_copy => $copy->id, cancel_time => undef, capture_time => undef } )->gather(1);
+ my $bc = $copy->barcode;
- if( $hold ) {
- $logger->info("hold found which can be fulfilled by copy ".$copy->id);
- return $hold;
- }
+ # find any existing holds that already target this copy
+ my $old_holds = $editor->search_action_hold_request(
+ { current_copy => $copy->id,
+ cancel_time => undef,
+ capture_time => undef
+ }
+ );
- # We know this hold is permitted, so just return it
- return $hold if $hold;
+ # hold->type "R" means we need this copy
+ for my $h (@$old_holds) { return ($h) if $h->hold_type eq 'R'; }
- $logger->debug("searching for potential holds at org ".
- $user->ws_ou." and copy ".$copy->id);
+ $logger->info("circulator: searching for best hold at org ".$user->ws_ou." and copy $bc");
- my $holds = $session->request(
+ # search for what should be the best holds for this copy to fulfill
+ my $best_holds = $U->storagereq(
"open-ils.storage.action.hold_request.nearest_hold.atomic",
- $user->ws_ou, $copy->id, 5 )->gather(1);
+ $user->ws_ou, $copy->id, 10 );
+
+ unless(@$best_holds) {
+
+ if( my $hold = $$old_holds[0] ) {
+ $logger->info("circulator: using existing pre-targeted hold ".$hold->id." in hold search");
+ return ($hold);
+ }
+
+ $logger->info("circulator: no suitable holds found for copy $bc");
+ return (undef, $evt);
+ }
+
- return (undef, $evt) unless @$holds;
+ my $best_hold;
# for each potential hold, we have to run the permit script
# to make sure the hold is actually permitted.
-
- for my $holdid (@$holds) {
+ for my $holdid (@$best_holds) {
next unless $holdid;
- $logger->info("Checking if hold $holdid is permitted for user ".$user->id);
-
- my ($hold) = $U->fetch_hold($holdid);
- next unless $hold;
- my ($reqr) = $U->fetch_user($hold->requestor);
+ $logger->info("circulator: checking if hold $holdid is permitted for copy $bc");
- my ($rlib) = $U->fetch_org_unit($hold->request_lib);
+ my $hold = $editor->retrieve_action_hold_request($holdid) or next;
+ my $reqr = $editor->retrieve_actor_user($hold->requestor) or next;
+ my $rlib = $editor->retrieve_actor_org_unit($hold->request_lib) or next;
- return ($hold) if OpenILS::Utils::PermitHold::permit_copy_hold(
- {
- patron_id => $hold->usr,
+ # see if this hold is permitted
+ my $permitted = OpenILS::Utils::PermitHold::permit_copy_hold(
+ { patron_id => $hold->usr,
requestor => $reqr->id,
copy => $copy,
pickup_lib => $hold->pickup_lib,
request_lib => $rlib,
}
);
+
+ if( $permitted ) {
+ $best_hold = $hold;
+ last;
+ }
+ }
+
+
+ unless( $best_hold ) { # no "good" permitted holds were found
+ if( my $hold = $$old_holds[0] ) { # can we return a pre-targeted hold?
+ $logger->info("circulator: using existing pre-targeted hold ".$hold->id." in hold search");
+ return ($hold);
+ }
+
+ # we got nuthin
+ $logger->info("circulator: no suitable holds found for copy $bc");
+ return (undef, $evt);
+ }
+
+ $logger->info("circulator: best hold ".$best_hold->id." found for copy $bc");
+
+ # indicate a permitted hold was found
+ return $best_hold if $check_only;
+
+ # we've found a permitted hold. we need to "grab" the copy
+ # to prevent re-targeted holds (next part) from re-grabbing the copy
+ $best_hold->current_copy($copy->id);
+ $editor->update_action_hold_request($best_hold)
+ or return (undef, $editor->event);
+
+
+ # re-target any other holds that already target this copy
+ for my $old_hold (@$old_holds) {
+ next if $old_hold->id eq $best_hold->id; # don't re-target the hold we want
+ $logger->info("circulator: re-targeting hold ".$old_hold->id.
+ " after a better hold [".$best_hold->id."] was found");
+ $U->storagereq(
+ 'open-ils.storage.action.hold_request.copy_targeter', undef, $old_hold->id );
}
- return (undef, $evt);
+ return ($best_hold);
}
my $approval_code = $payments->{approval_code} || 'n/a';
my $check_number = $payments->{check_number} || 'n/a';
+ my $total_paid = 0;
+
for my $pay (@{$payments->{payments}}) {
my $transid = $pay->[0];
my $amount = $pay->[1];
$amount =~ s/\$//og; # just to be safe
+ $total_paid += $amount;
+
$trans = $self->fetch_mbts($client, $login, $transid);
return $trans if $U->event_code($trans);
}
- $logger->activity("user ".$user->id." applying total ".
+ my $uid = $user->id;
+ $logger->info("user $uid applying total ".
"credit of $credit to user $userid") if $credit != 0;
+ $logger->info("user $uid applying total payment of $total_paid to user $userid");
+
$evt = _update_patron_credit( $session, $userid, $credit );
return $evt if $evt;
/
);
+
sub void_bill {
- my( $s, $c, $authtoken, $billid ) = @_;
+ my( $s, $c, $authtoken, @billids ) = @_;
- #my $e = OpenILS::Utils::Editor->new( authtoken => $authtoken );
my $e = new_editor( authtoken => $authtoken, xact => 1 );
return $e->event unless $e->checkauth;
return $e->event unless $e->allowed('VOID_BILLING');
- my $bill = $e->retrieve_money_billing($billid)
- or return $e->event;
-
- return OpenILS::Event->new('BILL_ALREADY_VOIDED', payload => $bill)
- if $bill->voided and $bill->voided =~ /t/io;
-
- $bill->voided('t');
- $bill->voider($e->requestor->id);
- $bill->void_time('now');
-
- $e->update_money_billing($bill) or return $e->event;
- my $evt = _check_open_xact($e, $bill->xact);
- return $evt if $evt;
+ my %users;
+ for my $billid (@billids) {
+
+ my $bill = $e->retrieve_money_billing($billid)
+ or return $e->event;
+
+ my $xact = $e->retrieve_money_billable_transaction($bill->xact)
+ or return $e->event;
+
+ $users{$xact->usr} = 1;
+
+ return OpenILS::Event->new('BILL_ALREADY_VOIDED', payload => $bill)
+ if $bill->voided and $bill->voided =~ /t/io;
+
+ $bill->voided('t');
+ $bill->voider($e->requestor->id);
+ $bill->void_time('now');
+
+ $e->update_money_billing($bill) or return $e->event;
+ my $evt = _check_open_xact($e, $bill->xact, $xact);
+ return $evt if $evt;
+ }
$e->commit;
-
- # ------------------------------------------------------------------------------
- # Update the patron penalty info in the DB
- # ------------------------------------------------------------------------------
- my $xact = $e->retrieve_money_billable_transaction($bill->xact)
- or return $e->event;
-
- $U->update_patron_penalties(
- authtoken => $authtoken,
- patronid => $xact->usr,
- );
-
+ # update the penalties for each affected user
+ $U->update_patron_penalties( authtoken => $authtoken, patronid => $_ ) for keys %users;
return 1;
}
+
sub _check_open_xact {
- my( $editor, $xactid ) = @_;
+ my( $editor, $xactid, $xact ) = @_;
# Grab the transaction
- my $xact = $editor->retrieve_money_billable_transaction($xactid)
- or return $editor->event;
+ $xact ||= $editor->retrieve_money_billable_transaction($xactid);
+ return $editor->event unless $xact;
+ $xactid ||= $xact->id;
# grab the summary and see how much is owed on this transaction
- my $summary = $editor->retrieve_money_billable_transaction_summary($xactid)
- or return $editor->event;
+ my ($summary) = $U->fetch_mbts($xactid, $editor);
# grab the circulation if it is a circ;
my $circ = $editor->retrieve_action_circulation($xactid);
insert_org_methods( $editor, $runner );
insert_copy_methods( $editor, $ctx, $runner );
+ insert_user_funcs( $editor, $ctx, $runner );
return $runner;
}
$runner->insert_method( 'environment.copy', '__OILS_FUNC_fetch_best_hold', sub {
my $key = shift;
$logger->debug("script_builder: searching for permitted hold for copy ".$copy->barcode);
- my ($hold) = $holdcode->find_nearest_permitted_hold(
- OpenSRF::AppSession->create('open-ils.storage'), $copy, $reqr );
+ my ($hold) = $holdcode->find_nearest_permitted_hold( $e, $copy, $reqr, 1 ); # do we need a new editor here since the xact may be dead??
$runner->insert( $key, $hold, 1 );
}
);
}
}
+sub insert_user_funcs {
+ my( $e, $ctx, $runner ) = @_;
+
+ # tells how many holds a user has
+ $runner->insert(__OILS_FUNC_userHoldCount =>
+ sub {
+ my( $write_key, $userid ) = @_;
+ my $val = $holdcode->__user_hold_count(new_editor(), $userid);
+ $logger->info("script_runner: user hold count is $val");
+ $runner->insert($write_key, $val, 1) if $val;
+ return $val;
+ }
+ );
+}
api_name => 'open-ils.collections.users_of_interest.retrieve',
api_level => 1,
argc => 4,
+ stream => 1,
signature => {
desc => q/
Returns an array of user information objects that the system
# they need global perms to view users so no org is provided
return $e->event unless $e->allowed('VIEW_USER');
- my $data = $U->storagereq(
- 'open-ils.storage.money.collections.users_of_interest.atomic',
- $age, $fine_level, $location);
-
- return [] unless $data and @$data;
-
- for (@$data) {
- my $u = $e->retrieve_actor_user(
- [
- $_->{usr},
- {
- flesh => 1,
- flesh_fields => {au => ["groups","profile", "card"]},
- select => {au => ["profile","id","dob", "card"]}
- }
- ]
- ) or return $e->event;
-
- $_->{usr} = {
- id => $u->id,
- dob => $u->dob,
- profile => $u->profile->name,
- barcode => $u->card->barcode,
- groups => [ map { $_->name } @{$u->groups} ],
- };
- }
-
- return $data;
+ my $data = [];
+
+ my $ses = OpenSRF::AppSession->create('open-ils.storage');
+
+ my $start = time;
+ my $req = $ses->request(
+ 'open-ils.storage.money.collections.users_of_interest',
+ $age, $fine_level, $location);
+
+ # let the client know we're still here
+ $conn->status( new OpenSRF::DomainObject::oilsContinueStatus );
+
+ my $total;
+ while( my $resp = $req->recv(timeout => 600) ) {
+ return $req->failed if $req->failed;
+ my $hash = $resp->content;
+ next unless $hash;
+
+ unless($total) {
+ $total = time - $start;
+ $logger->info("collections: users_of_interest ".
+ "($age, $fine_level, $location) took $total seconds");
+ }
+
+ my $u = $e->retrieve_actor_user(
+ [
+ $hash->{usr},
+ {
+ flesh => 1,
+ flesh_fields => {au => ["groups","profile", "card"]},
+ #select => {au => ["profile","id","dob", "card"]}
+ }
+ ]
+ ) or return $e->event;
+
+ $hash->{usr} = {
+ id => $u->id,
+ dob => $u->dob,
+ profile => $u->profile->name,
+ barcode => $u->card->barcode,
+ groups => [ map { $_->name } @{$u->groups} ],
+ };
+
+ $conn->respond($hash);
+ }
+
+ return undef;
}
api_name => 'open-ils.collections.users_with_activity.retrieve',
api_level => 1,
argc => 4,
+ stream => 1,
signature => {
desc => q/
Returns an array of users that are already in collections
my $org = $e->search_actor_org_unit({shortname => $location})
or return $e->event; $org = $org->[0];
- return $e->event unless $e->allowed('VIEW_USER', $org->id);
+ return $e->event unless $e->allowed('VIEW_USER', $org->id);
+
+ my $ses = OpenSRF::AppSession->create('open-ils.storage');
- return $U->storagereq(
+ my $start = time;
+ my $req = $ses->request(
'open-ils.storage.money.collections.users_with_activity.atomic',
$start_date, $end_date, $location);
+
+ $conn->status( new OpenSRF::DomainObject::oilsContinueStatus );
+
+ my $total;
+ while( my $resp = $req->recv(timeout => 600) ) {
+
+ unless($total) {
+ $total = time - $start;
+ $logger->info("collections: users_with_activity search ".
+ "($start_date, $end_date, $location) took $total seconds");
+ }
+
+ return $req->failed if $req->failed;
+ $conn->respond($resp->content);
+ }
+
+ return undef;
}
sub biblio_search_tcn {
- my( $self, $client, $tcn ) = @_;
+ my( $self, $client, $tcn, $include_deleted ) = @_;
$tcn =~ s/.*?(\w+)\s*$/$1/o;
my $e = new_editor();
- my $recs = $e->search_biblio_record_entry(
- {deleted => 'f', tcn_value => $tcn}, {idlist =>1});
+ my $search = {tcn_value => $tcn};
+ $search->{deleted} = 'f' unless $include_deleted;
+ my $recs = $e->search_biblio_record_entry( $search, {idlist =>1} );
return { count => scalar(@$recs), ids => $recs };
}
return { count => 0 };
}
+__PACKAGE__->register_method(
+ method => 'title_id_by_item_barcode',
+ api_name => 'open-ils.search.bib_id.by_barcode'
+);
+
+sub title_id_by_item_barcode {
+ my( $self, $conn, $barcode ) = @_;
+ my $e = new_editor();
+ my $copies = $e->search_asset_copy(
+ [
+ { deleted => 'f', barcode => $barcode },
+ {
+ flesh => 2,
+ flesh_fields => {
+ acp => [ 'call_number' ],
+ acn => [ 'record' ]
+ }
+ }
+ ]
+ );
+
+ return $e->event unless @$copies;
+ return $$copies[0]->call_number->record->id;
+}
+
__PACKAGE__->register_method(
method => "biblio_copy_to_mods",
my $recs = search_cache($ckey, $offset, $limit);
if(!$recs) {
- $recs = $U->storagereq($method, %$args);
- put_cache($ckey, scalar(@$recs), $recs);
- $recs = [ @$recs[$offset..($offset + ($limit - 1))] ];
+ $recs = $U->storagereq($method, %$args) || [];
+ if( $recs ) {
+ put_cache($ckey, scalar(@$recs), $recs);
+ $recs = [ @$recs[$offset..($offset + ($limit - 1))] ];
+ } else {
+ $recs = [];
+ }
}
my $count = 0;
'Z3950_BAD_QUERY', payload => $query, debug => "$err") if $err;
return OpenILS::Event->new('Z3950_SEARCH_FAILED',
- debug => $connection->errcode.":".$connection->errmsg) unless $results;
+ debug => $connection->errcode." => ".$connection->errmsg." : query = $query") unless $results;
$logger->info("z3950: search [$query] took ".(time - $start)." seconds");
my $str = "";
$str .= "\@$seperator " for (1..$count-1);
+ # -------------------------------------------------------------------
+ # "code" is the bib-1 "use attribute", "format" is the bib-1
+ # "structure attribute"
+ # -------------------------------------------------------------------
for( keys %$hash ) {
- $str .= '@attr ' .
- $services{$service}->{attrs}->{$_}->{format} . '=' .
- $services{$service}->{attrs}->{$_}->{code} . " \"" . $$hash{$_} . "\" ";
+# $str .= '@attr ' .
+# $services{$service}->{attrs}->{$_}->{format} . '=' .
+# $services{$service}->{attrs}->{$_}->{code} . " \"" . $$hash{$_} . "\" ";
+ $str .=
+ '@attr 1=' . $services{$service}->{attrs}->{$_}->{code} . # add the use attribute
+ ' @attr 4=' . $services{$service}->{attrs}->{$_}->{format} . # add teh structure attribute
+ " \"" . $$hash{$_} . "\" "; # add the search term
}
return $str;
}
}
$stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
+
+ # strip some other unfriendly chars that may leak in
+ $stuff =~ s/([\x{0000}-\x{0008}])//sgoe;
+
return $stuff;
}
__PACKAGE__->table( 'actor_org_unit' );
__PACKAGE__->columns( Primary => qw/id/);
__PACKAGE__->columns( Essential => qw/parent_ou ou_type mailing_address billing_address
- ill_address holds_address shortname name email phone/);
+ ill_address holds_address shortname name email phone opac_visible/);
#-------------------------------------------------------------------------------
package actor::org_unit::hours_of_operation;
my $master_db;
my @slave_dbs;
my $_db_params;
+
+ sub db_Handles {
+ return ($master_db, @slave_dbs);
+ }
+
sub child_init {
my $self = shift;
$_db_params = shift;
{
package OpenILS::Application::Storage;
use OpenSRF::Utils::Logger;
+
our $NOPRIMARY = 0;
my $log = 'OpenSRF::Utils::Logger';
-
my $pg = 'OpenILS::Application::Storage::Driver::Pg';
+ sub child_exit {
+ $_->disconnect for $pg->db_Handles;
+ }
sub current_xact {
my $self = shift;
my $cp = shift;
my $limit = int(shift()) || 10;
- my ($id) = action::hold_request->db_Main->selectrow_array(<<" SQL", {}, $cp, $pl);
+ my $ids = action::hold_request->db_Main->selectcol_arrayref(<<" SQL", {}, $cp, $pl);
SELECT h.id
FROM action.hold_request h
JOIN action.hold_copy_map hm ON (hm.hold = h.id)
h.request_time
LIMIT $limit
SQL
- return $id;
+
+ $client->respond( $_ ) for ( @$ids );
+ return undef;
}
__PACKAGE__->register_method(
api_name => 'open-ils.storage.action.hold_request.nearest_hold',
try {
if ($one_hold) {
+ $self->method_lookup('open-ils.storage.transaction.begin')->run( $client );
$holds = [ action::hold_request->search_where( { id => $one_hold, fulfillment_time => undef, cancel_time => undef } ) ];
} elsif ( $check_expire ) {
};
my @closed = actor::org_unit::closed_date->search_where(
- { close_start => { '<=', 'today' },
- close_end => { '>=', 'today' } }
+ { close_start => { '<=', 'now' },
+ close_end => { '>=', 'now' } }
);
for my $hold (@$holds) {
try {
- #first, re-fetch the hold, to make sure it's not captured already
- $hold = action::hold_request->retrieve( $hold->id );
- die "OK\n" if (!$hold or $hold->capture_time);
-
#start a transaction if needed
if ($self->method_lookup('open-ils.storage.transaction.current')->run) {
$log->debug("Cleaning up after previous transaction\n");
$self->method_lookup('open-ils.storage.transaction.begin')->run( $client );
$log->info("Processing hold ".$hold->id."...\n");
+ #first, re-fetch the hold, to make sure it's not captured already
+ $hold = action::hold_request->retrieve( $hold->id );
+ die "OK\n" if (!$hold or $hold->capture_time);
+
# remove old auto-targeting maps
my @oldmaps = action::hold_copy_map->search( hold => $hold->id );
$_->delete for (@oldmaps);
-
my $all_copies = [];
# find filters for MR holds
for my $cn ( @{ $rtree->call_numbers } ) {
push @$all_copies,
- asset::copy->search( id => [map {$_->id} @{ $cn->copies }] );
+ asset::copy->search_where(
+ { id => [map {$_->id} @{ $cn->copies }],
+ deleted => 'f' }
+ ) if ($cn && @{ $cn->copies });
}
}
} elsif ($hold->hold_type eq 'T') {
for my $cn ( @{ $rtree->call_numbers } ) {
push @$all_copies,
- asset::copy->search( id => [map {$_->id} @{ $cn->copies }] );
+ asset::copy->search_where(
+ { id => [map {$_->id} @{ $cn->copies }],
+ deleted => 'f' }
+ ) if ($cn && @{ $cn->copies });
}
} elsif ($hold->hold_type eq 'V') {
my ($vtree) = $self
->run( $hold->target, $hold->selection_ou, $hold->selection_depth );
push @$all_copies,
- asset::copy->search( id => [map {$_->id} @{ $vtree->copies }] );
+ asset::copy->search_where(
+ { id => [map {$_->id} @{ $vtree->copies }],
+ deleted => 'f' }
+ ) if ($vtree && @{ $vtree->copies });
- } elsif ($hold->hold_type eq 'C') {
-
- $all_copies = [asset::copy->retrieve($hold->target)];
+ } elsif ($hold->hold_type eq 'C' || $hold->hold_type eq 'R' || $hold->hold_type eq 'F') {
+ my $_cp = asset::copy->retrieve($hold->target);
+ push @$all_copies, $_cp if $_cp;
}
# trim unholdables
@$all_copies = grep { isTrue($_->status->holdable) &&
isTrue($_->location->holdable) &&
- isTrue($_->holdable)
+ isTrue($_->holdable) &&
+ !isTrue($_->deleted)
} @$all_copies;
# let 'em know we're still working
$log->info("\tNo copies available for targeting at all!\n");
push @successes, { hold => $hold->id, eligible_copies => 0, error => 'NO_COPIES' };
- $hold->update( { prev_check_time => 'today' } );
+ $hold->update( { prev_check_time => 'today', current_copy => undef } );
$self->method_lookup('open-ils.storage.transaction.commit')->run;
die "OK\n";
}
my @good_copies;
for my $c (@$all_copies) {
# current target
- next if ($c->id == $hold->current_copy);
+ next if ($c->id eq $hold->current_copy);
# circ lib is closed
- next if ( grep { ''.$_->org_unit == ''.$c->circ_lib } @closed );
+ next if ( grep { ''.$_->org_unit eq ''.$c->circ_lib } @closed );
# target of another hold
next if (action::hold_request
if ($best) {
$hold->update( { current_copy => ''.$best->id, prev_check_time => 'now' } );
$log->debug("\tUpdating hold [".$hold->id."] with new 'current_copy' [".$best->id."] for hold fulfillment.");
+ } elsif (
+ $old_best &&
+ action::hold_request
+ ->search_where(
+ { current_copy => $old_best->id,
+ fulfillment_time => undef,
+ cancel_time => undef,
+ }
+ )
+ ) {
+ $hold->update( { prev_check_time => 'now', current_copy => ''.$old_best->id } );
+ $log->debug( "\tRetargeting the previously targeted copy [".$old_best->id."]" );
} else {
$hold->update( { prev_check_time => 'now' } );
$log->info( "\tThere were no targetable copies for the hold" );
my $rand = int(rand(scalar(@capturable)));
while (my ($c) = splice(@capturable,$rand)) {
- unless ( OpenILS::Utils::PermitHold::permit_copy_hold(
+ return $c if ( OpenILS::Utils::PermitHold::permit_copy_hold(
{ title => $c->call_number->record->to_fieldmapper,
title_descriptor => $c->call_number->record->record_descriptor->next->to_fieldmapper,
patron => $hold->usr->to_fieldmapper,
requestor => $hold->requestor->to_fieldmapper,
request_lib => $hold->request_lib->to_fieldmapper,
}
- )) {
- last unless(@capturable);
- $rand = int(rand(scalar(@capturable)));
- next;
- }
- return $c;
+ ));
+
+ last unless(@capturable);
+ $rand = int(rand(scalar(@capturable)));
}
}
}
WHERE ? between close_start and close_end
AND org_unit = ?
ORDER BY close_start ASC, close_end DESC
+ LIMIT 1
SQL
$date = clense_ISO8601($date);
+ my ($begin, $end) = ($date,$date);
- my $sth = actor::org_unit::closed_date->db_Main->prepare( $sql );
- $sth->execute($date, $ou);
-
- my ($begin, $end);
- while (my $closure = $sth->fetchrow_hashref) {
- $begin ||= clense_ISO8601($closure->{close_start});
+ my $hoo = actor::org_unit::hours_of_operation->retrieve($ou);
+
+ if (my $closure = actor::org_unit::closed_date->db_Main->selectrow_hashref( $sql, {}, $date, $ou )) {
+ $begin = clense_ISO8601($closure->{close_start});
$end = clense_ISO8601($closure->{close_end});
if ( $direction <= 0 ) {
}
$end = clense_ISO8601($after->iso8601);
}
-
}
- $begin ||= $date;
- $end ||= $date;
-
-
if ( !$no_hoo ) {
- if ( my $hoo = actor::org_unit::hours_of_operation->retrieve($ou) ) {
+ if ( $hoo ) {
my $begin_dow = $_dt_parser->parse_datetime( $begin )->day_of_week_0;
my $begin_open_meth = "dow_".$begin_dow."_open";
$begin_open_meth = "dow_".$begin_dow."_open";
$begin_close_meth = "dow_".$begin_dow."_close";
}
+
+ if (my $closure = actor::org_unit::closed_date->db_Main->selectrow_hashref( $sql, {}, $begin, $ou )) {
+ $before = $_dt_parser->parse_datetime( $begin );
+ $before->subtract( minutes => 1 );
+ while ( my $_b = org_closed_overlap($self, $client, $ou, $before->iso8601, -1 ) ) {
+ $before = $_dt_parser->parse_datetime( clense_ISO8601($_b->{start}) );
+ }
+ }
my $end_dow = $_dt_parser->parse_datetime( $end )->day_of_week_0;
my $end_open_meth = "dow_".$end_dow."_open";
$end_open_meth = "dow_".$end_dow."_open";
$end_close_meth = "dow_".$end_dow."_close";
}
+
+ if (my $closure = actor::org_unit::closed_date->db_Main->selectrow_hashref( $sql, {}, $end, $ou )) {
+ $after = $_dt_parser->parse_datetime( $end );
+ $after->add( minutes => 1 );
+
+ while ( my $_a = org_closed_overlap($self, $client, $ou, $after->iso8601, 1 ) ) {
+ $after = $_dt_parser->parse_datetime( clense_ISO8601($_a->{end}) );
+ }
+ $end = clense_ISO8601($after->iso8601);
+ }
+
}
}
my $limit = shift || 1000;
my $sort = shift;
my $inactive = shift;
+
$sort = ['family_name','first_given_name'] unless ($$sort[0]);
+ push @$sort,'id';
# group 0 = user
# group 1 = address
return undef;
}
- my $order_by = join ', ', map { 'users.'. $_} @$sort;
+ my $order_by = join ', ', map { 'LOWER(users.'. (split / /,$_)[0] . ') ' . (split / /,$_)[1] } @$sort;
+ my $distinct_list = join ', ', map { 'LOWER(users.'. (split / /,$_)[0] . ')' } @$sort;
if ($inactive) {
$inactive = '';
}
$select = <<" SQL";
- SELECT users.id
+ SELECT DISTINCT $distinct_list
FROM $u_table AS users
JOIN ($select) AS search
USING (id)
LIMIT $limit
SQL
- return actor::user->db_Main->selectcol_arrayref($select, {}, map {lc($_)} (@usrv,@phonev,@identv,@namev,@addrv,@addrv));
+ return actor::user->db_Main->selectcol_arrayref($select, {Columns=>[scalar(@$sort)]}, map {lc($_)} (@usrv,@phonev,@identv,@namev,@addrv,@addrv));
}
__PACKAGE__->register_method(
api_name => 'open-ils.storage.actor.user.crazy_search',
$cn = asset::call_number->retrieve( $cn );
return undef unless ($cn);
+ return undef if ($cn->deleted);
my $call_number = $cn->to_fieldmapper;
$call_number->copies([]);
$call_number->record->fixed_fields( $cn->record->record_descriptor->next->to_fieldmapper );
for my $cp ( $cn->copies(circ_lib => $ou_list) ) {
+ next if ($cp->deleted);
my $copy = $cp->to_fieldmapper;
$copy->status( $cp->status->to_fieldmapper );
$copy->location( $cp->status->to_fieldmapper );
my $offset_count = 0;
my $limit_count = 0;
for my $cn ( $r->call_numbers ) {
+ next if ($cn->deleted);
my $call_number = $cn->to_fieldmapper;
$call_number->copies([]);
for my $cp ( $cn->copies(circ_lib => $ou_list) ) {
+ next if ($cp->deleted);
if ($offset > 0 && $offset_count < $offset) {
$offset_count++;
next;
"actor.org_unit_descendants($org)" ;
- my $copies_visible = 'AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
+ my $copies_visible = 'AND d.opac_visible IS TRUE AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
$copies_visible = '' if ($self->api_name =~ /staff/o);
my $sm_table = metabib::metarecord_source_map->table;
$isxn =~ s/\s*$//o;
$isxn =~ s/-//o if ($self->api_name =~ /isbn/o);
- my $tag = ($self->api_name =~ /isbn/o) ? "'020' OR tag = '024'" : "'022'";
+ my $tag = ($self->api_name =~ /isbn/o) ? "'020' OR f.tag = '024'" : "'022'";
my $fr_table = metabib::full_rec->table;
+ my $bib_table = biblio::record_entry->table;
my $sql = <<" SQL";
- SELECT record
- FROM $fr_table
- WHERE (tag = $tag)
- AND value LIKE ?
+ SELECT DISTINCT f.record
+ FROM $fr_table f
+ JOIN $bib_table b ON (b.id = f.record)
+ WHERE (f.tag = $tag)
+ AND f.value LIKE ?
+ AND b.deleted IS FALSE
SQL
- my $list = metabib::metarecord_source_map->db_Main->selectcol_arrayref($sql, {}, "$isxn%");
+ my $list = metabib::full_rec->db_Main->selectcol_arrayref($sql, {}, "$isxn%");
$client->respond($_) for (@$list);
return undef;
}
my $descendants = "actor.org_unit_descendants(u.id)";
my $ancestors = "actor.org_unit_ancestors(?)";
- my $copies_visible = 'AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
+ my $copies_visible = 'AND a.opac_visible IS TRUE AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
$copies_visible = '' if ($self->api_name =~ /staff/o);
my (@types,@forms);
my $has_vols = 'AND cn.owning_lib = d.id';
my $has_copies = 'AND cp.call_number = cn.id';
- my $copies_visible = 'AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
+ my $copies_visible = 'AND d.opac_visible IS TRUE AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
if ($self->api_name =~ /staff/o) {
$copies_visible = '';
my $has_vols = 'AND cn.owning_lib = d.id';
my $has_copies = 'AND cp.call_number = cn.id';
- my $copies_visible = 'AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
+ my $copies_visible = 'AND d.opac_visible IS TRUE AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
my $visible_count = ', count(DISTINCT cp.id)';
my $visible_count_test = 'HAVING count(DISTINCT cp.id) > 0';
my $has_vols = 'AND cn.owning_lib = d.id';
my $has_copies = 'AND cp.call_number = cn.id';
- my $copies_visible = 'AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
+ my $copies_visible = 'AND d.opac_visible IS TRUE AND cp.opac_visible IS TRUE AND cs.holdable IS TRUE AND cl.opac_visible IS TRUE';
if ($self->api_name =~ /staff/o) {
$copies_visible = '';
$has_vols = '' if ($ou_type == 0);
AND cp.opac_visible IS TRUE
AND cs.holdable IS TRUE
AND cl.opac_visible IS TRUE
+ AND d.opac_visible IS TRUE
AND br.active IS TRUE
AND br.deleted IS FALSE
AND ord.record = mrs.source
AND cp.opac_visible IS TRUE
AND cs.holdable IS TRUE
AND cl.opac_visible IS TRUE
+ AND d.opac_visible IS TRUE
AND br.active IS TRUE
AND br.deleted IS FALSE
AND ord.record = mrs.source
my %bonus = ();
$bonus{'keyword'} = [ { "CASE WHEN $search_class.value LIKE ? THEN 10 ELSE 1 END" => $SQLstring } ];
+ $bonus{'author'} = [ { "CASE WHEN $search_class.value ILIKE ? THEN 10 ELSE 1 END" => $first_word } ];
$bonus{'series'} = [
{ "CASE WHEN $search_class.value LIKE ? THEN 1.5 ELSE 1 END" => $first_word },
AND cp.opac_visible IS TRUE
AND cs.holdable IS TRUE
AND cl.opac_visible IS TRUE
+ AND d.opac_visible IS TRUE
AND br.active IS TRUE
AND br.deleted IS FALSE
AND cp.deleted IS FALSE
my %bonus = ();
$bonus{'subject'} = [];
- $bonus{'author'} = [];
+ $bonus{'author'} = [ { "CASE WHEN $search_class.value ILIKE ? THEN 1.5 ELSE 1 END" => $first_word } ];
$bonus{'keyword'} = [ { "CASE WHEN $search_class.value ILIKE ? THEN 10 ELSE 1 END" => $SQLstring } ];
AND cp.opac_visible IS TRUE
AND cs.holdable IS TRUE
AND cl.opac_visible IS TRUE
+ AND d.opac_visible IS TRUE
AND cp.deleted IS FALSE
AND cn.deleted IS FALSE
LIMIT 1
my $descendants = "actor.org_unit_descendants((select id from actor.org_unit where shortname = ?))";
my $SQL = <<" SQL";
- SELECT lt.usr,
- MAX(bl.billing_ts) AS last_pertinent_billing,
- SUM(bl.amount) - COALESCE(SUM((SELECT SUM(amount) FROM money.payment WHERE xact = lt.id)),0) AS threshold_amount
- FROM ( SELECT id,usr,billing_location AS location FROM money.grocery
- UNION ALL
- SELECT id,usr,circ_lib AS location FROM action.circulation ) AS lt
- JOIN $descendants d ON (lt.location = d.id)
- JOIN money.billing bl ON (lt.id = bl.xact AND bl.voided IS FALSE)
- WHERE AGE(bl.billing_ts) > ?
- GROUP BY lt.usr
- HAVING SUM(
- (SELECT COUNT(*)
- FROM money.collections_tracker
- WHERE usr = lt.usr
- AND location in (
- (SELECT id
- FROM $descendants )
- )
- ) ) = 0
- AND (SUM(bl.amount) - COALESCE(SUM((SELECT SUM(amount) FROM money.payment WHERE xact = lt.id)),0)) > ?
+
+select
+ usr,
+ MAX(last_billing) as last_pertinent_billing,
+ SUM(total_billing) - SUM(COALESCE(p.amount,0)) as threshold_amount
+ from (select
+ x.id,
+ x.usr,
+ MAX(b.billing_ts) as last_billing,
+ SUM(b.amount) AS total_billing
+ from action.circulation x
+ left join money.collections_tracker c ON (c.usr = x.usr AND c.location = ?)
+ join money.billing b on (b.xact = x.id)
+ where x.xact_finish is null
+ and c.id is null
+ and x.circ_lib in (XX)
+ and b.billing_ts < current_timestamp - ? * '1 day'::interval
+ and not b.voided
+ group by 1,2
+
+ union all
+
+ select
+ x.id,
+ x.usr,
+ MAX(b.billing_ts) as last_billing,
+ SUM(b.amount) AS total_billing
+ from money.grocery x
+ left join money.collections_tracker c ON (c.usr = x.usr AND c.location = ?)
+ join money.billing b on (b.xact = x.id)
+ where x.xact_finish is null
+ and c.id is null
+ and x.billing_location in (XX)
+ and b.billing_ts < current_timestamp - ? * '1 day'::interval
+ and not b.voided
+ group by 1,2
+ ) full_list
+ left join money.payment p on (full_list.id = p.xact)
+ group by 1
+ having SUM(total_billing) - SUM(COALESCE(p.amount,0)) > ?
+;
SQL
my @l_ids;
for my $l (@loc) {
- my $sth = money::collections_tracker->db_Main->prepare($SQL);
- $sth->execute(uc($l), $age, uc($l), $amount );
+ my ($org) = actor::org_unit->search( shortname => uc($l) );
+ next unless $org;
+
+ my $o_list = actor::org_unit->db_Main->selectcol_arrayref( "SELECT id FROM actor.org_unit_descendants(?);", {}, $org->id );
+ next unless (@$o_list);
+
+ my $o_txt = join ',' => @$o_list;
+
+ (my $real_sql = $SQL) =~ s/XX/$o_txt/gsm;
+
+ my $sth = money::collections_tracker->db_Main->prepare($real_sql);
+ $sth->execute( $org->id, $age, $org->id, $age, $amount );
+
while (my $row = $sth->fetchrow_hashref) {
#$row->{usr} = actor::user->retrieve($row->{usr})->to_fieldmapper;
$client->respond( $row );
my $mb = money::billing->table;
my $circ = action::circulation->table;
my $mg = money::grocery->table;
- my $descendants = "actor.org_unit_descendants((select id from actor.org_unit where shortname = ?))";
my $SQL = <<" SQL";
- SELECT lt.usr,
- MAX(bl.billing_ts) AS last_pertinent_billing,
- MAX(pm.payment_ts) AS last_pertinent_payment
- FROM ( SELECT id,usr,billing_location AS location, 'g'::char AS x_type FROM money.grocery
- UNION ALL
- SELECT id,usr,circ_lib AS location, 'c'::char AS x_type FROM action.circulation
- UNION ALL
- SELECT id,usr,circ_lib AS location, 'i'::char AS x_type FROM action.circulation
- WHERE checkin_time between ? and ? ) AS lt
- JOIN $descendants d ON (lt.location = d.id)
- JOIN money.collections_tracker cl ON (lt.usr = cl.usr)
- LEFT JOIN money.billing bl ON (lt.id = bl.xact)
- LEFT JOIN money.payment pm ON (lt.id = pm.xact)
- WHERE bl.billing_ts between ? and ?
- OR pm.payment_ts between ? and ?
- OR lt.x_type = 'i'::char
- GROUP BY 1
+SELECT usr,
+ MAX(last_pertinent_billing) AS last_pertinent_billing,
+ MAX(last_pertinent_payment) AS last_pertinent_payment
+ FROM (
+ SELECT lt.usr,
+ MAX(bl.billing_ts) AS last_pertinent_billing,
+ NULL::TIMESTAMPTZ AS last_pertinent_payment
+ FROM money.grocery lt
+ JOIN money.collections_tracker cl ON (lt.usr = cl.usr)
+ JOIN money.billing bl ON (lt.id = bl.xact)
+ WHERE cl.location = ?
+ AND lt.billing_location IN (XX)
+ AND bl.billing_ts BETWEEN ? AND ?
+ GROUP BY 1
+
+ UNION ALL
+ SELECT lt.usr,
+ NULL::TIMESTAMPTZ AS last_pertinent_billing,
+ MAX(pm.payment_ts) AS last_pertinent_payment
+ FROM money.grocery lt
+ JOIN money.collections_tracker cl ON (lt.usr = cl.usr)
+ JOIN money.payment pm ON (lt.id = pm.xact)
+ WHERE cl.location = ?
+ AND lt.billing_location IN (XX)
+ AND pm.payment_ts BETWEEN ? AND ?
+ GROUP BY 1
+
+ UNION ALL
+ SELECT lt.usr,
+ NULL::TIMESTAMPTZ AS last_pertinent_billing,
+ NULL::TIMESTAMPTZ AS last_pertinent_payment
+ FROM action.circulation lt
+ JOIN money.collections_tracker cl ON (lt.usr = cl.usr)
+ WHERE cl.location = ?
+ AND lt.circ_lib IN (XX)
+ AND lt.checkin_time BETWEEN ? AND ?
+ GROUP BY 1
+
+ UNION ALL
+ SELECT lt.usr,
+ NULL::TIMESTAMPTZ AS last_pertinent_billing,
+ MAX(pm.payment_ts) AS last_pertinent_payment
+ FROM action.circulation lt
+ JOIN money.collections_tracker cl ON (lt.usr = cl.usr)
+ JOIN money.payment pm ON (lt.id = pm.xact)
+ WHERE cl.location = ?
+ AND lt.circ_lib IN (XX)
+ AND pm.payment_ts BETWEEN ? AND ?
+ GROUP BY 1
+
+ UNION ALL
+ SELECT lt.usr,
+ MAX(bl.billing_ts) AS last_pertinent_billing,
+ NULL::TIMESTAMPTZ AS last_pertinent_payment
+ FROM action.circulation lt
+ JOIN money.collections_tracker cl ON (lt.usr = cl.usr)
+ JOIN money.billing bl ON (lt.id = bl.xact)
+ WHERE cl.location = ?
+ AND lt.circ_lib IN (XX)
+ AND bl.billing_ts BETWEEN ? AND ?
+ GROUP BY 1
+ ) foo
+ GROUP BY 1
+;
SQL
my @l_ids;
for my $l (@loc) {
- my $sth = money::collections_tracker->db_Main->prepare($SQL);
- $sth->execute( $startdate, $enddate, uc($l), $startdate, $enddate, $startdate, $enddate );
+ my ($org) = actor::org_unit->search( shortname => uc($l) );
+ next unless $org;
+
+ my $o_list = actor::org_unit->db_Main->selectcol_arrayref( "SELECT id FROM actor.org_unit_descendants(?);", {}, $org->id );
+ next unless (@$o_list);
+
+ my $o_txt = join ',' => @$o_list;
+
+ (my $real_sql = $SQL) =~ s/XX/$o_txt/gsm;
+
+ my $sth = money::collections_tracker->db_Main->prepare($real_sql);
+ $sth->execute(
+ $org->id, $startdate, $enddate,
+ $org->id, $startdate, $enddate,
+ $org->id, $startdate, $enddate,
+ $org->id, $startdate, $enddate,
+ $org->id, $startdate, $enddate
+ );
+
while (my $row = $sth->fetchrow_hashref) {
$row->{usr} = actor::user->retrieve($row->{usr})->to_fieldmapper;
$client->respond( $row );
# ---------------------------------------------------------------------
econst OILS_SETTING_LOST_PROCESSING_FEE => 'circ.lost_materials_processing_fee';
econst OILS_SETTING_DEF_ITEM_PRICE => 'cat.default_item_price';
+econst OILS_SETTING_ORG_BOUNCED_EMAIL => 'org.bounced_emails';
return $self->{_sql} = $self->$toSQL;
}
+#-------------------------------------------------------------------------------------------------
+package OpenILS::Reporter::SQLBuilder::Input::Transform::GenericTransform;
+
+sub toSQL {
+ my $self = shift;
+ my $func = $self->{transform};
+
+ my @params;
+ @params = @{ $self->{params} } if ($self->{params});
+
+ my $sql = $func . '(\'';
+ $sql .= join("','", @params) if (@params);
+ $sql .= '\')';
+
+ return $sql;
+}
+
#-------------------------------------------------------------------------------------------------
package OpenILS::Reporter::SQLBuilder::Input::Transform::NULL;
sub toSQL {
my $self = shift;
- return 'DATE_TRUNC("' . $self->{_relation} . '"."' . $self->name . '")';
+ return 'EXTRACT(HOUR FROM "' . $self->{_relation} . '"."' . $self->name . '")';
}
sub is_aggregate { return 0 }
my $self = shift;
syslog('LOG_DEBUG', 'OILS: Patron->fee_amount()');
- my $total = 0;
- my $e = OpenILS::SIP->editor();
- my $xacts = $e->search_money_open_billable_transaction_summary(
- { usr => $self->{user}->id, balance_owed => { '!=' => 0 } } );
+ my $ses = $U->start_db_session();
+ my $summary = $ses->request(
+ 'open-ils.storage.money.open_user_summary.search', $self->{user}->id )->gather(1);
+ $U->rollback_db_session($ses);
- $total += $_->balance_owed for @$xacts;
- syslog('LOG_INFO', "User ".$self->{user}->id." has a fee amount of \$$total");
+ my $total = $summary->balance_owed;
+ syslog('LOG_INFO', "User ".$self->{id} .':'.$self->{user}->id." has a fee amount of \$$total");
return $total;
}
# -----------------------------------------------------------------------------
sub xact_rollback {
my $self = shift;
+ return unless $self->{session};
$self->log(I, "rolling back db session");
return $self->request($self->app.".transaction.rollback");
}
sub rollback {
my $self = shift;
$self->xact_rollback if $self->{xact};
+ delete $self->{xact};
$self->disconnect;
}
sub disconnect {
my $self = shift;
$self->session->disconnect if $self->{session};
+ delete $self->{session};
}
}
try {
- $val = $self->session->request($method, @params)->gather(1);
+
+ my $req = $self->session->request($method, @params);
+
+ if( $self->substream ) {
+ $self->log(D,"running in substream mode");
+ $val = [];
+ while( my $resp = $req->recv ) {
+ push(@$val, $resp->content) if $resp->content;
+ }
+ } else {
+ $val = $req->gather(1);
+ }
+
+ #$val = $self->session->request($method, @params)->gather(1);
} catch Error with {
$err = shift;
return $val;
}
+sub substream {
+ my( $self, $bool ) = @_;
+ $self->{substream} = $bool if defined $bool;
+ return $self->{substream};
+}
+
# -----------------------------------------------------------------------------
# Sets / Returns the requstor object. This is set when checkauth succeeds.
sub runmethod {
my( $self, $action, $type, $arg, $options ) = @_;
+ $options ||= {};
+
if( $action eq 'retrieve' ) {
if(! defined($arg) ) {
$self->log(W,"$action $type called with no ID...");
my $method = $self->app.".direct.$type.$action";
if( $action eq 'search' ) {
- $method = "$method.atomic";
+ $method .= '.atomic';
} elsif( $action eq 'batch_retrieve' ) {
$action = 'search';
@arg = ( { id => $arg } );
$method =~ s/batch_retrieve/search/o;
- $method = "$method.atomic";
+ $method .= '.atomic';
} elsif( $action eq 'retrieve_all' ) {
$action = 'search';
$tt =~ s/\./::/og;
my $fmobj = "Fieldmapper::$tt";
@arg = ( { $fmobj->Identity => { '!=' => undef } } );
- $method = "$method.atomic";
+ $method .= '.atomic';
}
$method =~ s/search/id_list/o if $options->{idlist};
+ $method =~ s/\.atomic$//o if $self->substream($$options{substream} || 0);
+
# remove any stale events
$self->clear_event;
return undef;
}
- if( $action eq 'search' or $action eq 'batch_retrieve' or $action eq 'retrieve_all') {
+ if( $action eq 'search' ) {
$self->log(I, "$type.$action : returned ".scalar(@$obj). " result(s)");
$self->event(_mk_not_found($type, $arg)) unless @$obj;
}
- $arg->id($obj->id) if $action eq 'create'; # grabs the id on create
+ if( $action eq 'create' ) {
+ $self->log(I, "created a new $type object with ID " . $obj->id);
+ $arg->id($obj->id);
+ }
+
$self->data($obj); # cache the data for convenience
return ($obj) ? $obj : 1;
eval $retrieveallf;
}
+sub json_query {
+ my( $self, $arg, $options ) = @_;
+ $options ||= {};
+ my @arg = ( ref($arg) eq 'ARRAY' ) ? @$arg : ($arg);
+ my $method = $self->app.'.json_query.atomic';
+ $method =~ s/\.atomic$//o if $self->substream($$options{substream} || 0);
+ $self->clear_event;
+ my $obj;
+ my $err;
+
+ try {
+ $obj = $self->request($method, @arg);
+ } catch Error with { $err = shift; };
+
+ if( $err ) {
+ $self->event(
+ OpenILS::Event->new( 'DATABASE_QUERY_FAILED',
+ payload => $arg, debug => "$err" ));
+ return undef;
+ }
+
+ $self->log(I, "json_query : returned ".scalar(@$obj). " result(s)");
+ return $obj;
+}
+
1;
author => {
corporate =>
"//mods:mods/mods:name[\@type='corporate']/*[local-name()='namePart']".
- "[../mods:role/mods:text[text()='creator']][1]",
+ "[../mods:role/mods:text[text()='creator']".
+ " or ../mods:role/mods:roleTerm[".
+ " \@type='text'".
+ " and \@authority='marcrelator'".
+ " and text()='creator']".
+ "][1]",
personal =>
"//mods:mods/mods:name[\@type='personal']/*[local-name()='namePart']".
- "[../mods:role/mods:text[text()='creator']][1]",
+ "[../mods:role/mods:text[text()='creator']".
+ " or ../mods:role/mods:roleTerm[".
+ " \@type='text'".
+ " and \@authority='marcrelator'".
+ " and text()='creator']".
+ "][1]",
conference =>
"//mods:mods/mods:name[\@type='conference']/*[local-name()='namePart']".
- "[../mods:role/mods:text[text()='creator']][1]",
+ "[../mods:role/mods:text[text()='creator']".
+ " or ../mods:role/mods:roleTerm[".
+ " \@type='text'".
+ " and \@authority='marcrelator'".
+ " and text()='creator']".
+ "][1]",
other =>
"//mods:mods/mods:name[\@type='personal']/*[local-name()='namePart']",
+ any =>
+ "//mods:mods/mods:name/*[local-name()='namePart'][1]",
},
subject => {
topic =>
- "//mods:mods/mods:subject/*[local-name()='geographic' or local-name()='name' or local-name()='temporal' or local-name()='topic']/parent::mods:subject",
+ "//mods:mods/mods:subject/*[".
+ " local-name()='geographic'".
+ " or local-name()='name'".
+ " or local-name()='temporal'".
+ " or local-name()='topic'".
+ "]/parent::mods:subject",
# geographic =>
# "//mods:mods/*[local-name()='subject']/*[local-name()='geographic']",
if(!$tmp) { $author = ""; }
else {
($author = $tmp->{personal}) ||
- ($author = $tmp->{other}) ||
($author = $tmp->{corporate}) ||
- ($author = $tmp->{conference});
+ ($author = $tmp->{conference}) ||
+ ($author = $tmp->{other}) ||
+ ($author = $tmp->{any});
}
$tmp = $modsperl->{subject};
my $record = init_virtual_record();
# turn the hash into a fieldmapper object
- (my $title = $perl->{title}) =~ s/\[.*?\]//og;
- (my $author = $perl->{author}) =~ s/\(.*?\)//og;
+ #(my $title = $perl->{title}) =~ s/\[.*?\]//og;
+ #(my $author = $perl->{author}) =~ s/\(.*?\)//og;
+ my $title = $perl->{title};
+ my $author = $perl->{author};
my @series;
for my $s (@{$perl->{series}}) {
push( @allevents, OpenILS::Event->new('ITEM_NOT_HOLDABLE') )
unless $U->is_true($ctx->{copy}->status->holdable);
- my $evt = check_age_protect($ctx->{patron}, $ctx->{copy});
- push( @allevents, $evt ) if $evt;
+ my $evt;
+
+ # grab the data safely
+ my $rlib = ref($$params{request_lib}) ? $$params{request_lib}->id : $$params{request_lib};
+ my $olib = ref($ctx->{volume}) ? $ctx->{volume}->owning_lib : -1;
+ my $rid = ref($ctx->{requestor}) ? $ctx->{requestor}->id : -2;
+ my $pid = ($params->{patron}) ? $params->{patron}->id : $params->{patron_id};
+
+ if( ($rid ne $pid) and ($olib eq $rlib) ) {
+ $logger->info("Item owning lib $olib is the same as the request lib. No age_protection will be checked");
+ } else {
+ $logger->info("item owning lib = $olib, request lib = $rlib, requestor=$rid, patron=$pid. checking age_protection");
+ $evt = check_age_protect($ctx->{patron}, $ctx->{copy});
+ push( @allevents, $evt ) if $evt;
+ }
$logger->debug("Running permit_copy_hold on copy " . $$params{copy}->id);
# Extract and uniquify the event list
# --------------------------------------------------------------
my $events = $result->{events};
- my $pid = ($params->{patron}) ? $params->{patron}->id : $params->{patron_id};
$logger->debug("circ_permit_hold for user $pid returned events: [@$events]");
push( @allevents, OpenILS::Event->new($_)) for @$events;
package OpenILS::WWW::SuperCat;
use strict; use warnings;
-use Apache2 ();
use Apache2::Log;
use Apache2::Const -compile => qw(OK REDIRECT DECLINED NOT_FOUND :log);
use APR::Const -compile => qw(:error SUCCESS);
template="$base/1.1/$lib/mods/$class/?searchTerms={searchTerms}&startPage={startPage?}&startIndex={startIndex?}&count={count?}&searchLang={language?}"/>
<Url type="application/x-marcxml+xml"
template="$base/1.1/$lib/marcxml/$class/?searchTerms={searchTerms}&startPage={startPage?}&startIndex={startIndex?}&count={count?}&searchLang={language?}"/>
+ <Url type="text/html"
+ template="$base/1.1/$lib/html-full/$class/?searchTerms={searchTerms}&startPage={startPage?}&startIndex={startIndex?}&count={count?}&searchLang={language?}"/>
<LongName>Search $lib</LongName>
<Query role="example" searchTerms="harry+potter" />
<Developer>Mike Rylander for GPLS/PINES</Developer>
}
}
+ $lang = 'eng' if ($lang eq 'en-US');
+
if ($term_copy) {
no warnings;
$class = 'keyword' if ($class eq '-');
sub run_request {
- my( $service, $method, @args ) = @_;
- my $ses = OpenSRF::AppSession->create( $service );
- my $data = $ses->request($method, @args)->gather(1);
- return wrap_perl($data);
+ my( $service, $method, @args ) = @_;
+ my $ses = OpenSRF::AppSession->create( $service );
+ #my $data = $ses->request($method, @args)->gather(1);
+
+ my $data = [];
+ my $req = $ses->request($method, @args);
+ while( my $resp = $req->recv( timeout => 600 ) ) {
+ if( $req->failed ) {
+ push( @$data, $req->failed );
+ last;
+ }
+ push( @$data, $resp->content );
+ }
+
+ return [] if scalar(@$data) == 0;
+ return wrap_perl($$data[0])
+ if scalar(@$data) == 1 and $method !~ /.atomic$/og;
+ return wrap_perl($data);
}
# These should probably be moved out to a library somewhere
open(F, ">$lockfile");
print F $$;
close F;
- daemonize("Clark Kent, waiting for trouble");
+ daemonize("clark_master");
}
CREATE RULE protect_user_delete AS ON DELETE TO actor.usr DO INSTEAD UPDATE actor.usr SET deleted = TRUE WHERE OLD.id = actor.usr.id;
-- Just so that there is a user...
-INSERT INTO actor.usr ( profile, card, usrname, passwd, first_given_name, family_name, dob, master_account, super_user, ident_type, ident_value, home_ou )
- VALUES ( 1, 1,'admin', 'open-ils', 'Administrator', 'System Account', '1979-01-22', TRUE, TRUE, 1, 'identification', 1 );
+INSERT INTO actor.usr ( profile, card, usrname, passwd, first_given_name, family_name, dob, master_account, super_user, ident_type, ident_value, home_ou )
+ VALUES ( 1, 1, 'admin', 'open-ils', 'Administrator', 'System Account', '1979-01-22', TRUE, TRUE, 1, 'identification', 1 );
CREATE TABLE actor.usr_note (
id BIGSERIAL PRIMARY KEY,
shortname TEXT NOT NULL,
name TEXT NOT NULL,
email TEXT,
- phone TEXT
+ phone TEXT,
+ opac_visible BOOL NOT NULL DEFAULT TRUE
);
CREATE INDEX actor_org_unit_parent_ou_idx ON actor.org_unit (parent_ou);
CREATE INDEX actor_org_unit_ou_type_idx ON actor.org_unit (ou_type);
CREATE INDEX perm_list_code_idx ON permission.perm_list (code);
INSERT INTO permission.perm_list VALUES (-1, 'EVERYTHING', NULL);
-/*
INSERT INTO permission.perm_list VALUES (2, 'OPAC_LOGIN', NULL);
INSERT INTO permission.perm_list VALUES (4, 'STAFF_LOGIN', NULL);
INSERT INTO permission.perm_list VALUES (5, 'MR_HOLDS', NULL);
INSERT INTO permission.perm_list VALUES (6, 'TITLE_HOLDS', NULL);
INSERT INTO permission.perm_list VALUES (7, 'VOLUME_HOLDS', NULL);
+INSERT INTO permission.perm_list VALUES (8, 'COPY_HOLDS', 'User is allowed to place a hold on a specific copy');
INSERT INTO permission.perm_list VALUES (9, 'REQUEST_HOLDS', NULL);
INSERT INTO permission.perm_list VALUES (10, 'REQUEST_HOLDS_OVERRIDE', NULL);
+INSERT INTO permission.perm_list VALUES (11, 'VIEW_HOLD', 'Allows a user to view another user''s holds');
INSERT INTO permission.perm_list VALUES (13, 'DELETE_HOLDS', NULL);
+INSERT INTO permission.perm_list VALUES (14, 'UPDATE_HOLD', 'Allows a user to update another user''s hold');
INSERT INTO permission.perm_list VALUES (15, 'RENEW_CIRC', NULL);
INSERT INTO permission.perm_list VALUES (16, 'VIEW_USER_FINES_SUMMARY', NULL);
INSERT INTO permission.perm_list VALUES (17, 'VIEW_USER_TRANSACTIONS', NULL);
INSERT INTO permission.perm_list VALUES (18, 'UPDATE_MARC', NULL);
+INSERT INTO permission.perm_list VALUES (19, 'CREATE_MARC', 'User is allowed to create new MARC records');
INSERT INTO permission.perm_list VALUES (20, 'IMPORT_MARC', NULL);
INSERT INTO permission.perm_list VALUES (21, 'CREATE_VOLUME', NULL);
INSERT INTO permission.perm_list VALUES (22, 'UPDATE_VOLUME', NULL);
INSERT INTO permission.perm_list VALUES (43, 'CREATE_BILL', 'Allows a user to create a new bill on a transaction');
INSERT INTO permission.perm_list VALUES (44, 'VIEW_CONTAINER', 'Allows a user to view another user''s containers (buckets)');
INSERT INTO permission.perm_list VALUES (45, 'CREATE_CONTAINER', 'Allows a user to create a new container for another user');
-INSERT INTO permission.perm_list VALUES (8, 'COPY_HOLDS', 'User is allowed to place a hold on a specific copy');
INSERT INTO permission.perm_list VALUES (24, 'CREATE_COPY', 'User is allowed to create a new copy object');
-INSERT INTO permission.perm_list VALUES (19, 'CREATE_ORIGINAL_MARC', 'User is allowed to create new MARC records');
INSERT INTO permission.perm_list VALUES (47, 'UPDATE_ORG_UNIT', 'Allows a user to change org unit settings');
INSERT INTO permission.perm_list VALUES (48, 'VIEW_CIRCULATIONS', 'Allows a user to see what another use has checked out');
-INSERT INTO permission.perm_list VALUES (14, 'UPDATE_HOLD', 'Allows a user to update another user''s hold');
-INSERT INTO permission.perm_list VALUES (11, 'VIEW_HOLD', 'Allows a user to view another user''s holds');
INSERT INTO permission.perm_list VALUES (42, 'VIEW_TRANSACTION', 'User may view another user''s transactions');
INSERT INTO permission.perm_list VALUES (49, 'DELETE_CONTAINER', 'Allows a user to delete another user container');
INSERT INTO permission.perm_list VALUES (50, 'CREATE_CONTAINER_ITEM', 'Create a container item for another user');
INSERT INTO permission.perm_list VALUES (102, 'CIRC_OVERRIDE_DUE_DATE', 'Allows a user to change set the due date on an item to any date');
INSERT INTO permission.perm_list VALUES (103, 'CIRC_PERMIT_OVERRIDE', 'Allows a user to bypass the circ permit call for checkout');
INSERT INTO permission.perm_list VALUES (104, 'COPY_IS_REFERENCE.override', 'Allows a user to override the copy_is_reference event');
-
-SELECT SETVAL('permission.perm_list_id_seq'::TEXT, 105);
-*/
+INSERT INTO permission.perm_list VALUES (105, 'VOID_BILLING', 'Allows a user to void a bill');
+INSERT INTO permission.perm_list VALUES (106, 'CIRC_CLAIMS_RETURNED.override', 'Allows a person to check in/out an item that is claims returned');
+INSERT INTO permission.perm_list VALUES (107, 'COPY_BAD_STATUS.override', 'Allows a user to check out an item in a non-circulatable status');
+INSERT INTO permission.perm_list VALUES (108, 'COPY_ALERT_MESSAGE.override', 'Allows a user to check in/out an item that has an alert message');
+INSERT INTO permission.perm_list VALUES (109, 'COPY_STATUS_LOST.override', 'Allows a user to remove the lost status from a copy');
+INSERT INTO permission.perm_list VALUES (110, 'COPY_STATUS_MISSING.override', 'Allows a user to change the missing status on a copy');
+INSERT INTO permission.perm_list VALUES (111, 'ABORT_TRANSIT', 'Allows a user to abort a copy transit if the user is at the transit destination or source');
+INSERT INTO permission.perm_list VALUES (112, 'ABORT_REMOTE_TRANIST', 'Allows a user to abort a copy transit if the user is not at the transit source or dest');
+INSERT INTO permission.perm_list VALUES (113, 'VIEW_ZIP_DATA', 'Allowsa user to query the zip code data method');
+INSERT INTO permission.perm_list VALUES (114, 'CANCEL_HOLDS', '');
+INSERT INTO permission.perm_list VALUES (115, 'CREATE_DUPLICATE_HOLDS', 'Allows a user to create duplicate holds (e.g. two holds on the same title)');
+INSERT INTO permission.perm_list VALUES (117, 'actor.org_unit.closed_date.update', 'Allows a user to update a closed date interval for a given location');
+INSERT INTO permission.perm_list VALUES (116, 'actor.org_unit.closed_date.delete', 'Allows a user to remove a closed date interval for a given location');
+INSERT INTO permission.perm_list VALUES (118, 'actor.org_unit.closed_date.create', 'Allows a user to create a new closed date for a location');
+INSERT INTO permission.perm_list VALUES (119, 'DELETE_NON_CAT_TYPE', 'Allows a user to delete a non cataloged type');
+INSERT INTO permission.perm_list VALUES (120, 'money.collections_tracker.create', 'Allows a user to put someone into collections');
+INSERT INTO permission.perm_list VALUES (121, 'money.collections_tracker.delete', 'Allows a user to remove someone from collections');
+INSERT INTO permission.perm_list VALUES (122, 'BAR_PATRON', 'Allows a user to bar a patron');
+INSERT INTO permission.perm_list VALUES (123, 'UNBAR_PATRON', 'Allows a user to un-bar a patron');
+INSERT INTO permission.perm_list VALUES (124, 'DELETE_WORKSTATION', 'Allows a user to remove an existing workstation so a new one can replace it');
+INSERT INTO permission.perm_list VALUES (125, 'group_application.user', 'Allows a user to add/remove users to/from the "User" group');
+INSERT INTO permission.perm_list VALUES (126, 'group_application.user.patron', 'Allows a user to add/remove users to/from the "Patron" group');
+INSERT INTO permission.perm_list VALUES (127, 'group_application.user.staff', 'Allows a user to add/remove users to/from the "Staff" group');
+INSERT INTO permission.perm_list VALUES (128, 'group_application.user.staff.circ', 'Allows a user to add/remove users to/from the "Circulator" group');
+INSERT INTO permission.perm_list VALUES (129, 'group_application.user.staff.cat', 'Allows a user to add/remove users to/from the "Cataloger" group');
+INSERT INTO permission.perm_list VALUES (130, 'group_application.user.staff.admin.global_admin', 'Allows a user to add/remove users to/from the "GlobalAdmin" group');
+INSERT INTO permission.perm_list VALUES (131, 'group_application.user.staff.admin.local_admin', 'Allows a user to add/remove users to/from the "LocalAdmin" group');
+INSERT INTO permission.perm_list VALUES (132, 'group_application.user.staff.admin.lib_manager', 'Allows a user to add/remove users to/from the "LibraryManager" group');
+INSERT INTO permission.perm_list VALUES (133, 'group_application.user.staff.cat.cat1', 'Allows a user to add/remove users to/from the "Cat1" group');
+INSERT INTO permission.perm_list VALUES (134, 'group_application.user.staff.supercat', 'Allows a user to add/remove users to/from the "Supercat" group');
+INSERT INTO permission.perm_list VALUES (135, 'group_application.user.sip_client', 'Allows a user to add/remove users to/from the "SIP-Client" group');
+INSERT INTO permission.perm_list VALUES (136, 'group_application.user.vendor', 'Allows a user to add/remove users to/from the "Vendor" group');
+INSERT INTO permission.perm_list VALUES (137, 'ITEM_AGE_PROTECTED.override', 'Allows a user to place a hold on an age-protected item');
+INSERT INTO permission.perm_list VALUES (138, 'MAX_RENEWALS_REACHED.override', 'Allows a user to renew an item past the maximun renewal count');
+INSERT INTO permission.perm_list VALUES (139, 'PATRON_EXCEEDS_CHECKOUT_COUNT.override', 'Allow staff to override checkout count failure');
+INSERT INTO permission.perm_list VALUES (140, 'PATRON_EXCEEDS_OVERDUE_COUNT.override', 'Allow staff to override overdue count failure');
+INSERT INTO permission.perm_list VALUES (141, 'PATRON_EXCEEDS_FINES.override', 'Allow staff to override fine amount checkout failure');
+INSERT INTO permission.perm_list VALUES (142, 'CIRC_EXCEEDS_COPY_RANGE.override', '');
+INSERT INTO permission.perm_list VALUES (143, 'ITEM_ON_HOLDS_SHELF.override', '');
+INSERT INTO permission.perm_list VALUES (144, 'COPY_NOT_AVAILABLE.override', 'Allow staff to force checkout of Missing/Lost type items');
+INSERT INTO permission.perm_list VALUES (145, 'VOLUME_UPDATE', '');
+INSERT INTO permission.perm_list VALUES (146, 'HOLD_EXISTS.override', 'allows users to place multiple holds on a single title');
+INSERT INTO permission.perm_list VALUES (147, 'RUN_REPORTS', 'Allows a users to run reports');
+INSERT INTO permission.perm_list VALUES (148, 'SHARE_REPORT_FOLDER', 'Allows a user to share report his own folders');
+INSERT INTO permission.perm_list VALUES (149, 'VIEW_REPORT_OUTPUT', 'Allow user to view report output');
+INSERT INTO permission.perm_list VALUES (150, 'COPY_CIRC_NOT_ALLOWED.override', 'Allows a user to checkout an item that is marked as non-circ');
+INSERT INTO permission.perm_list VALUES (151, 'DELETE_CONTAINER_ITEM', 'Allows a user to delete an item out of another user''s container');
+
+SELECT SETVAL('permission.perm_list_id_seq'::TEXT, 151, TRUE);
CREATE TABLE permission.grp_tree (
id SERIAL PRIMARY KEY,
);
CREATE INDEX grp_tree_parent_idx ON permission.grp_tree (parent);
-/*
-INSERT INTO permission.grp_tree VALUES (1, 'Users', NULL, NULL, '3 years');
-INSERT INTO permission.grp_tree VALUES (2, 'Patrons', 1, NULL, '3 years');
-INSERT INTO permission.grp_tree VALUES (3, 'Staff', 1, NULL, '3 years');
-INSERT INTO permission.grp_tree VALUES (4, 'Catalogers', 3, NULL, '3 years');
-INSERT INTO permission.grp_tree VALUES (5, 'Circulators', 3, NULL, '3 years');
-INSERT INTO permission.grp_tree VALUES (10, 'Local System Administrator', 3, 'System maintenance, configuration, etc.', '3 years');
+INSERT INTO permission.grp_tree (id, name, parent, description, perm_interval, usergroup, application_perm)
+ VALUES (1, 'Users', NULL, NULL, '3 years', FALSE, 'group_application.user');
+INSERT INTO permission.grp_tree (id, name, parent, description, perm_interval, usergroup, application_perm)
+ VALUES (2, 'Patrons', 1, NULL, '3 years', TRUE, 'group_application.user.patron');
+INSERT INTO permission.grp_tree (id, name, parent, description, perm_interval, usergroup, application_perm)
+ VALUES (3, 'Staff', 1, NULL, '3 years', FALSE, 'group_application.user.staff');
+INSERT INTO permission.grp_tree (id, name, parent, description, perm_interval, usergroup, application_perm)
+ VALUES (4, 'Catalogers', 3, NULL, '3 years', TRUE, 'group_application.user.staff.cat');
+INSERT INTO permission.grp_tree (id, name, parent, description, perm_interval, usergroup, application_perm)
+ VALUES (5, 'Circulators', 3, NULL, '3 years', TRUE, 'group_application.user.staff.circ');
+INSERT INTO permission.grp_tree (id, name, parent, description, perm_interval, usergroup, application_perm)
+ VALUES (10, 'Local System Administrator', 3, 'System maintenance, configuration, etc.', '3 years', TRUE, 'group_application.user.staff.admin.local_admin');
SELECT SETVAL('permission.grp_tree_id_seq'::TEXT, 11);
-*/
CREATE TABLE permission.grp_perm_map (
id SERIAL PRIMARY KEY,
CONSTRAINT perm_grp_once UNIQUE (grp,perm)
);
-/*
+-- XXX Incomplete base permission setup. A patch would be appreciated.
INSERT INTO permission.grp_perm_map VALUES (57, 2, 15, 0, false);
INSERT INTO permission.grp_perm_map VALUES (109, 2, 95, 0, false);
INSERT INTO permission.grp_perm_map VALUES (1, 1, 2, 0, false);
INSERT INTO permission.grp_perm_map VALUES (138, 5, 104, 1, false);
SELECT SETVAL('permission.grp_perm_map_id_seq'::TEXT, 139);
-*/
CREATE TABLE permission.usr_perm_map (
id SERIAL PRIMARY KEY,
note TEXT
) INHERITS (money.billable_xact);
ALTER TABLE money.grocery ADD PRIMARY KEY (id);
+CREATE INDEX circ_open_date_idx ON "money".grocery (xact_start) WHERE xact_finish IS NULL;
+CREATE INDEX m_g_usr_idx ON "money".grocery (usr);
CREATE TABLE money.billing (
id BIGSERIAL PRIMARY KEY,
) INHERITS (money.bnm_payment);
ALTER TABLE money.bnm_desk_payment ADD PRIMARY KEY (id);
+
CREATE OR REPLACE VIEW money.desk_payment_view AS
SELECT p.*,c.relname AS payment_type
FROM money.bnm_desk_payment p
CREATE INDEX money_credit_card_payment_accepting_usr_idx ON money.credit_card_payment (accepting_usr);
CREATE INDEX money_credit_card_payment_cash_drawer_idx ON money.credit_card_payment (cash_drawer);
+CREATE OR REPLACE VIEW money.non_drawer_payment_view AS
+ SELECT p.*, c.relname AS payment_type
+ FROM money.bnm_payment p
+ JOIN pg_class c ON p.tableoid = c.oid
+ WHERE c.relname NOT IN ('cash_payment','check_payment','credit_card_payment');
+
CREATE OR REPLACE VIEW money.cashdrawer_payment_view AS
SELECT ou.id AS org_unit,
ws.id AS cashdrawer,
CREATE INDEX circ_open_xacts_idx ON action.circulation (usr) WHERE xact_finish IS NULL;
CREATE INDEX circ_outstanding_idx ON action.circulation (usr) WHERE checkin_time IS NULL;
CREATE INDEX circ_checkin_time ON "action".circulation (checkin_time) WHERE checkin_time IS NOT NULL;
+CREATE INDEX circ_circ_lib_idx ON "action".circulation (circ_lib);
+CREATE INDEX circ_open_date_idx ON "action".circulation (xact_start) WHERE xact_finish IS NULL;
CREATE OR REPLACE VIEW action.open_circulation AS
r.tcn_source,
r.tcn_value,
title.value AS title,
- author.value AS author,
+ FIRST(author.value) AS author,
publisher.value AS publisher,
SUBSTRING(pubdate.value FROM $$\d+$$) AS pubdate,
ARRAY_ACCUM( SUBSTRING(isbn.value FROM $$^\S+$$) ) AS isbn,
ARRAY_ACCUM( SUBSTRING(issn.value FROM $$^\S+$$) ) AS issn
FROM biblio.record_entry r
LEFT JOIN metabib.full_rec title ON (r.id = title.record AND title.tag = '245' AND title.subfield = 'a')
- LEFT JOIN metabib.full_rec author ON (r.id = author.record AND author.tag = '100' AND author.subfield = 'a')
+ LEFT JOIN metabib.full_rec author ON (r.id = author.record AND author.tag IN ('100','110','111') AND author.subfield = 'a')
LEFT JOIN metabib.full_rec publisher ON (r.id = publisher.record AND publisher.tag = '260' AND publisher.subfield = 'b')
LEFT JOIN metabib.full_rec pubdate ON (r.id = pubdate.record AND pubdate.tag = '260' AND pubdate.subfield = 'c')
LEFT JOIN metabib.full_rec isbn ON (r.id = isbn.record AND isbn.tag IN ('024', '020') AND isbn.subfield IN ('a','z'))
LEFT JOIN metabib.full_rec issn ON (r.id = issn.record AND issn.tag = '022' AND issn.subfield = 'a')
WHERE r.deleted IS FALSE
- GROUP BY 1,2,3,4,5,6,7,8,9;
+ GROUP BY 1,2,3,4,5,6,8,9;
CREATE OR REPLACE VIEW reporter.demographic AS
SELECT u.id,
END AS "type"
FROM action.circulation;
+CREATE OR REPLACE VIEW reporter.hold_request_record AS
+SELECT id,
+ target,
+ hold_type,
+ CASE
+ WHEN hold_type = 'T'
+ THEN target
+ WHEN hold_type = 'V'
+ THEN (SELECT cn.record FROM asset.call_number cn WHERE cn.id = ahr.target)
+ WHEN hold_type = 'C'
+ THEN (SELECT cn.record FROM asset.call_number cn JOIN asset.copy cp ON (cn.id = cp.call_number) WHERE cp.id = ahr.target)
+ WHEN hold_type = 'M'
+ THEN (SELECT mr.master_record FROM metabib.metarecord mr WHERE mr.id = ahr.target)
+ END AS bib_record
+ FROM action.hold_request ahr;
+
+CREATE OR REPLACE VIEW reporter.xact_billing_totals AS
+SELECT b.xact,
+ SUM( CASE WHEN b.voided THEN 0 ELSE amount END ) as unvoided,
+ SUM( CASE WHEN b.voided THEN amount ELSE 0 END ) as voided,
+ SUM( amount ) as total
+ FROM money.billing b
+ GROUP BY 1;
+
+CREATE OR REPLACE VIEW reporter.xact_paid_totals AS
+SELECT b.xact,
+ SUM( CASE WHEN b.voided THEN 0 ELSE amount END ) as unvoided,
+ SUM( CASE WHEN b.voided THEN amount ELSE 0 END ) as voided,
+ SUM( amount ) as total
+ FROM money.payment b
+ GROUP BY 1;
+
COMMIT;
--- /dev/null
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use OpenSRF::System;
+use OpenSRF::EX qw/:try/;
+use OpenSRF::AppSession;
+use OpenSRF::Utils::SettingsClient;
+use OpenILS::Application::AppUtils;
+use OpenILS::Utils::Fieldmapper;
+
+use MARC::Record;
+use MARC::File::XML;
+use UNIVERSAL::require;
+
+use Getopt::Long;
+
+my @formats = qw/USMARC UNIMARC XML/;
+
+my ($config,$format,$encoding,$help) = ('/openils/conf/bootstrap.conf','USMARC','MARC8');
+
+GetOptions(
+ 'help' => \$help,
+ 'config=s' => \$config,
+ 'format=s' => \$format,
+ 'encoding=s' => \$encoding,
+);
+
+if ($help) {
+ print <<" HELP";
+Usage: $0 [options]
+ --help or -h This screen.
+ --config or -c Configuration file [/openils/conf/bootstrap.conf]
+ --format or -f Output format (USMARC, UNIMARC, XML) [USMARC]
+ --encoding or -e Output Encoding (UTF-8, ISO-8859-?, MARC8) [MARC8]
+
+Example:
+
+ cat list_of_ids | $0 > output_file
+
+ HELP
+ exit;
+}
+
+$format = uc($format);
+$encoding = uc($encoding);
+
+binmode(STDOUT, ':raw') if ($encoding ne 'UTF-8');
+binmode(STDOUT, ':utf8') if ($encoding eq 'UTF-8');
+
+if (!grep { $format eq $_ } @formats) {
+ die "Please select a supported format. ".
+ "Right now that means one of [".
+ join('|',@formats). "]\n";
+}
+
+if ($format ne 'XML') {
+ my $type = 'MARC::File::' . $format;
+ $type->require;
+}
+
+OpenSRF::System->bootstrap_client( config_file => $config );
+Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
+
+my $ses = OpenSRF::AppSession->connect('open-ils.cstore');
+
+print <<HEADER if ($format eq 'XML');
+<?xml version="1.0" encoding="$encoding"?>
+<collection xmlns='http://www.loc.gov/MARC21/slim'>
+HEADER
+
+while ( my $i = <> ) {
+ my $bib = $ses->request( 'open-ils.cstore.direct.biblio.record_entry.retrieve', $i )->gather(1);
+
+ next unless $bib;
+
+ if ($format eq 'XML') {
+ print $bib->marc . "\n";
+ } else {
+ print MARC::Record->new_from_xml( $bib->marc, $encoding, $format )->as_usmarc;
+ }
+}
+
+print "</collection>\n" if ($format eq 'XML');
+
+$ses->disconnect;
+
--- /dev/null
+<record>
+ <leader>01149cjm a2200265Ka 4500</leader>
+ <controlfield tag="008"> </controlfield>
+ <datafield tag="010" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="024" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="028" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="082" ind1="0" ind2="4">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="092" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="100" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="d"></subfield>
+ </datafield>
+ <datafield tag="245" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="h"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="260" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="300" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="511" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="518" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="500" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="505" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="650" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+</record>
--- /dev/null
+<record>
+ <leader>00620cam a2200205Ka 4500</leader>
+ <controlfield tag="008"> </controlfield>
+ <datafield tag="010" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="020" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="082" ind1="0" ind2="4">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="092" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="100" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="245" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="260" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="300" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="500" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="650" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="v"></subfield>
+ </datafield>
+ <datafield tag="650" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+</record>
--- /dev/null
+<record>
+ <leader>01490cgm a2200229Ka 4500</leader>
+ <controlfield tag="008"> </controlfield>
+ <datafield tag="020" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="028" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ </datafield>
+ <datafield tag="082" ind1="0" ind2="4">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="092" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="245" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="h"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="250" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="260" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="300" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ <subfield code="b"></subfield>
+ <subfield code="c"></subfield>
+ </datafield>
+ <datafield tag="538" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="511" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+ <datafield tag="508" ind1="" ind2="">
+ <subfield code="a"></subfield>
+ </datafield>
+</record>
--- /dev/null
+/* DepressedPress.com DP_DateExtensions
+Author: Jim Davis, the Depressed Press of Boston
+Date: June 20, 2006
+Contact: webmaster@depressedpress.com
+Website: www.depressedpress.com
+
+Full documentation can be found at:
+http://www.depressedpress.com/Content/Development/JavaScript/Extensions/
+
+DP_DateExtensions adds features to the JavaScript "Date" datatype.
+Copyright (c) 1996-2006, The Depressed Press of Boston (depressedpress.com)
+All rights reserved.
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
++) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
++) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
++) Neither the name of the DEPRESSED PRESS OF BOSTON (DEPRESSEDPRESS.COM) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+CHANGES: --------------------------------------------------------------------------------
+
+ 2007-02-02 / billserickson@gmail.com
+ - chopped out some utility methods to trim file size
+ - changed some formatting for visual ease
+ - date / time can now be separated by a "T", "t" or a space
+ - truncating milliseconds. not needed and .123456
+ comes accross 123456ms and not 123ms + 456 microseconds
+*/
+
+
+Date.parseIso8601 = function(CurDate) {
+
+ // Check the input parameters
+ if ( typeof CurDate != "string" ) {
+ return null;
+ };
+ // Set the fragment expressions
+ var S = "[\\-/:.]";
+ var Yr = "((?:1[6-9]|[2-9][0-9])[0-9]{2})";
+ var Mo = S + "((?:1[012])|(?:0[1-9])|[1-9])";
+ var Dy = S + "((?:3[01])|(?:[12][0-9])|(?:0[1-9])|[1-9])";
+ var Hr = "(2[0-4]|[01]?[0-9])";
+ var Mn = S + "([0-5]?[0-9])";
+ var Sd = "(?:" + S + "([0-5]?[0-9])(?:[.,]([0-9]+))?)?";
+ var TZ = "(?:(Z)|(?:([\+\-])(1[012]|[0]?[0-9])(?::?([0-5]?[0-9]))?))?";
+ // RegEx the input
+ // First check: Just date parts (month and day are optional)
+ // Second check: Full date plus time (seconds, milliseconds and TimeZone info are optional)
+ var TF;
+
+ if ( TF = new RegExp("^" + Yr + "(?:" + Mo + "(?:" + Dy + ")?)?" + "$").exec(CurDate) ) {
+ } else if ( TF = new RegExp("^" + Yr + Mo + Dy + "[Tt ]" + Hr + Mn + Sd + TZ + "$").exec(CurDate) ) {};
+
+ // If the date couldn't be parsed, return null
+ if ( !TF ) { return null };
+ // Default the Time Fragments if they're not present
+ if ( !TF[2] ) { TF[2] = 1 } else { TF[2] = TF[2] - 1 };
+ if ( !TF[3] ) { TF[3] = 1 };
+ if ( !TF[4] ) { TF[4] = 0 };
+ if ( !TF[5] ) { TF[5] = 0 };
+ if ( !TF[6] ) { TF[6] = 0 };
+ if ( !TF[7] ) { TF[7] = 0 };
+ if ( !TF[8] ) { TF[8] = null };
+ if ( TF[9] != "-" && TF[9] != "+" ) { TF[9] = null };
+ if ( !TF[10] ) { TF[10] = 0 } else { TF[10] = TF[9] + TF[10] };
+ if ( !TF[11] ) { TF[11] = 0 } else { TF[11] = TF[9] + TF[11] };
+ // If there's no timezone info the data is local time
+
+ TF[7] = 0;
+
+ if ( !TF[8] && !TF[9] ) {
+ return new Date(TF[1], TF[2], TF[3], TF[4], TF[5], TF[6], TF[7]);
+ };
+ // If the UTC indicator is set the date is UTC
+ if ( TF[8] == "Z" ) {
+ return new Date(Date.UTC(TF[1], TF[2], TF[3], TF[4], TF[5], TF[6], TF[7]));
+ };
+ // If the date has a timezone offset
+ if ( TF[9] == "-" || TF[9] == "+" ) {
+ // Get current Timezone information
+ var CurTZ = new Date().getTimezoneOffset();
+ var CurTZh = TF[10] - ((CurTZ >= 0 ? "-" : "+") + Math.floor(Math.abs(CurTZ) / 60))
+ var CurTZm = TF[11] - ((CurTZ >= 0 ? "-" : "+") + (Math.abs(CurTZ) % 60))
+ // Return the date
+ return new Date(TF[1], TF[2], TF[3], TF[4] - CurTZh, TF[5] - CurTZm, TF[6], TF[7]);
+ };
+ // If we've reached here we couldn't deal with the input, return null
+ return null;
+
+};
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* "Date" Object Prototype Extensions */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+Date.prototype.dateFormat = function(Mask) {
+
+ var FormattedDate = "";
+ var Ref_MonthFullName = ["January", "February", "March", "April", "May",
+ "June", "July", "August", "September", "October", "November", "December"];
+ var Ref_MonthAbbreviation = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+ var Ref_DayFullName = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
+ var Ref_DayAbbreviation = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+
+ // Convert any supported simple masks into "real" masks
+ switch (Mask) {
+ case "short":
+ Mask = "m/d/yy";
+ break;
+ case "medium":
+ Mask = "mmm d, yyyy";
+ break;
+ case "long":
+ Mask = "mmmm d, yyyy";
+ break;
+ case "full":
+ Mask = "dddd, mmmm d, yyyy";
+ break;
+ };
+
+ // Tack a temporary space at the end of the mask to ensure that the last character isn't a mask character
+ Mask += " ";
+
+ // Parse the Mask
+ var CurChar;
+ var MaskPart = "";
+ for ( var Cnt = 0; Cnt < Mask.length; Cnt++ ) {
+ // Get the character
+ CurChar = Mask.charAt(Cnt);
+ // Determine if the character is a mask element
+ if ( (CurChar != "d") && (CurChar != "m") && (CurChar != "y") ) {
+ // Determine if we need to parse a MaskPart or not
+ if ( MaskPart != "" ) {
+ // Convert the mask part to the date value
+ switch (MaskPart) {
+ case "d":
+ FormattedDate += this.getDate();
+ break;
+ case "dd":
+ FormattedDate += ("0" + this.getDate()).slice(-2);
+ break;
+ case "ddd":
+ FormattedDate += Ref_DayAbbreviation[this.getDay()];
+ break;
+ case "dddd":
+ FormattedDate += Ref_DayFullName[this.getDay()];
+ break;
+ case "m":
+ FormattedDate += this.getMonth() + 1;
+ break;
+ case "mm":
+ FormattedDate += ("0" + (this.getMonth() + 1)).slice(-2);
+ break;
+ case "mmm":
+ FormattedDate += Ref_MonthAbbreviation[this.getMonth()];
+ break;
+ case "mmmm":
+ FormattedDate += Ref_MonthFullName[this.getMonth()];
+ break;
+ case "yy":
+ FormattedDate += ("0" + this.getFullYear()).slice(-2);
+ break;
+ case "yyyy":
+ FormattedDate += ("000" + this.getFullYear()).slice(-4);
+ break;
+ };
+ // Reset the MaskPart to nothing
+ MaskPart = "";
+ };
+ // Add the character to the output
+ FormattedDate += CurChar;
+ } else {
+ // Add the current mask character to the MaskPart
+ MaskPart += CurChar;
+ };
+ };
+
+ // Remove the temporary space from the end of the formatted date
+ FormattedDate = FormattedDate.substring(0,FormattedDate.length - 1);
+
+ // Return the formatted date
+ return FormattedDate;
+
+};
+
+
+Date.prototype.timeFormat = function(Mask) {
+
+ var FormattedTime = "";
+
+ // Convert any supported simple masks into "real" masks
+ switch (Mask) {
+ case "short":
+ Mask = "h:mm tt";
+ break;
+ case "medium":
+ Mask = "h:mm:ss tt";
+ break;
+ case "long":
+ Mask = "h:mm:ss.l tt";
+ break;
+ case "full":
+ Mask = "h:mm:ss.l tt";
+ break;
+ };
+
+ // Tack a temporary space at the end of the mask to ensure that the last character isn't a mask character
+ Mask += " ";
+
+ // Parse the Mask
+ var CurChar;
+ var MaskPart = "";
+ for ( var Cnt = 0; Cnt < Mask.length; Cnt++ ) {
+ // Get the character
+ CurChar = Mask.charAt(Cnt);
+ // Determine if the character is a mask element
+ if ( (CurChar != "h") && (CurChar != "H") && (CurChar != "m") &&
+ (CurChar != "s") && (CurChar != "l") && (CurChar != "t") && (CurChar != "T") ) {
+ // Determine if we need to parse a MaskPart or not
+ if ( MaskPart != "" ) {
+ // Convert the mask part to the date value
+ switch (MaskPart) {
+ case "h":
+ var CurValue = this.getHours();
+ if ( CurValue > 12 ) {
+ CurValue = CurValue - 12;
+ };
+ FormattedTime += CurValue;
+ break;
+ case "hh":
+ var CurValue = this.getHours();
+ if ( CurValue > 12 ) {
+ CurValue = CurValue - 12;
+ };
+ FormattedTime += ("0" + CurValue).slice(-2);
+ break;
+ case "H":
+ FormattedTime += ("0" + this.getHours()).slice(-2);
+ break;
+ case "HH":
+ FormattedTime += ("0" + this.getHours()).slice(-2);
+ break;
+ case "m":
+ FormattedTime += this.getMinutes();
+ break;
+ case "mm":
+ FormattedTime += ("0" + this.getMinutes()).slice(-2);
+ break;
+ case "s":
+ FormattedTime += this.getSeconds();
+ break;
+ case "ss":
+ FormattedTime += ("0" + this.getSeconds()).slice(-2);
+ break;
+ case "l":
+ FormattedTime += ("00" + this.getMilliseconds()).slice(-3);
+ break;
+ case "t":
+ if ( this.getHours() > 12 ) {
+ FormattedTime += "p";
+ } else {
+ FormattedTime += "a";
+ };
+ break;
+ case "tt":
+ if ( this.getHours() > 12 ) {
+ FormattedTime += "pm";
+ } else {
+ FormattedTime += "am";
+ };
+ break;
+ case "T":
+ if ( this.getHours() > 12 ) {
+ FormattedTime += "P";
+ } else {
+ FormattedTime += "A";
+ };
+ break;
+ case "TT":
+ if ( this.getHours() > 12 ) {
+ FormattedTime += "PM";
+ } else {
+ FormattedTime += "AM";
+ };
+ break;
+ };
+ // Reset the MaskPart to nothing
+ MaskPart = "";
+ };
+ // Add the character to the output
+ FormattedTime += CurChar;
+ } else {
+ // Add the current mask character to the MaskPart
+ MaskPart += CurChar;
+ };
+ };
+
+ // Remove the temporary space from the end of the formatted date
+ FormattedTime = FormattedTime.substring(0,FormattedTime.length - 1);
+
+ // Return the formatted date
+ return FormattedTime;
+
+};
+
+
+/*
+ dropTZ - do not include the timezone in the output. only used for YMDH+
+ useSpace - if true, use a space instaed of a "T" between date and time
+*/
+Date.prototype.iso8601Format = function(Style, isUTC, dropTZ, useSpace) {
+
+ var FormattedDate = "";
+
+ switch (Style) {
+ case "Y":
+ FormattedDate += this.dateFormat("yyyy");
+ break;
+ case "YM":
+ FormattedDate += this.dateFormat("yyyy-mm");
+ break;
+ case "YMD":
+ FormattedDate += this.dateFormat("yyyy-mm-dd");
+ break;
+ case "YMDHM":
+ FormattedDate += this.dateFormat("yyyy-mm-dd") + ((useSpace) ? " " : "T") + this.timeFormat("HH:mm");
+ break;
+ case "YMDHMS":
+ FormattedDate += this.dateFormat("yyyy-mm-dd") + ((useSpace) ? " " : "T") + this.timeFormat("HH:mm:ss");
+ break;
+ case "YMDHMSM":
+ FormattedDate += this.dateFormat("yyyy-mm-dd") + ((useSpace) ? " " : "T") + this.timeFormat("HH:mm:ss.l");
+ break;
+ };
+
+ if ( !dropTZ && (Style == "YMDHM" || Style == "YMDHMS" || Style == "YMDHMSM") ) {
+ if ( isUTC ) {
+ FormattedDate += "Z";
+ } else {
+ // Get TimeZone Information
+ var TimeZoneOffset = this.getTimezoneOffset();
+ var TimeZoneInfo = (TimeZoneOffset >= 0 ? "-" : "+") +
+ ("0" + (Math.floor(Math.abs(TimeZoneOffset) / 60))).slice(-2) + ":" +
+ ("00" + (Math.abs(TimeZoneOffset) % 60)).slice(-2);
+ FormattedDate += TimeZoneInfo;
+ };
+ };
+
+ // Return the date
+ return FormattedDate;
+
+};
+
+
+
+
if(this.cancelled) return;
-
-
/* determine the xmlhttp server dynamically */
var url = location.protocol + "//" + location.host + "/" + XML_HTTP_GATEWAY;
var data = null;
if( this.type == 'GET' ) url += "?" + this.param_string;
- if(isXUL() && this.secure ) dump('SECURE = true\n');
-
this.url = url;
+ //if( isXUL() ) dump('request URL = ' + url + '?' + this.param_string + '\n');
+
try {
if(blocking) this.xmlhttp.open(this.type, url, false);
try {
var auth;
try { auth = cookieManager.read(COOKIE_SES) } catch(ee) {}
- if( !auth && isXUL() ) auth = ses();
+ if( isXUL() ) auth = fetchXULStash().session.key;
if( auth )
this.xmlhttp.setRequestHeader('X-OILS-Authtoken', auth);
var status = null;
this.event(null);
- /* DEBUG
+ /*
try {
dump(this.url + '?' + this.param_string + '\n' +
'Returned with \n\tstatus = ' + this.xmlhttp.status +
var text = this.xmlhttp.responseText;
+ //try{if(getDebug()) _debug('response: ' + text + '\n')}catch(e){}
+
if(text == "" || text == " " || text == null) {
try { dump('dbg: Request returned no text!\n'); } catch(E) {}
if(isXUL())
this.param_string += "¶m=" + string;
}
+function fetchXULStash() {
+ if( isXUL() ) {
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var __OILS = new Components.Constructor("@mozilla.org/openils_data_cache;1", "nsIOpenILS");
+ var data_cache = new __OILS( );
+ return data_cache.wrappedJSObject.OpenILS.prototype.data;
+
+ } catch(E) {
+ _debug('Error in OpenILS.data._debug_stash(): ' + js2JSON(E) );
+ }
+ }
+ return {};
+}
+
+
var FETCH_HIGHEST_PERM_ORG = 'open-ils.actor:open-ils.actor.user.perm.highest_org.batch';
var FETCH_USER_NOTES = 'open-ils.actor:open-ils.actor.note.retrieve.all';
var FETCH_ORG_BY_SHORTNAME = 'open-ils.actor:open-ils.actor.org_unit.retrieve_by_shorname';
+var FETCH_BIB_ID_BY_BARCODE = 'open-ils.search:open-ils.search.bib_id.by_barcode';
/* ---------------------------------------------------------------------------- */
linknode.setAttribute("href", buildOPACLink(args));
}
+function setSessionCookie(ses) {
+ cookieManager.write(COOKIE_SES, ses, -1);
+}
+
+
/* ----------------------------------------------------------------------- */
/* user session handling */
if ses != G.user.session, we also force a grab */
function grabUser(ses, force) {
- if(!ses && isXUL()) ses = xulG['authtoken'];
+ if(!ses && isXUL()) {
+ stash = fetchXULStash();
+ ses = stash.session.key
+ _debug("stash auth token = " + ses);
+ }
if(!ses) {
ses = cookieManager.read(COOKIE_SES);
G.user = user;
G.user.fleshed = false;
G.user.session = ses;
- cookieManager.write(COOKIE_SES, ses, -1);
+ setSessionCookie(ses);
grabUserPrefs();
if(G.user.prefs['opac.hits_per_page'])
G.user.session = ses;
G.user.fleshed = true;
- cookieManager.write(COOKIE_SES, ses, '+1y'); /* update the cookie */
+ setSessionCookie(ses);
return G.user;
}
for( var i in orgArraySearcher ) {
var node = orgArraySearcher[i];
if( node == null ) continue;
+ if(!isXUL() && !isTrue(node.opac_visible())) continue;
if(node.parent_ou() == null)
tree.addNode(node.id(), -1, node.name(),
"javascript:orgSelect(" + node.id() + ");", node.name());
cookieManager.write(COOKIE_FONT, size, '+1y');
}
-
var resourceFormats = [
"text",
"moving image",
x.ou_type(_l[i][1]);
x.parent_ou(_l[i][2]);
x.name(_l[i][3]);
+ x.opac_visible(_l[i][4]);
orgArraySearcher[x.id()] = x;
}
for (var i in orgArraySearcher) {
/* split on spaces. capitalize the first /\w/ character in
each substring */
function normalize(val) {
+ return val; /* disable me for now */
if(!val) return "";
if(node) alert(node.innerHTML);
}
+function alertIdText(id, text) {
+ var node = $(id);
+ if(!node) return;
+ if(text)
+ alert(text + '\n\n' + node.innerHTML);
+ else
+ alert(node.innerHTML);
+}
+
function confirmId(id) {
var node = $(id);
if(node) return confirm(node.innerHTML);
border: 3px solid #A7EA9D;
-moz-border-radius: 6px;
padding: 6px;
- margin-top: 65px;'
+ margin-top: 65px;
}
.greenrow {
<div style='width: 60%; text-align:center; padding: 10px; font-size: 8pt;'>
<span class='footer_link'>
+ <a class='classic_link' href='/'>Dynamic Catalog</a>
+ </span>
+
+ <span> | </span>
+
+ <span class='footer_link'>
<a class='classic_link' href='advanced.html'>Advanced Search</a>
</span>
.light_border { border: 1px solid #E0E0E0; }
+/*.overdue { color: red; font-size: 110%; background: #F0F0E0; }*/
+.overdue { color: red; font-weight: bold;}
/*
#main_table { border-collapse: collapse; width: 100%; height: 100%; }
for( var i = 0; i < list.length; i++ ) {
var str = list[i];
for( var j = 0; j < str.length; j++ ) {
- if(str.charAt(j) == ' ') continue;
+ //if(str.charAt(j) == ' ') continue;
vals.push(str.charAt(j));
}
}
arg[PARAM_RTYPE] = RTYPE_TCN;
break;
+ case 'barcode':
+ advFindBarcode(term);
+ break;
+
case 'cn':
arg.page = CNBROWSE;
}
+function advFindBarcode(barcode) {
+ var req = new Request(FETCH_BIB_ID_BY_BARCODE, barcode);
+ req.callback(advDrawBarcode);
+ req.request.alertEvent = false;
+ req.send();
+}
+
+function advDrawBarcode(r) {
+ titleid = r.getResultObject();
+ if(checkILSEvent(titleid)) {
+ alertId('myopac.copy.not.found');
+ return;
+ }
+ if(!titleid) return;
+ var args = {};
+ args.page = RDETAIL;
+ args[PARAM_RID] = titleid;
+ location.href = buildOPACLink(args);
+}
+
+
+
item_form is specified, use item_type(s)--language
*/
+var noEmailMessage;
+
function holdsHandleStaff() {
swapCanvas($('xulholds_box'));
$('xul_recipient_barcode').focus();
holdArgs = (args) ? args : holdArgs;
+ if(!noEmailMessage)
+ noEmailMessage = $('holds_email').removeChild($('holds.no_email'));
+
if(isXUL() && holdArgs.recipient == null
&& holdArgs.editHold == null) {
holdsHandleStaff();
}
}
+ if(!G.user.email()) {
+ $('holds_enable_email').checked = false;
+ $('holds_enable_email').disabled = true;
+ var n = noEmailMessage.cloneNode(true);
+ appendClear( $('holds_email'), n);
+ unHideMe(n);
+ $('holds.no_email.my_account').setAttribute('href', buildOPACLink({page:MYOPAC},null,true));
+ }
+
if(!$('holds_phone').value)
$('holds_enable_phone').checked = false;
pickup_lib : pickuplib
};
- _debug("hold possible args = "+js2JSON(args));
+ if(recurse) {
+ /* if we're calling create again (recursing),
+ we know that the hold possibility check already succeeded */
+ holdHandleCreateResponse({_recurse:true, _hold:hold}, true );
- var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );
-
- req.request.alertEvent = false;
- req.request._hold = hold;
- req.request._recurse = recurse;
- req.callback(holdHandleCreateResponse);
- req.send();
+ } else {
+ _debug("hold possible args = "+js2JSON(args));
+
+ var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );
+
+ req.request.alertEvent = false;
+ req.request._hold = hold;
+ req.request._recurse = recurse;
+ req.callback(holdHandleCreateResponse);
+ req.send();
+ }
}
}
-function holdHandleCreateResponse(r) {
- var res = r.getResultObject();
- if(!res || checkILSEvent(res) ) {
- if(!res) {
- alert($('hold_not_allowed').innerHTML);
- } else {
- if( res.textcode == 'PATRON_BARRED' ) {
- alertId('hold_failed_patron_barred');
- } else {
+function holdHandleCreateResponse(r, recurse) {
+
+ if(!recurse) {
+ var res = r.getResultObject();
+ if(!res || checkILSEvent(res) ) {
+ if(!res) {
alert($('hold_not_allowed').innerHTML);
+ } else {
+ if( res.textcode == 'PATRON_BARRED' ) {
+ alertId('hold_failed_patron_barred');
+ } else {
+ alert($('hold_not_allowed').innerHTML);
+ }
}
+ swapCanvas($('holds_box'));
+ return;
}
- swapCanvas($('holds_box'));
- return;
- }
-
+ }
+
holdCreateHold(r._recurse, r._hold);
}
showCanvas();
- holdArgs = null;
runEvt('common', 'holdUpdated');
}
function holdProcessResult( hold, res, recurse ) {
+
if( res == '1' ) {
alert($('holds_success').innerHTML);
+ holdArgs = null;
} else {
var circsCache = new Array();
var checkedDrawn = false;
+function moClearCheckedTable() {
+ var tbody = $("myopac_checked_tbody");
+ var loading = $("myopac_checked_loading");
+ var none = $("myopac_checked_none");
+ clearNodes( tbody, [ loading, none ] );
+}
+
+var __can_renew_one = false;
+
function myOPACDrawCheckedOutSlim(r) {
var checked = r.getResultObject();
var loading = $("myopac_checked_loading");
var none = $("myopac_checked_none");
+ __can_renew_one = false;
+
if(checkedDrawn) return;
checkedDrawn = true;
if(!checkedRowTemplate)
checkedRowTemplate = tbody.removeChild($("myopac_checked_row"));
- clearNodes( tbody, [ loading, none ] );
+ moClearCheckedTable();
hideMe(loading); /* remove all children and start over */
if(!(checked && (checked.out || checked.overdue))) {
req.send();
}
+ appendClear($('mo_items_out_count'),
+ text(new String( parseInt(checked.overdue.length) + parseInt(checked.out.length) )) );
+
+ if( checked.overdue.length > 0 ) {
+ addCSSClass($('mo_items_overdue_count'), 'overdue');
+ appendClear($('mo_items_overdue_count'),
+ text(new String( parseInt(checked.overdue.length) )) );
+ }
+
}
+
function myOPACDrawCheckedItem(r) {
var circ = r.getResultObject();
var tbody = r.tbody;
var row = checkedRowTemplate.cloneNode(true);
row.id = 'myopac_checked_row_ ' + circ.id();
+ row.setAttribute('circid', circ.id());
var due = _trimTime(circ.due_date());
var dlink = $n( row, "myopac_checked_due" );
var rlink = $n( row, "myopac_checked_renewals" );
- var rnlink = $n( row, "myopac_checked_renew_link" );
+ //var rnlink = $n( row, "myopac_checked_renew_link" );
- if( r.od ) due = elem('b', {style:'color:red;font-size:110%'},due);
- else due = text(due);
+ //if( r.od ) due = elem('b', {style:'color:red;font-size:110%'},due);
+ if( r.od ) {
+ due = elem('b', null, due);
+ addCSSClass(due, 'overdue');
+ } else {
+ due = text(due);
+ }
dlink.appendChild(due);
rlink.appendChild(text(circ.renewal_remaining()));
unHideMe(row);
- rnlink.setAttribute('href', 'javascript:myOPACRenewCirc("'+circ.id()+'");');
+ //rnlink.setAttribute('href', 'javascript:myOPACRenewCirc("'+circ.id()+'");');
circsCache.push(circ);
- if( circ.renewal_remaining() < 1 ) hideMe(rnlink);
+ if( circ.renewal_remaining() < 1 ) {
+ $n(row, 'selectme').disabled = true;
+ if(!__can_renew_one)
+ $('mo_renew_button').disabled = true;
+ } else {
+ __can_renew_one = true;
+ $('mo_renew_button').disabled = false;
+ $n(row, 'selectme').disabled = false;
+ }
tbody.appendChild(row);
req.send();
}
+var __circ_titles = {};
+
function myOPACDrawCheckedTitle(r) {
var record = r.getResultObject();
var circid = r.circ;
var alink = $n( row, "myopac_checked_author_link" );
buildTitleDetailLink(record, tlink);
buildSearchLink(STYPE_AUTHOR, record.author(), alink);
+ __circ_titles[circid] = record.title();
}
function myOPACDrawNonCatalogedItem(r) {
tlink.parentNode.appendChild(text(copy.dummy_title()));
alink.parentNode.appendChild(text(copy.dummy_author()));
+ __circ_titles[circid] = copy.dummy_title();
}
+/*
function myOPACRenewCirc(circid) {
var circ;
if(!confirm($('myopac_renew_confirm').innerHTML)) return;
var req = new Request(RENEW_CIRC, G.user.session,
- { patron : G.user.id(), copyid : circ.target_copy() } );
+ { patron : G.user.id(), copyid : circ.target_copy(), opac_renewal : 1 } );
req.request.alertEvent = false;
req.send(true);
var res = req.result();
checkedDrawn = false;
myOPACShowChecked();
}
+*/
//function _trimTime(time) { if(!time) return ""; return time.replace(/\ .*/,""); }
function _trimTime(time) {
if(!time) return "";
- return time.replace(/T.*/,"");
+ var d = Date.parseIso8601(time);
+ if(!d) return ""; /* date parse failed */
+ return d.iso8601Format('YMD');
}
-function _trimSeconds(time) { if(!time) return ""; return time.replace(/:\d\d\..*$/,""); }
+function _trimSeconds(time) {
+ if(!time) return "";
+ var d = Date.parseIso8601(time);
+ if(!d) return ""; /* date parse failed */
+ return d.iso8601Format('YMDHM',null,true,true);
+}
function myOPACShowTransactions(r) {
fleshedUser = user;
if(!user) return;
+ var expireDate = Date.parseIso8601(user.expire_date());
+ if( expireDate < new Date() ) {
+ appendClear($('myopac.expired.date'), expireDate.iso8601Format('YMD'));
+ unHideMe($('myopac.expired.alert'));
+ }
+
var iv1 = user.ident_value()+'';
if (iv1.length > 4) iv1 = iv1.replace(new RegExp(iv1.substring(0,iv1.length - 4)), '***********');
duration = parseInt(duration + '000');
var dtf = circ.circ_time();
+ var start = Date.parseIso8601(circ.circ_time());
+ var due = new Date( start.getTime() + duration );
+ appendClear($n(row, 'circ_time'), text(due.iso8601Format('YMDHM', null, true, true)));
+}
- /*Date.W3CDTF is not happy with the milliseonds, nor is it
- happy without minute component of the timezone */
- dtf = dtf.replace(/\.\d+/,'');
- dtf += ":00";
- var start = new Date.W3CDTF();
- start.setW3CDTF(dtf);
- var due = new Date( start.getTime() + duration );
- due = (due+'').replace(/(.*?:\d\d):.*/, '$1');
- appendClear($n(row, 'circ_time'), text(due));
+
+function myopacSelectAllChecked() {
+ __myopacSelectChecked(true);
+}
+
+function myopacSelectNoneChecked() {
+ __myopacSelectChecked(false);
}
+function __myopacSelectChecked(value) {
+ var rows = myopacGetCheckedOutRows();
+ for( var i = 0; i < rows.length; i++ ) {
+ var row = rows[i];
+ var box = $n(row, 'selectme');
+ if( box && ! box.disabled )
+ box.checked = value;
+ }
+}
+
+function myopacGetCheckedOutRows() {
+ var rows = [];
+ var tbody = $('myopac_checked_tbody');
+ var children = tbody.childNodes;
+ for( var i = 0; i < children.length; i++ ) {
+ var child = children[i];
+ if( child.nodeName.match(/^tr$/i) )
+ if( $n(child, 'selectme') )
+ rows.push(child);
+ }
+ return rows;
+}
+
+var __renew_circs = [];
+
+/* true if 1 renewal succeeded */
+var __a_renew_success = false;
+
+/* renews all selected circulations */
+function myOPACRenewSelected() {
+ var rows = myopacGetCheckedOutRows();
+ if(!confirm($('myopac_renew_confirm').innerHTML)) return;
+ __a_renew_success = false;
+
+ var renewThese = [];
+
+ for( var i = 0; i < rows.length; i++ ) {
+
+ var row = rows[i];
+ if( ! $n(row, 'selectme').checked ) continue;
+ var circ_id = row.getAttribute('circid');
+
+ var circ;
+ for( var j = 0; j != circsCache.length; j++ )
+ if(circsCache[j].id() == circ_id)
+ circ = circsCache[j];
+
+ renewThese.push(circ);
+ }
+
+ for( var i = 0; i < renewThese.length; i++ ) {
+ var circ = renewThese[i];
+ moRenewCirc( circ.target_copy(), G.user.id(), circ );
+ }
+}
+
+
+/* renews a single circulation */
+function moRenewCirc(copy_id, user_id, circ) {
+
+ unHideMe($('my_renewing'));
+ moClearCheckedTable();
+
+ _debug('renewing circ ' + circ.id() + ' with copy ' + copy_id);
+ var req = new Request(RENEW_CIRC, G.user.session,
+ { patron : user_id,
+ copyid : copy_id, opac_renewal : 1
+ }
+ );
+
+ __renew_circs.push(circ.id());
+ req.request.alertEvent = false;
+ req.callback(myHandleRenewResponse);
+ req.request.circ = circ;
+ req.send();
+}
+
+
+
+/* handles the circ renew results */
+function myHandleRenewResponse(r) {
+ var res = r.getResultObject();
+ var circ = r.circ;
+
+ /* remove this circ from the list of circs to renew */
+ __renew_circs = grep(__renew_circs, function(i) { return (i != circ.id()); });
+
+ _debug("handling renew result for " + circ.id());
+
+ if(checkILSEvent(res) || checkILSEvent(res[0]))
+ alertIdText('myopac_renew_fail', __circ_titles[circ.id()]);
+ else __a_renew_success = true;
+
+ if(__renew_circs) return; /* more to come */
+
+ __renew_circs = [];
+
+ if( __a_renew_success )
+ alert($('myopac_renew_success').innerHTML);
+
+ hideMe($('my_renewing'));
+ checkedDrawn = false;
+ myOPACShowChecked();
+}
hideMe($('rdetail_extras_loading'));
$('rdetail_view_marc_box').innerHTML = r.getResultObject();
- var d = new Date();
-
var div = elem('div', { "class" : 'hide_me' });
var span = div.appendChild( elem('abbr') );
}
}
+ /* don't show hidden orgs */
if(node) {
+ if(!isXUL() && !isTrue(node.opac_visible())) return;
+
var row = copyRow.cloneNode(true);
row.id = "cp_info_" + node.id();
}
}
- if(isLocal) unHideMe(rowNode);
+ //if(isLocal) unHideMe(rowNode);
+ unHideMe(rowNode);
rdetailSetPath( thisOrg, isLocal );
rdetailBuildBrowseInfo( rowNode, arr[1], isLocal, thisOrg );
G.evt.result.hitCountReceived.push(resultSetHitInfo);
G.evt.result.recordReceived.push(resultDisplayRecord, resultAddCopyCounts);
G.evt.result.copyCountsReceived.push(resultDisplayCopyCounts);
- G.evt.result.allRecordsReceived.push(resultBuildCaches, resultDrawSubjects, resultDrawAuthors, resultDrawSeries);
+ G.evt.result.allRecordsReceived.push(resultBuildCaches, resultDrawSubjects,
+ resultDrawAuthors, resultDrawSeries, function(){unHideMe($('result_info_2'))});
attachEvt('result','lowHits',resultLowHits);
attachEvt('result','zeroHits',resultZeroHits);
attachEvt( "common", "locationUpdated", resultSBSubmit );
G.ui.result.current_page.appendChild(text(cpage));
G.ui.result.num_pages.appendChild(text(pages + ")")); /* the ) is dumb */
+ $('current_page2').appendChild(text(cpage));
+ $('num_pages2').appendChild(text(pages + ")")); /* the ) is dumb */
+
/* set the offsets */
var offsetEnd = getDisplayCount() + getOffset();
if( getDisplayCount() > (getHitCount() - getOffset()))
G.ui.result.offset_end.appendChild(text(offsetEnd));
G.ui.result.offset_start.appendChild(text(getOffset() + 1));
+ $('offset_end2').appendChild(text(offsetEnd));
+ $('offset_start2').appendChild(text(getOffset() + 1));
+
G.ui.result.result_count.appendChild(text(getHitCount()));
unHideMe(G.ui.result.info);
+
+ $('result_count2').appendChild(text(getHitCount()));
+ unHideMe($('result_info_div2'));
}
function resultLowHits() {
G.ui.result.next_link.setAttribute("href", buildOPACLink(args));
addCSSClass(G.ui.result.next_link, config.css.result.nav_active);
+ $('next_link2').setAttribute("href", buildOPACLink(args));
+ addCSSClass($('next_link2'), config.css.result.nav_active);
+
args[PARAM_OFFSET] = getHitCount() - (getHitCount() % getDisplayCount());
/* when hit count is divisible by display count, we have to adjust */
G.ui.result.end_link.setAttribute("href", buildOPACLink(args));
addCSSClass(G.ui.result.end_link, config.css.result.nav_active);
+
+ $('end_link2').setAttribute("href", buildOPACLink(args));
+ addCSSClass($('end_link2'), config.css.result.nav_active);
}
if( o > 0 ) {
G.ui.result.prev_link.setAttribute( "href", buildOPACLink(args));
addCSSClass(G.ui.result.prev_link, config.css.result.nav_active);
+ $('prev_link2').setAttribute( "href", buildOPACLink(args));
+ addCSSClass($('prev_link2'), config.css.result.nav_active);
+
args[PARAM_OFFSET] = 0;
G.ui.result.home_link.setAttribute( "href", buildOPACLink(args));
addCSSClass(G.ui.result.home_link, config.css.result.nav_active);
+
+ $('search_home_link2').setAttribute( "href", buildOPACLink(args));
+ addCSSClass($('search_home_link2'), config.css.result.nav_active);
}
- if(getDisplayCount() < getHitCount())
+ if(getDisplayCount() < getHitCount()) {
unHideMe($('start_end_links_span'));
+ unHideMe($('start_end_links_span2'));
+ }
showCanvas();
try{searchTimer.stop()}catch(e){}
function rresultHandleRIds(r) {
var res = r.getResultObject();
+ if(!res) res = {count:0,ids:[]};
+
if( res.count == 0 && rresultTries == 0 && ! r.noretry) {
rresultTries++;
<select multiple='true' size='3' id='adv_global_audience' class='hide_me'>
</select>
<select multiple='true' size='3' id='adv_global_audience_basic'>
- <option value='e'>Adult</option>
+ <option value='e '>Adult</option>
<option value='abcdj'>Juvenile</option>
<option value='fg '>General</option>
</select>
<tbody>
<tr>
+ <script>
+ function __setsortsel() {
+ var sel = $('adv_global_sort_by')
+ if(sel.selectedIndex == 0) {
+ $("adv_global_sort_dir").disabled = true;
+ $("adv_global_sort_dir").selectedIndex = 0;
+ } else $("adv_global_sort_dir").disabled = false;
+ }
+ </script>
+
<td align=''>
- <select id='adv_global_sort_by'
- onchange='
- if(this.selectedIndex == 0) {
- $("adv_global_sort_dir").disabled = true;
- $("adv_global_sort_dir").selectedIndex = 0;
- } else $("adv_global_sort_dir").disabled = false;'>
+ <select id='adv_global_sort_by' onchange='__setsortsel();'>
<option value='rel'>Relevance</option>
<option value='title'>Title</option>
<option value='author'>Author</option>
</select>
</td>
+
<td align='center' width='100%' nowrap='nowrap'>
<b id='now_searching_location'> </b>
</td>
</select>
</td>
+ <!-- force the enable/disable sort dir code to run -->
+ <script>__setsortsel();</script>
+
<td align='center'>
<!--#include virtual="../common/libselect.xml"-->
</td>
<link rel='search'
type="application/opensearchdescription+xml"
title="Evergreen"
- href="dev.gapines.org/opac/extras/opensearch/1.1/-/osd.xml"> </link>
+ href="http://<!--#echo var='SERVER_NAME'-->/opac/extras/opensearch/1.1/-/osd.xml"> </link>
<tr>
<td class='holds_cell'>&opac.holds.concactEmail;:</td>
- <td class='holds_cell' id='holds_email'> </td>
+ <td class='holds_cell' id='holds_email'>
+ <span class='hide_me' id='holds.no_email'>
+ (See <a class='classic_link' id='holds.no_email.my_account'>My Account</a> for setting your email address)
+ </span>
+ </td>
</tr>
<tr>
<td class='holds_cell'>Enable email notifications for this hold?</td>
<span class='hide_me' id='hold_not_allowed'>
No items were found that could fulfill the requested holds.
It's possible that choosing a different format will result in a successful hold.
- Otherwise, please consult your local librarian.
+ It is also possible that you have exceeded the number of allowable holds.
+ For further information, please consult your local librarian.
</span>
</div>
<option value='cn'>Call Number</option>
<option value='lccn'>LCCN</option>
<option value='tcn'>TCN</option>
+ <option value='barcode'>Item Barcode</option>
</select>
</td><td>
<input type='text' id='adv_quick_text' size='16'> </input>
</tr></tbody></table>
</div>
+ <span class='hide_me' id='myopac.copy.not.found'>No copy with the requested barcode was found</span>
<div style='margin-top: 8px;' class='adv_quick_search_submit'>
<a id='adv_quick_submit' href='javascript:advGenericSearch();' class='classic_link'>Submit</a>
</div>
style='width: 60%; text-align:center; padding: 10px; font-size: 8pt;'>
<span class='footer_link'>
+ <a class='classic_link'
+ href='/opac/extras/slimpac/start.html'>Basic Catalog (HTML only)</a>
+ </span>
+ <span> | </span>
+ <span class='footer_link'>
<a target='_blank' class='classic_link'
href='http://www.georgialibraries.org/lib/directories/pineslibdir.html'>Find a Library Near Me</a>
</span>
<body onload='init(); getId("home_adv_search_link").setAttribute("href", buildOPACLink({page:ADVANCED})); getId("home_myopac_link").setAttribute("href", buildOPACLink({page:MYOPAC}, false, true));'>
- <table width='100%' style='border-collapse: collapse;'>
+
+ <noscript>
+ <style type="text/css">#toptable { display: none; }</style>
+ <p style="font-size: 1.3em; padding: 3em; text-align: center;">
+ JavaScript must be enabled in order for you to use the regular Evergreen Catalog.
+ However, it seems JavaScript is either disabled or not supported by your browser.
+ To use the regular Evergreen Catalog, enable JavaScript by changing your browser options, then
+ <a style="color: blue; text-decoration: underline;" href="/">try again</a>.
+ <br/><br/>Alternatively, you can use the basic HTML-only catalog
+ <a style="color: blue; text-decoration: underline;" href="/opac/extras/slimpac/start.html">here</a>.
+ </p>
+ </noscript>
+
+ <table id='toptable' width='100%' style='border-collapse: collapse;'>
<tbody>
<tr>
<td width='10%'> </td>
</tbody>
</table>
<script language='javascript'>isFrontPage = true;</script>
+ <script language="javascript">
+ try {
+ document.getElementById('toptable').style.display = 'table';
+ } catch(e) {
+ try {
+ document.getElementById('toptable').style.display = '';
+ } catch(ee) {}
+ }
+ </script>
<center>
<!--#include virtual='../footer.xml'-->
</center>
<div id='myopac_checked_div' xmlns:xi="http://www.w3.org/2001/XInclude" >
- <script language='javascript' src='<!--#echo var="OILS_JS_BASE"-->/Date.W3CDTF.js'/>
+ <!--
+ <script language='javascript' src='<!||#echo var="OILS_JS_BASE"||>/Date.W3CDTF.js'/>
+ -->
+
+ <table width='100%'><tbody>
+ <tr>
+ <td aligh='left' class='data_grid'>
+ <!--
+ Total items out: <b id='mo_items_out_count' style='padding-right: 20px;'>0</b>
+ -->
+ Total items out: <b id='mo_items_out_count' style='padding: 5px;'>0</b> /
+ Total items overdue: <b id='mo_items_overdue_count' style='padding: 5px;'>0</b>
+ </td>
+ <td align='right'>
+ <button onclick='myOPACRenewSelected();' id='mo_renew_button' disabled='disabled'>Renew Selected Items</button>
+ </td>
+ </tr>
+ <tr id='my_renewing' class='hide_me'><td align='center'><b>Renewing...</b></td></tr>
+ </tbody></table>
<table width='100%' class='light_border data_grid'>
<thead class='color_3'>
<tr>
- <td width='50%'>Title</td>
+ <td width='45%'>Title</td>
<td width='20%'>Author</td>
<td width='10%' nowrap='nowrap' align='center'>Due Date</td>
<td width='10%' nowrap='nowrap' align='center'>Renewals Remaining</td>
- <td width='10%' nowrap='nowrap' align='center'>Renew</td>
+ <td width='15%'>Select
+ (<a id='myopac_select_all_checked' onclick='myopacSelectAllChecked();'
+ class='classic_link' href='javascript:void(0);'>All</a>/<a id='myopac_select_none_checked'
+ onclick='myopacSelectNoneChecked();' class='classic_link' href='javascript:void(0);'>None</a>)
+ </td>
</tr>
</thead>
+
<tbody id='myopac_checked_tbody'>
<tr id='myopac_checked_none' class='hide_me'>
<td colspan='10' align='center'><b>You have no items checked out at this time</b></td>
</tr>
+
+
<tr id='myopac_checked_loading'><td>Loading...</td></tr>
<tr id='myopac_checked_row' class='light_border hide_me'>
<td align='center' name='myopac_checked_due' class='light_border'> </td>
<td align='center' name='myopac_checked_renewals' class='light_border'> </td>
+ <!--
<td align='center' name='myopac_checked_renew' class='light_border'>
<a style='text-decoration:underline;' href='javascript:void(0);'
name='myopac_checked_renew_link' class='class_link'>Renew</a>
</td>
+ -->
+
+ <td align='center'><input type='checkbox' name='selectme'/></td>
</tr>
</tbody>
</table>
</div>
- <div id='myopac_renew_success' class='hide_me'>Item successfully renewed</div>
+ <div id='myopac_renew_success' class='hide_me'>Item(s) successfully renewed</div>
- <span class='hide_me' id='myopac_renew_confirm'>Are you sure you wish to renew this item?</span>
+ <span class='hide_me' id='myopac_renew_confirm'>Are you sure you wish to renew the selected item(s)?</span>
<span class='hide_me' id='myopac_renew_fail'>
- The system was unable to renew the selected item. Please ask a librarian for help.
+ The system is unable to renew the selected item at this time. This usually means the item is needed to fulfill a hold. Please see a librarian for further help.
</span>
+ <span class='hide_me' id='myopac_renew_fail2'>
+ PINES policy prevents the renewal of this item at this time. Please see a librarian for further details.
+ </span>
+
</div>
<div id='myopac_summary_div' xmlns:xi="http://www.w3.org/2001/XInclude" >
+
+ <div id='myopac.expired.alert' class='hide_me' style='margin-bottom: 20px;'>
+ <table class='data_grid' width='100%'>
+ <tbody>
+ <tr>
+ <td width='100%' style='color:red;'>
+ Your account expired on <span id='myopac.expired.date'/>!
+ Please see a librarian to renew your account.
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
<div id='myopac.notes.div' class='hide_me'>
<table class='data_grid' width='100%'>
<thead>
<br/>
</div>
- <!--
- <table class='light_border data_grid'>
- -->
<table width='70%' class='light_border myopac_summary_table'>
<tbody id='myopac_summary_tbody'>
- <!--
- <tr>
- <td class='color_4 light_border' width='20%'>First Name</td>
- <td class='light_border' id='myopac_summary_first'> </td>
- </tr>
- <tr>
- <td class='color_4 light_border'>Middle Name</td>
- <td class='light_border' id='myopac_summary_middle'> </td>
- </tr>
- <tr>
- <td class='color_4 light_border'>Last Name</td>
- <td class='light_border' id='myopac_summary_last'> </td>
- </tr>
- -->
-
<tr>
<td width='30%' class='color_4 light_border'>Name</td>
<td class='light_border'>
<div id='canvas_main' class='hide_me'>
<script language='javascript' src='../js/myopac.js'> </script>
+ <script language='javascript' src='<!--#echo var="OILS_JS_BASE"-->/DP_DateExtensions.js'/>
+
<script> config.ids.altcanvas.myopac_reload = 'myopac_reloading'; </script>
<div id='myopac_reloading' class='hide_me non_canvas'> Loading... </div>
</tbody>
</table>
+
+ <!-- ====================== -->
+ <table style='width: 100%; margin-top: 12px;' id='result_info_2' class='hide_me'>
+ <tbody>
+
+ <tr style='height: 1em; background: #E0F6E0'>
+
+ <td style='vertical-align: top;' id='next_prev_links2'>
+
+ <span class='hide_me' id='result_info_div2' style='font-size: 9pt;'>
+ <span> Results </span>
+ <b id='offset_start2'> </b>
+ <span> - </span>
+ <b id='offset_end2'> </b>
+ <span> &common.ofAtLeast; </span>
+ <b id='result_count2'> </b>
+ <span style='padding-left: 6px;'> (page </span>
+ <span id='current_page2'> </span>
+ <span> &common.of; </span>
+ <span id='num_pages2'> </span>
+ </span>
+
+ <span id='start_end_links_span2' class='hide_me'
+ style='padding-left: 40px;' >
+ <a class='search_page_nav_link' id='search_home_link2'
+ title="First results page">Start</a><a class='search_page_nav_link'
+ id='prev_link2' title='Previous page'><<</a>
+
+ <span class='search_page_nav_link' id='page_numbers2'> </span>
+ <a class='search_page_nav_link' id='next_link2'
+ title='Next Page'>>></a><a class='search_page_nav_link'
+ id='end_link2' title="Last results page">End</a>
+ </span>
+
+ </td>
+
+ <td colspan='5'
+ style='padding-bottom: 4px; text-align:center; vertical-align: top; border-bottom: 1px solid #E0E0E0;'>
+ <!--
+ <span id='search_info_table2' style='font-size: 8pt;'>
+ <b>Available copies / Total copies </b>
+ </span>
+ -->
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <!-- ====================== -->
+
+
<script language='javascript'>
config.names.result.format_cell = 'result_table_format_cell';
config.names.result.format_link = 'resource_link'
background: #E0F0F0;
min-height: 150px;
max-height: 290px;
- overflow: scroll;
+ overflow: auto;
}
.oils_rpt_small_info_selector {
border: 1px solid blue;
background: #E0F0F0;
height: 80px;
- overflow: scroll;
width: 12em;
+ overflow: auto;
}
border-style: inset;
}
+button:disabled {
+ color: #000;
+ background-color: #EEE;
+ border: 2px solid #888;
+}
+
.floaty {
position: absolute;
text-align: center;
fetchUser(cgi.param('ses'));
DOM.oils_rpt_user.appendChild(text(USER.usrname()));
+ if( cgi.param('dbg') ) oilsRptDebugEnabled = true;
+
fetchHighestPermOrgs(SESSION, USER.id(), perms);
if( PERMS.RUN_REPORTS == -1 ) {
unHideMe(DOM.oils_rpt_permission_denied);
/** initializes reports, some basid display settings,
* grabs and builds the IDL tree
*/
+
+var __dblclicks = {}; /* retain a cache of the selector value doubleclick event handlers */
+
function oilsInitReportBuilder() {
if(!oilsInitReports()) return false;
oilsReportBuilderReset();
/* manually shove data into the display selectors */
var def = JSON2js(template.data());
+ /* --------------------------------------------------------------- */
+ /* hack to determine the higest existing param in the template */
+ matches = template.data().match(/::P\d/g);
+ var max = 0;
+ for( var i = 0; i < matches.length; i++ ) {
+ var num = parseInt(matches[i].replace(/::P(\d)/,'$1'));
+ if( num > max ) max = num;
+ }
+ oilsRptID2 = max + 1;
+ _debug("set next avail param to " + oilsRptID2);
+ //_debug('PARAM = ' + oilsRptNextParam());
+ //var x = null;
+ //x.blah();
+ /* --------------------------------------------------------------- */
+
var table = def.from.table;
var node;
for( var i in oilsIDL ) {
function(item) {
oilsAddRptHavingItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
- oilsRpt.setTemplate(template);
+ //oilsRpt.setTemplate(template); /* commented out with clone fix, *shouldn't* break anything */
oilsRpt.templateObject = null; /* simplify debugging */
}
removeChildren(oilsRptFilterSelector);
removeChildren(oilsRptHavingSelector);
//removeChildren(oilsRptOrderBySelector);
- oilsRptResetParams();
+ //oilsRptResetParams();
}
function oilsReportBuilderSave() {
/* adds an item to the display window */
function oilsAddRptDisplayItem(path, name, tform, params) {
- if( ! oilsAddSelectorItem(oilsRptDisplaySelector, path, name) )
+
+ if( ! oilsAddSelectorItem(
+ { selector : oilsRptDisplaySelector,
+ val : path,
+ label : name,
+ path : path,
+ type : 'display',
+ transform : tform }) ) {
return;
+ }
/* add the selected columns to the report output */
name = (name) ? name : oilsRptPathCol(path);
iterate(oilsRpt.def.select,
function(item) {
_debug('re-inserting display item ' + item.path);
- oilsAddSelectorItem(oilsRptDisplaySelector, item.path, item.alias) });
+ oilsAddSelectorItem(
+ { selector: oilsRptDisplaySelector,
+ val:item.path,
+ label:item.alias,
+ path:item.path,
+ transform : item.column.transform,
+ type : 'display'
+ }
+ ) });
}
} else {
var newpath = "";
+ var last_is_left = false; /* true if our parent join is a 'left' join */
+
/* walk the path, fleshing the from clause as we go */
for( var i = 0; i < parts.length; i += 2 ) {
tobj = tobj[col];
if( field.type == 'link' ) {
tobj.key = field.key;
- if( field.reltype == 'has_many' || field.reltype == 'might_have' )
+ if( field.reltype == 'has_many' || field.reltype == 'might_have' || last_is_left ) {
tobj.type = 'left';
+ last_is_left = true;
+ } else {
+ last_is_left = false;
+ }
}
newpath = newpath + '-'+ path_col;
var opt = sel.options[idx];
sel.options[idx] = null;
idx--;
+
var val = opt.getAttribute('value');
- insertSelectorVal(sel, idx, opt.innerHTML, val);
+ var label = opt.getAttribute('label');
+ var path = opt.getAttribute('path');
+ var evt_id = opt.getAttribute('listener');
+
+ opt = insertSelectorVal(sel, idx, label, val);
+
+ opt.setAttribute('path', path);
+ opt.setAttribute('title', label);
+ opt.setAttribute('label', label);
+ opt.setAttribute('value', val);
+ opt.setAttribute('listener', evt_id);
+
+ /* re-attach the double-click event */
+ opt.addEventListener('dblclick', __dblclicks[evt_id], true );
+
sel.options[idx].selected = true;
var arr = oilsRpt.def.select;
var opt = sel.options[idx];
sel.options[idx] = null;
idx++;
+
+ //var val = opt.getAttribute('value');
+ //insertSelectorVal(sel, idx, opt.innerHTML, val);
+ //insertSelectorVal(sel, idx, opt.getAttribute('label'), val);
+
var val = opt.getAttribute('value');
- insertSelectorVal(sel, idx, opt.innerHTML, val);
+ var label = opt.getAttribute('label');
+ var path = opt.getAttribute('path');
+ var evt_id = opt.getAttribute('listener');
+
+ opt = insertSelectorVal(sel, idx, label, val);
+
+ opt.setAttribute('value', val);
+ opt.setAttribute('path', path);
+ opt.setAttribute('title', label);
+ opt.setAttribute('label', label);
+ opt.setAttribute('listener', evt_id);
+
+ /* re-attach the double-click event */
+ opt.addEventListener('dblclick', __dblclicks[evt_id], true );
+
sel.options[idx].selected = true;
var arr = oilsRpt.def.select;
var epath = name[1];
name = name[0];
- if( ! oilsAddSelectorItem(oilsRptFilterSelector, epath, name) )
+ if( ! oilsAddSelectorItem(
+ { selector : oilsRptFilterSelector,
+ val : epath,
+ label : name,
+ path : path,
+ transform : tform,
+ operation : filter,
+ type : 'filter'
+ }) )
return;
var where = {
column: { transform: tform, colname: oilsRptPathCol(path) },
condition : {}
};
+
+ //_debug('NEXT PARAM = ' + oilsRptID2);
+ //_debug('NEXT PARAM = ' + oilsRptNextParam());
+
if( filter == 'is' || filter == 'is not' )
where.condition[filter] = null;
else where.condition[filter] = oilsRptNextParam();
var epath = name[1];
name = name[0];
- if( ! oilsAddSelectorItem(oilsRptHavingSelector, epath, name) )
+ if( ! oilsAddSelectorItem(
+ { selector: oilsRptHavingSelector,
+ val:epath,
+ label:name,
+ path:path,
+ transform : tform,
+ operation : filter,
+ type : 'agg_filter' /* XXX */
+ }) )
+
return;
var having = {
function _oilsDelSelectedFilterItems(type) {
/* the values in this list are formed: <path>:<operation>:<transform> */
- var list = oilsDelSelectedItems(oilsRptFilterSelector);
+ var list;
+ if( type == 'where' )
+ list = oilsDelSelectedItems(oilsRptFilterSelector);
+ else if( type == 'having' )
+ list = oilsDelSelectedItems(oilsRptHavingSelector);
+
+ _debug("deleting filter items " + list);
for( var i = 0; i < list.length; i++ ) {
var enc_path = list[i];
var data = oilsRptParseFilterEncPath(enc_path);
+
+ _debug("trimming filter items with enc_path = " + enc_path);
+ _debug(data.path);
+ _debug(data.operation);
+ _debug(data.tform);
+ _debug(data.tform);
+ _debug(type);
+ _debug('---------------------');
+
oilsRpt.def[type] = grep(
oilsRpt.def[type],
function(f) {
- return oilsRptFilterDataMatches(
+ return ! oilsRptFilterDataMatches(
f, data.path, data.operation, data.tform );
}
);
if( col == filter.column.colname &&
rel == filter.relation &&
tform == filter.column.transform &&
- operation == oilsRptObjectKeys(filter)[0] ) return true;
+ operation == oilsRptObjectKeys(filter.condition)[0] ) return true;
return false;
}
-/*
-function oilsRptFilterGrep(flist, filter) {
-
- for( var j = 0; j < flist.length; j++ ) {
-
- var fil = flist[j];
- var col = filter.column;
- var frel = hex_md5(oilsRptPathRel(fil.path));
- var fcol = oilsRptPathCol(fil.path);
-
- var op = oilsRptObjectKeys(filter.condition)[0];
-
- if( frel == filter.relation &&
- fcol == col.colname &&
- fil.operation == op &&
- fil.tform == col.transform ) {
- return false;
- }
- }
- return true;
-}
-*/
-
/* adds an item to the display window */
+/*
function oilsAddRptAggFilterItem(val) {
- oilsAddSelectorItem(oilsRptHavingFilterSelector, val);
+ oilsAddSelectorItem({selector:oilsRptHavingFilterSelector, val:val, label:val, path:val});
}
+*/
/* removes a specific item from the display window */
+/*
function oilsDelAggFilterItem(val) {
oilsDelSelectorItem(oilsRptHavingFilterSelector, val);
}
+*/
+/* adds an item to the display window */
+//function oilsAddSelectorItem(sel, val, name, path) {
+function oilsAddSelectorItem(args) {
-/*
-function ___oilsDelSelectedAggFilterItems() {
- var list = oilsDelSelectedItems(oilsRptHavingFilterSelector);
- oilsRpt.def.having = grep( oilsRpt.def.having,
- function(i) {
- for( var j = 0; j < list.length; j++ ) {
- var d = list[j];
- var col = i.column;
+ var sel = args.selector;
+ var label = args.label;
+ var path = args.path;
+ var val = args.val;
- if( typeof col != 'string' )
- for( var c in col ) col = col[c];
+ label = (label) ? label : oilsRptMakeLabel(val);
- if( typeof col != 'string' ) col = col[0];
+ var i;
+ for( i = 0; i < sel.options.length; i++ ) {
+ var opt = sel.options[i];
+ if( opt.value == val ) return false;
+ }
- if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
- */
- // var param = (i.alias) ? i.alias.match(/::P\d*/) : null;
- /*
- if( param ) delete oilsRpt.params[param];
- return false;
- }
- }
- return true;
- }
- );
+ var opt = insertSelectorVal( sel, -1, label, val );
+ opt.setAttribute('title', label);
+ opt.setAttribute('path', path);
+ opt.setAttribute('label', label);
- if(!oilsRpt.def.having) oilsRpt.def.having = [];
- oilsRptPruneFromList(list);
- oilsRptDebug();
-}
-*/
+ var evt_id = oilsNextNumericId();
+ opt.setAttribute('listener', evt_id);
+ args.index = i;
+ delete args.selector;
+ var listener = function(){ oilsRptDrawDataWindow(path, args);};
+ opt.addEventListener('dblclick', listener, true );
+ __dblclicks[evt_id] = listener;
+ //function(){ oilsRptDrawDataWindow(path, args);} , true);
-/* adds an item to the display window */
-function oilsAddSelectorItem(sel, val, name) {
- name = (name) ? name : oilsRptMakeLabel(val);
- for( var i = 0; i < sel.options.length; i++ ) {
- var opt = sel.options[i];
- if( opt.value == val ) return false;
- }
- var opt = insertSelectorVal( sel, -1, name, val );
- opt.setAttribute('title', name);
return true;
}
This draws the 3-tabbed window containing the transform,
filter, and aggregate filter picker window
*/
-function oilsRptDrawDataWindow(path) {
+function oilsRptDrawDataWindow(path, args) {
+
+ args = (args) ? args : {};
+
+ for( var x in args )
+ _debug("oilsRptDrawDataWindow(): args -> " + x + " = " + args[x]);
+
var col = oilsRptPathCol(path);
var cls = oilsRptPathClass(path);
var field = oilsRptFindField(oilsIDL[cls], col);
/* don't let them see the floating div until the position is fully determined */
div.style.visibility='hidden';
- oilsRptDrawTransformWindow(path, col, cls, field);
- oilsRptDrawFilterWindow(path, col, cls, field);
- oilsRptDrawHavingWindow(path, col, cls, field);
+ oilsRptDrawTransformWindow(path, col, cls, field, args);
+ oilsRptDrawFilterWindow(path, col, cls, field, args);
+ oilsRptDrawHavingWindow(path, col, cls, field, args);
//oilsRptDrawOrderByWindow(path, col, cls, field);
//buildFloatingDiv(div, 600);
/* now let them see it */
div.style.visibility='visible';
- oilsRptSetDataWindowActions(div);
+ //args.type = (args.type) ? args.type : 'display';
+ oilsRptSetDataWindowActions(div, args);
}
-function oilsRptSetDataWindowActions(div) {
+function oilsRptSetDataWindowActions(div, args) {
/* give the tab links behavior */
-
DOM.oils_rpt_tform_tab.onclick =
function(){
oilsRptHideEditorDivs();
unHideMe(DOM.oils_rpt_filter_div)
addCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
};
+
DOM.oils_rpt_agg_filter_tab.onclick =
function(){
oilsRptHideEditorDivs();
};
*/
- DOM.oils_rpt_tform_tab.onclick();
+ DOM.oils_rpt_tform_submit.disabled = false;
+ DOM.oils_rpt_filter_submit.disabled = false;
+ DOM.oils_rpt_agg_filter_submit.disabled = false;
+
+ if( !args.type ) {
+ DOM.oils_rpt_tform_tab.onclick();
+ } else {
+ /* disable editing on existing items for now */
+ if( args.type == 'display' ) {
+ DOM.oils_rpt_tform_tab.onclick();
+ DOM.oils_rpt_tform_submit.disabled = true;
+ }
+ if( args.type == 'filter' ) {
+ DOM.oils_rpt_filter_tab.onclick();
+ DOM.oils_rpt_filter_submit.disabled = true;
+ }
+ if( args.type == 'agg_filter' ) {
+ DOM.oils_rpt_agg_filter_tab.onclick();
+ DOM.oils_rpt_agg_filter_submit.disabled = true;
+ }
+ }
+
DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
}
-function oilsRptDrawFilterWindow(path, col, cls, field) {
+function oilsRptDrawFilterWindow(path, col, cls, field, args) {
var tformPicker = new oilsRptTformPicker( {
node : DOM.oils_rpt_filter_tform_table,
datatype : field.datatype,
- non_aggregate : true
+ non_aggregate : true,
+ select : args.transform
}
);
var filterPicker = new oilsRptFilterPicker({
node : DOM.oils_rpt_filter_op_table,
- datatype : field.datatype
+ datatype : field.datatype,
+ select : args.operation
}
);
}
-function oilsRptDrawHavingWindow(path, col, cls, field) {
+function oilsRptDrawHavingWindow(path, col, cls, field, args) {
var tformPicker = new oilsRptTformPicker( {
node : DOM.oils_rpt_agg_filter_tform_table,
datatype : field.datatype,
- aggregate : true
+ aggregate : true,
+ select : args.transform
}
);
var filterPicker = new oilsRptFilterPicker({
node : DOM.oils_rpt_agg_filter_op_table,
- datatype : field.datatype
+ datatype : field.datatype,
+ select : args.operation
}
);
}
/* draws the transform window */
-function oilsRptDrawTransformWindow(path, col, cls, field) {
- DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
+function oilsRptDrawTransformWindow(path, col, cls, field, args) {
+ args = (args) ? args : {};
+
+ DOM.oils_rpt_tform_label_input.value =
+ (args.label) ? args.label : oilsRptMakeLabel(path);
+
var dtype = field.datatype;
var tformPicker = new oilsRptTformPicker( {
node : DOM.oils_rpt_tform_table,
datatype : field.datatype,
non_aggregate : true,
- aggregate : true
+ aggregate : true,
+ select : args.transform
}
);
</tr>
</tbody></table>
+
<div id='oils_rpt_tree_div'>
</div>
+
+ <br/>
+ <div>
+ <b>**</b>
+ <span style='padding-left: 6px;'>
+ Indicates that when filtering on the item, a list of named choices will be generated.
+ </span>
+ </div>
+
</td>
<td id='oils_rpt_table_right_td' align='right'>
<div class='oils_rpt_info_div'>
<select id='oils_rpt_agg_filter_selector' class='oils_rpt_info_item oils_rpt_info_selector' multiple='multiple'/>
<button onclick='oilsDelSelectedAggFilterItems();'><u>X</u> Remove Selected</button>
</div>
+ <div class='oils_rpt_info_div'>
+ <span style='color:red;font-weight:bold;'>Hint: </span> Double-click on an item to see the item details.
+ </div>
</td>
</tr>
</tbody>
(<span id='oils_rpt_editor_window_datatype'/>)
</div>
<div id='oils_rpt_tform_div'>
- <input size='28' id='oils_rpt_tform_label_input'/>
+ <input size='42' id='oils_rpt_tform_label_input'/>
<div class='oils_rpt_field_editor_window'>
<div style='margin-bottom: 10px;'>Select how this field should be displayed:</div>
<div id='oils_rpt_tform_table'/>
this.dtype = args.datatype;
this.selector = elem('select');
for( var key in OILS_RPT_FILTERS )
- this.addOpt(key);
+ this.addOpt(key, key == args.select );
appendClear(this.node, this.selector);
}
-oilsRptFilterPicker.prototype.addOpt = function(key) {
+oilsRptFilterPicker.prototype.addOpt = function(key, select) {
var filter = OILS_RPT_FILTERS[key];
var label = filter.label;
- insertSelectorVal( this.selector, -1, label, key);
+ var opt = insertSelectorVal( this.selector, -1, label, key);
+ if( select ) opt.selected = true;
if( filter.labels && filter.labels[this.dtype] )
insertSelectorVal( this.selector, -1, filter.labels[this.dtype], key);
}
var url = oilsRptBuildOutputLink(r.template(), r.id(), sched.id());
_debug("launching report output view at URL: " + url);
if(isXUL())
- xulG.new_tab(url,{"tab_name":"Report Output: " + r.name()},{})
+ xulG.new_tab('/xul/server/util/rbrowser.xul?url=' + url, /* this comes from urls.XUL_REMOTE_BROWSER */
+ {tab_name:'Report Output: ' + r.name(), browser:true},
+ {no_xulG:false, show_nav_buttons:true, show_print_button:true});
else {
//goTo(url);
var win = window.open(url,r.name(), 'resizable,width=800,height=600,scrollbars=1');
atomicWidget = oilsRptNumberWidget
break;
+ case 'substring':
+ atomicWidget = oilsRptSubstrWidget
+ break;
+
}
rptObject, DOM.oils_rpt_param_editor_tbody);
this.paramEditor.draw();
+ removeChildren(DOM.oils_rpt_report_editor_selected_folder);
+ removeChildren(DOM.oils_rpt_output_selected_folder);
+
var obj = this;
oilsRptBuildFolder(
'report',
/* string transforms ------------------------- */
+ /* XXX not supported yet
substring : {
datatype : OILS_RPT_DTYPE_STRING,
label : 'Substring'
},
+ */
lower : {
datatype : OILS_RPT_DTYPE_STRING,
label : 'Age'
},
- /*
- relative_year : {
- datatype : OILS_RPT_DTYPE_TIMESTAMP,
- label : 'Relative year'
- },
-
- relative_month : {
- datatype : OILS_RPT_DTYPE_TIMESTAMP,
- label : 'Relative month'
- },
-
- relative_week : {
- datatype : OILS_RPT_DTYPE_TIMESTAMP,
- label : 'Relative week'
- },
-
- relative_date : {
- datatype : OILS_RPT_DTYPE_TIMESTAMP,
- label : 'Relative date'
- },
- */
-
- /* exists?
- days_ago : {
- datatype : OILS_RPT_DTYPE_TIMESTAMP,
- label : 'Days ago'
- }
- */
-
months_ago : {
datatype : OILS_RPT_DTYPE_TIMESTAMP,
label : 'Months ago'
label : 'Quarters ago'
},
-
- /* exists?
- years_ago : {
- datatype : OILS_RPT_DTYPE_TIMESTAMP,
- label : 'Years ago'
- },
- */
-
-
/* int / float transforms ----------------------------------- */
sum : {
datatype : [ OILS_RPT_DTYPE_INT, OILS_RPT_DTYPE_FLOAT ],
this.selector = elem('select');
this.tforms = oilsRptGetTforms(args);
for( var i = 0; i < this.tforms.length; i++ )
- this.addOpt(this.tforms[i]);
+ this.addOpt(this.tforms[i], this.tforms[i] == args.select );
appendClear(this.node, this.selector);
}
-oilsRptTformPicker.prototype.addOpt = function(key) {
+oilsRptTformPicker.prototype.addOpt = function(key, select) {
var tform = OILS_RPT_TRANSFORMS[key];
var obj = this;
- insertSelectorVal(this.selector, -1, tform.label, key);
+ var opt = insertSelectorVal(this.selector, -1, tform.label, key);
+ if( select ) opt.selected = true;
}
oilsRptTformPicker.prototype.getSelected = function(key) {
action = 'javascript:oilsAddLinkTree("' +
dataId+'","'+field['class']+'","'+fullpath+'");';
- oilsRptTree.addNode( dataId, subTreeId, field.label, action, field.label,
+ label = field.label;
+
+ /* indicate that this will build a friendly list at report time */
+ if( field.selector ) label += ' **';
+
+ oilsRptTree.addNode( dataId, subTreeId, label, action, field.label,
(field.type == 'link') ? 'oils_rpt_tree_link_ref' : null );
}
}
str += oilsIDL[parts[i]].label;
} else {
var f = oilsRptFindField(oilsIDL[parts[i-1]], parts[i]);
- str += ":"+f.label;
+ str += " -> "+f.label;
}
}
return str;
oilsRptSetWidget.prototype.objToStr = function(obj) {
if( typeof obj == 'string' ) return obj;
- return ':'+obj.transform+':'+obj.params[0];
+ //return ':'+obj.transform+':'+obj.params[0];
+ var str = ':'+obj.transform;
+ for( var i = 0; i < obj.params.length; i++ )
+ str += ':' + obj.params[i];
+ _debug("objToStr(): built string " + str);
+ return str;
+
}
oilsRptSetWidget.prototype.strToObj = function(str) {
if( str.match(/^:.*/) ) {
- var tform = str.replace(/^:(.*):.*/,'$1');
- var param = str.replace(/^:.*:(.*)/,'$1');
- return { transform : tform, params : [param] };
+ var parts = str.split(/:/);
+ _debug("strToObj(): " + str + ' : ' + parts);
+ parts.shift();
+ var tform = parts.shift();
+ //var tform = str.replace(/^:(.*):.*/,'$1');
+ //var param = str.replace(/^:.*:(.*)/,'$1');
+ return { transform : tform, params : parts };
}
return str;
}
org.shortname(), org.id(), null, findOrgDepth(org) );
if( org.id() == oilsRptCurrentOrg )
opt.selected = true;
+
+ /* sometimes we need these choices
+ if( !isTrue(findOrgType(org.ou_type()).can_have_vols()) )
+ opt.disabled = true;
+ */
+
if( org.children() ) {
for( var c = 0; c < org.children().length; c++ )
this.draw(org.children()[c]);
/* ---------------------------------------------------------------------
+ Atomic substring picker
+ --------------------------------------------------------------------- */
+function oilsRptSubstrWidget(args) {
+ this.node = args.node
+ this.data = elem('input',{type:'text',size:12})
+ this.offset = elem('input',{type:'text',size:5})
+ this.length = elem('input',{type:'text',size:5})
+}
+
+oilsRptSubstrWidget.prototype.draw = function() {
+ this.node.appendChild(text('string: '))
+ this.node.appendChild(this.data);
+ this.node.appendChild(elem('br'));
+ this.node.appendChild(text('offset: '))
+ this.node.appendChild(this.offset);
+ this.node.appendChild(elem('br'));
+ this.node.appendChild(text('length: '))
+ this.node.appendChild(this.length);
+}
+
+oilsRptSubstrWidget.prototype.getValue = function() {
+ return {
+ transform : 'substring',
+ params : [ this.data.value, this.offset.value, this.length.value ]
+ };
+}
+
+oilsRptSubstrWidget.prototype.getDisplayValue = function() {
+ return {
+ label : this.data.value + ' : ' + this.offset.value + ' : ' + this.length.value,
+ value : this.getValue()
+ };
+}
+
+
+/* ---------------------------------------------------------------------
Atomic number picker
--------------------------------------------------------------------- */
function oilsRptNumberWidget(args) {
insertSelectorVal(this.selector,-1,'Relative Date',2);
this.numberPicker =
- new oilsRptNumberWidget({node:this.relSpan,size:24,start:1});
+ new oilsRptNumberWidget({node:this.relSpan,size:90,start:1});
this.label = 'Day(s)';
if(this.type == 'month') this.label = 'Month(s)';
</xsl:choose>
</xsl:when>
<xsl:otherwise>
- <xsl:value-of select="concat('/opac/extras/jacket/small/','---')"/>
+ <xsl:text>/opac/extras/jacket/small/</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
build_dir:
@echo
+ @echo '********************************************************* Kludge, make sure these directories exists '
+ mkdir -p chrome/locale/en-US/
+ mkdir -p chrome/content/OpenSRF/
+ @echo
@echo '********************************************************* Creating and populating build/ '
mkdir -p build/
cp -R chrome build/
--- /dev/null
+<!ENTITY brandShortName "Evergreen">
+<!ENTITY brandFullName "Evergreen">
+<!ENTITY vendorShortName "open-ils.org">
+
+<!-- LOCALIZATION NOTE (releaseBaseURL): The about: page appends __MOZ_APP_VERSION__.html, e.g. 2.0.html -->
+<!ENTITY releaseBaseURL "http://open-ils.org/cvs/">
--- /dev/null
+brandShortName=Evergreen
+brandFullName=Evergreen
+vendorShortName=open-ils.org
content open_ils_staff_client content/
locale open_ils_staff_client en-US locale/en-US/
skin open_ils_staff_client open_ils_staff_client skin/
+locale branding en-US branding/locale/en-US/
}
file.close();
+ JSAN.use('util.file'); var file = new util.file('print_strategy');
+ if (file._file.exists()) {
+ try {
+ var x = file.get_content();
+ if (x) {
+ obj.print_strategy = x;
+ obj.stash('print_strategy');
+ obj.data_progress('Print strategy retrieved from file. ');
+ }
+ } catch(E) {
+ alert(E);
+ }
+ }
+ file.close();
+
JSAN.use('util.functional');
JSAN.use('util.fm_utils');
}
const api = {
+ 'TEST_SECURE' : { 'app' : 'open-ils.actor', 'method' : 'opensrf.system.time' },
+ 'TEST_UNSECURE' : { 'app' : 'open-ils.actor', 'method' : 'opensrf.system.time', 'secure' : false },
'AUTH_INIT' : { 'app' : 'open-ils.auth', 'method' : 'open-ils.auth.authenticate.init' },
'AUTH_COMPLETE' : { 'app' : 'open-ils.auth', 'method' : 'open-ils.auth.authenticate.complete' },
'AUTH_DELETE' : { 'app' : 'open-ils.auth', 'method' : 'open-ils.auth.session.delete' },
'AUTH_WORKSTATION' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.workstation.register' },
'BILL_PAY' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.money.payment' },
- 'BILLING_TYPE_LIST' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.billing_type.retrieve.all' },
+ 'BILLING_TYPE_LIST' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.billing_type.retrieve.all', 'secure' : false },
'BLOB_AU_PARTS_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.retrieve.parts' },
- 'BLOB_MARC_CALLNUMBERS_RETRIEVE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.marc_cn.retrieve' },
+ 'BLOB_MARC_CALLNUMBERS_RETRIEVE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.marc_cn.retrieve', 'secure' : false },
'BLOB_MOBTS_CIRC_MVR_HAVING_BALANCE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.transactions.have_balance.fleshed' },
'BLOB_MOBTS_CIRC_MVR_OPEN' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.transactions.fleshed' },
'BUCKET_CREATE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.create' },
- 'BUCKET_DELETE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.delete' },
'BUCKET_FLESH' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.flesh' },
- 'BUCKET_FULL_DELETE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.full_delete' },
+ 'BUCKET_DELETE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.full_delete' },
'BUCKET_RETRIEVE_VIA_USER' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.all.retrieve_by_user' },
'BUCKET_ITEM_CREATE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.item.create' },
'BUCKET_ITEM_DELETE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.container.item.delete' },
'CAPTURE_COPY_FOR_HOLD_VIA_BARCODE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold.capture_copy.barcode' },
'CHECKIN_VIA_BARCODE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.checkin' },
'CHECKOUT' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.checkout' },
+ 'CHECKOUT_FULL' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.checkout.full' },
'CHECKOUT_PERMIT' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.checkout.permit' },
'CHECKOUT_RENEW' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.renew' },
'CIRC_MODIFIER_LIST' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.circ_modifier.retrieve.all' },
- 'FM_ACN_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.callnumber.retrieve' },
+ 'FM_ACN_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.callnumber.retrieve', 'secure' : false },
'FM_ACN_TREE_UPDATE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.asset.volume.fleshed.batch.update' },
- 'FM_ACN_TREE_LIST_RETRIEVE_VIA_RECORD_ID_AND_ORG_IDS' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.asset.copy_tree.retrieve' },
+ 'FM_ACN_TREE_LIST_RETRIEVE_VIA_RECORD_ID_AND_ORG_IDS' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.asset.copy_tree.retrieve', 'secure' : false },
'FM_ACN_TRANSFER' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.asset.volume.batch.transfer' },
- 'FM_ACN_FIND_OR_CREATE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.call_number.find_or_create' },
+ 'FM_ACN_FIND_OR_CREATE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.call_number.find_or_create', 'secure' : false },
'FM_ACP_DETAILS' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_details.retrieve' },
+ 'FM_ACP_DETAILS_VIA_BARCODE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_details.retrieve.barcode' },
//'FM_ACP_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed.retrieve' },
- 'FM_ACP_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed2.retrieve' },
+ 'FM_ACP_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed2.retrieve', 'secure' : false },
//'FM_ACP_RETRIEVE_VIA_BARCODE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.find_by_barcode' },
- 'FM_ACP_RETRIEVE_VIA_BARCODE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed2.find_by_barcode' },
- 'FM_ACP_FLESHED_BATCH_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed.batch.retrieve' },
+ 'FM_ACP_RETRIEVE_VIA_BARCODE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed2.find_by_barcode', 'secure' : false },
+ 'FM_ACP_FLESHED_BATCH_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed.batch.retrieve', 'secure' : false },
'FM_ACP_FLESHED_BATCH_UPDATE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.asset.copy.fleshed.batch.update' },
- 'FM_ACPL_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_location.retrieve.all' },
- 'FM_ACPL_RETRIEVE_VIA_ID' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_location.retrieve' },
- 'FM_ACPN_RETRIEVE_ALL' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_note.retrieve.all' },
+ 'FM_ACPL_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_location.retrieve.all', 'secure' : false },
+ 'FM_ACPL_RETRIEVE_VIA_ID' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_location.retrieve', 'secure' : false },
+ 'FM_ACPN_RETRIEVE_ALL' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_note.retrieve.all', 'secure' : false },
'FM_ACPN_CREATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_note.create' },
- 'FM_ACPN_DELETE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_note.delete' },
- 'FM_ACTSC_RETRIEVE_BATCH' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.actor.retrieve.batch' },
- 'FM_ACTSC_RETRIEVE_VIA_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.actor.retrieve.all' },
+ 'FM_ACPN_DELETE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.copy_note.delete', 'secure' : false },
+ 'FM_ACTSC_RETRIEVE_BATCH' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.actor.retrieve.batch', 'secure' : false },
+ 'FM_ACTSC_RETRIEVE_VIA_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.actor.retrieve.all', 'secure' : false },
'FM_AHN_CREATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_notification.create' },
'FM_AHN_RETRIEVE_VIA_AHR' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_notification.retrieve_by_hold' },
'FM_AHR_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.holds.retrieve_by_id' },
'FM_AHR_RETRIEVE_VIA_PICKUP_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.holds.retrieve_by_pickup_lib' },
'FM_AHR_ID_LIST_RETRIEVE_VIA_PICKUP_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.holds.id_list.retrieve_by_pickup_lib' },
'FM_AHR_PULL_LIST' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_pull_list.retrieve' },
- 'FM_AHR_ID_LIST_PULL_LIST' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_pull_list.id_list.retrieve' },
+ 'FM_AHR_ID_LIST_PULL_LIST' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_pull_list.id_list.retrieve', 'secure' : false },
'FM_AHR_ONSHELF_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.captured_holds.on_shelf.retrieve' },
- 'FM_AHR_ID_LIST_ONSHELF_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.captured_holds.id_list.on_shelf.retrieve' },
+ 'FM_AHR_ID_LIST_ONSHELF_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.captured_holds.id_list.on_shelf.retrieve', 'secure' : false },
'FM_AHR_COUNT_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.hold_requests.count' },
'FM_AHR_CANCEL' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold.cancel' },
'FM_AHR_UPDATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold.update' },
'FM_ANCC_RETRIEVE_VIA_ID' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.non_cataloged_circulation.retrieve' },
'FM_ANCC_RETRIEVE_VIA_USER' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.open_non_cataloged_circulation.user' },
'FM_ANCIHU_CREATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.non_cat_in_house_use.create' },
- 'FM_AOA_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.org_unit.address.retrieve' },
- 'FM_AOU_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.org_tree.retrieve' },
+ 'FM_AOA_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.org_unit.address.retrieve', 'secure' : false },
+ 'FM_AOU_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.org_tree.retrieve', 'secure' : false },
'FM_AOU_RETRIEVE_RELATED_VIA_SESSION' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.org_unit.full_path.retrieve' },
- 'FM_AOU_IDS_RETRIEVE_VIA_RECORD_ID' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.actor.org_unit.retrieve_by_title' },
- 'FM_AOUT_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.org_types.retrieve' },
- 'FM_ASC_BATCH_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.asset.retrieve.batch' },
- 'FM_ASC_RETRIEVE_VIA_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.asset.retrieve.all' },
+ 'FM_AOU_IDS_RETRIEVE_VIA_RECORD_ID' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.actor.org_unit.retrieve_by_title', 'secure' : false },
+ 'FM_AOUT_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.org_types.retrieve', 'secure' : false },
+ 'FM_ASC_BATCH_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.asset.retrieve.batch', 'secure' : false },
+ 'FM_ASC_RETRIEVE_VIA_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.stat_cat.asset.retrieve.all', 'secure' : false },
'FM_ASV_CREATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.survey.create' },
- 'FM_ASV_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.survey.retrieve.all' },
+ 'FM_ASV_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.survey.retrieve.all', 'secure' : false },
'FM_ASV_RETRIEVE_REQUIRED' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.survey.retrieve.required' },
'FM_ASVR_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.survey.response.retrieve' },
'FM_ATC_VOID' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.transit.abort' },
- 'FM_ATC_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.transit.retrieve' },
- 'FM_ATC_RETRIEVE_VIA_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.transit.retrieve_by_lib' },
+ 'FM_ATC_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.transit.retrieve', 'secure' : false },
+ 'FM_ATC_RETRIEVE_VIA_AOU' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.transit.retrieve_by_lib', 'secure' : false },
'FM_AU_IDS_RETRIEVE_VIA_HASH' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.patron.search.advanced' },
'FM_AU_LIST_RETRIEVE_VIA_GROUP' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.usergroup.members.retrieve' },
'FM_AU_RETRIEVE_VIA_SESSION' : { 'app' : 'open-ils.auth', 'method' : 'open-ils.auth.session.retrieve' },
'FM_AUN_DELETE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.note.delete' },
'FM_AUS_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.patron.settings.retrieve' },
'FM_AUS_UPDATE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.patron.settings.update' },
- 'FM_BRE_RETRIEVE_VIA_ID' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.metadata.retrieve' },
- 'FM_BRE_ID_SEARCH_VIA_BARCODE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.find_by_barcode' },
- 'FM_BRE_ID_SEARCH_VIA_TCN' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.tcn' },
- 'FM_BRN_FROM_MARCXML' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.z3950.marcxml_to_brn' },
- 'FM_CCS_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.config.copy_status.retrieve.all' },
+ 'FM_BRE_RETRIEVE_VIA_ID' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.metadata.retrieve', 'secure' : false },
+ 'FM_BRE_ID_SEARCH_VIA_BARCODE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.find_by_barcode', 'secure' : false },
+ 'FM_BRE_ID_SEARCH_VIA_TCN' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.tcn', 'secure' : false },
+ 'FM_BRN_FROM_MARCXML' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.z3950.marcxml_to_brn', 'secure' : false },
+ 'FM_CCS_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.config.copy_status.retrieve.all', 'secure' : false },
'FM_CIRC_DETAILS' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.fleshed.retrieve' },
'FM_CIRC_RETRIEVE_VIA_ID' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.retrieve' },
/*'FM_CIRC_RETRIEVE_VIA_USER' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.actor.user.checked_out.slim' },*/
'FM_CIRC_COUNT_RETRIEVE_VIA_USER' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.checked_out.count' },
'FM_CIRC_COUNT_RETRIEVE_VIA_COPY' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.circulation.count' },
'FM_CIRC_EDIT_DUE_DATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.circulation.due_date.update' },
- 'FM_CIT_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.ident_types.retrieve' },
- 'FM_CITM_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.item_type_map.retrieve.all' },
- 'FM_CNAL_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.net_access_level.retrieve.all' },
- 'FM_CNCT_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.non_cat_types.retrieve.all' },
- 'FM_CRAHP_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.config.rules.age_hold_protect.retrieve.all' },
- 'FM_CST_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.standings.retrieve' },
+ 'FM_CIT_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.ident_types.retrieve', 'secure' : false },
+ 'FM_CITM_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.item_type_map.retrieve.all', 'secure' : false },
+ 'FM_CNAL_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.net_access_level.retrieve.all', 'secure' : false },
+ 'FM_CNCT_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.non_cat_types.retrieve.all', 'secure' : false },
+ 'FM_CRAHP_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.config.rules.age_hold_protect.retrieve.all', 'secure' : false },
+ 'FM_CST_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.standings.retrieve', 'secure' : false },
'FM_MB_CREATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.money.billing.create' },
'FM_MB_RETRIEVE_VIA_MBTS_ID' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.money.billing.retrieve.all' },
'FM_MB_VOID' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.money.billing.void' },
'FM_MOBTS_TOTAL_OPEN' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.transactions.total' },
'FM_MOBTS_COUNT_OPEN' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.transactions.count' },
'FM_MOUS_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.fines.summary' },
- 'FM_PGT_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.groups.tree.retrieve' },
- 'MARC_HTML_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.record.html' },
+ 'FM_PGT_RETRIEVE' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.groups.tree.retrieve', 'secure' : false },
+ 'MARC_HTML_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.record.html', 'secure' : false },
'FM_BLOB_RETRIEVE_VIA_Z3950_SEARCH' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.z3950.search_class' },
'FM_BLOB_RETRIEVE_VIA_Z3950_RAW_SEARCH' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.z3950.search_service' },
- 'RETRIEVE_Z3950_SERVICES' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.z3950.retrieve_services' },
+ 'RETRIEVE_Z3950_SERVICES' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.z3950.retrieve_services', 'secure' : false },
'MARK_ITEM_DAMAGED' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.mark_item_damaged' },
'MARK_ITEM_MISSING' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.mark_item_missing' },
'MARK_ITEM_LOST' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.circulation.set_lost' },
'MARK_ITEM_CLAIM_RETURNED' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.circulation.set_claims_returned' },
- 'MODS_SLIM_METARECORD_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.metarecord.mods_slim.retrieve' },
- 'MODS_SLIM_RECORD_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.record.mods_slim.retrieve' },
- 'MODS_SLIM_RECORD_RETRIEVE_VIA_COPY' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.mods_from_copy' },
+ 'MODS_SLIM_METARECORD_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.metarecord.mods_slim.retrieve', 'secure' : false },
+ 'MODS_SLIM_RECORD_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.record.mods_slim.retrieve', 'secure' : false },
+ 'MODS_SLIM_RECORD_RETRIEVE_VIA_COPY' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.mods_from_copy', 'secure' : false },
'PERM_CHECK' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.perm.check' },
'PERM_MULTI_ORG_CHECK' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.perm.check.multi_org' },
'MARC_XML_RECORD_CREATE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.xml.create' },
'MARC_XML_RECORD_IMPORT' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.xml.import' },
'MARC_XML_RECORD_REPLACE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.marc.replace' },
'MARC_XML_RECORD_UPDATE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.record.xml.update' },
+ 'MARC_XML_TEMPLATE_RETRIEVE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.marc_template.retrieve', 'secure' : false },
+ 'MARC_XML_TEMPLATE_LIST' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.marc_template.types.retrieve', 'secure' : false },
'MERGE_RECORDS' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.biblio.records.merge' },
'PATRON_BARCODE_EXISTS' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.barcode.exists' },
'RECALCULATE_STANDING_PENALTIES' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.user.penalties.update' },
function() {
var tcn = prompt('What is the TCN or accession ID for the record?','','TCN Lookup');
+ function spawn_tcn(r) {
+ for (var i = 0; i < r.count; i++) {
+ var id = r.ids[i];
+ var opac_url = obj.url_prefix( urls.opac_rdetail ) + '?r=' + id;
+ obj.data.stash_retrieve();
+ var content_params = {
+ 'session' : ses(),
+ 'authtime' : ses('authtime'),
+ 'opac_url' : opac_url,
+ };
+ if (i == 0) {
+ obj.set_tab(
+ obj.url_prefix(urls.XUL_OPAC_WRAPPER),
+ {'tab_name':tcn},
+ content_params
+ );
+ } else {
+ obj.new_tab(
+ obj.url_prefix(urls.XUL_OPAC_WRAPPER),
+ {'tab_name':tcn},
+ content_params
+ );
+ }
+ }
+ }
+
if (tcn) {
JSAN.use('util.network');
var network = new util.network();
var robj = network.simple_request('FM_BRE_ID_SEARCH_VIA_TCN',[tcn]);
if (robj.count != robj.ids.length) throw('FIXME -- FM_BRE_ID_SEARCH_VIA_TCN = ' + js2JSON(robj));
if (robj.count == 0) {
- alert('TCN not found');
- } else {
- for (var i = 0; i < robj.count; i++) {
- var id = robj.ids[i];
- var opac_url = obj.url_prefix( urls.opac_rdetail ) + '?r=' + id;
- obj.data.stash_retrieve();
- var content_params = {
- 'session' : ses(),
- 'authtime' : ses('authtime'),
- 'opac_url' : opac_url,
- };
- if (i == 0) {
- obj.set_tab(
- obj.url_prefix(urls.XUL_OPAC_WRAPPER),
- {'tab_name':tcn},
- content_params
- );
- } else {
- obj.new_tab(
- obj.url_prefix(urls.XUL_OPAC_WRAPPER),
- {'tab_name':tcn},
- content_params
- );
+ var robj2 = network.simple_request('FM_BRE_ID_SEARCH_VIA_TCN',[tcn,1]);
+ if (robj2.count == 0) {
+ alert('"' + tcn + '" not found');
+ } else {
+ if ( window.confirm('"' + tcn + '" is deleted. Show deleted record anyway?') ) {
+ spawn_tcn(robj2);
}
}
+ } else {
+ spawn_tcn(robj);
}
}
}
'yns_alert' : function (s,title,b1,b2,b3,c,image) {
+ try {
+
+ if (location.href.match(/^chrome/)) return this.yns_alert_original(s,title,b1,b2,b3,c);
+
/* The original purpose of yns_alert was to prevent errors from being scanned through accidentally with a barcode scanner.
However, this can be done in a less annoying manner by rolling our own dialog and not having any of the options in focus */
JSAN.use('OpenILS.data');
var data = new OpenILS.data(); data.init({'via':'stash'});
data.temp_yns_xml = xml; data.stash('temp_yns_xml');
+ var url = urls.XUL_FANCY_PROMPT + '?xml_in_stash=temp_yns_xml' + '&title=' + window.escape(title);
+ if (typeof xulG != 'undefined') if (typeof xulG.url_prefix == 'function') url = xulG.url_prefix( url );
window.open(
- urls.XUL_FANCY_PROMPT
- + '?xml_in_stash=temp_yns_xml'
- + '&title=' + window.escape(title),
- 'fancy_prompt', 'chrome,resizable,modal,width=700,height=500'
+ url, 'fancy_prompt', 'chrome,resizable,modal,width=700,height=500'
);
data.init({'via':'stash'});
if (data.fancy_prompt_data != '') {
//return this.yns_alert(s,title,b1,b2,b3,c,image);
return null;
}
+
+ } catch(E) {
+
+ dump('yns_alert failed: ' + E + '\ns = ' + s + '\ntitle = ' + title + '\nb1 = ' + b1 + '\nb2 = ' + b2 + '\nb3 = ' + b3 + '\nc = ' + c + '\nimage = ' + image + '\n');
+
+ this.yns_alert_original(s + '\n\nAlso, yns_alert failed: ' + E,title,b1,b2,b3,c);
+
+ }
},
'yns_alert_formatted' : function (s,title,b1,b2,b3,c,image) {
+ try {
+
+ if (location.href.match(/^chrome/)) return this.yns_alert_original(s,title,b1,b2,b3,c);
+
/* The original purpose of yns_alert was to prevent errors from being scanned through accidentally with a barcode scanner.
However, this can be done in a less annoying manner by rolling our own dialog and not having any of the options in focus */
JSAN.use('OpenILS.data');
var data = new OpenILS.data(); data.init({'via':'stash'});
data.temp_yns_xml = xml; data.stash('temp_yns_xml');
+ var url = urls.XUL_FANCY_PROMPT + '?xml_in_stash=temp_yns_xml' + '&title=' + window.escape(title);
+ if (typeof xulG != 'undefined') if (typeof xulG.url_prefix == 'function') url = xulG.url_prefix( url );
window.open(
- urls.XUL_FANCY_PROMPT
- + '?xml_in_stash=temp_yns_xml'
- + '&title=' + window.escape(title),
- 'fancy_prompt', 'chrome,resizable,modal,width=700,height=500'
+ url, 'fancy_prompt', 'chrome,resizable,modal,width=700,height=500'
);
data.init({'via':'stash'});
if (data.fancy_prompt_data != '') {
//return this.yns_alert(s,title,b1,b2,b3,c,image);
return null;
}
- },
+ } catch(E) {
+ alert('yns_alert_formatted failed: ' + E + '\ns = ' + s + '\ntitle = ' + title + '\nb1 = ' + b1 + '\nb2 = ' + b2 + '\nb3 = ' + b3 + '\nc = ' + c + '\nimage = ' + image + '\n');
+
+ }
+
+ },
'yns_alert_original' : function (s,title,b1,b2,b3,c) {
if (!fname) { fname = this.name; } else { this.name = fname; }
if (!fname) throw('Must specify a filename.');
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect UniversalPreferencesWrite UniversalBrowserWrite UniversalPreferencesRead UniversalBrowserRead UniversalFileRead");
+ var pref = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+ if (!path && pref.getBoolPref("open-ils.write_in_user_chrome_directory")) path = 'uchrome';
+ } catch(E) {
+ // getBoolPref throws an exception if "open-ils.write_in_user_chrome_directory" is not defined at all
+ // in defaults/preferences/prefs.js
+ }
+
switch(path) {
- case 'profile' :
- this._file = this.dirService.get( "UChrom", Components.interfaces.nsIFile );
+ case 'uchrome' :
+ this._file = this.dirService.get( "UChrm", Components.interfaces.nsIFile );
//this._file = this.dirService.get( "ProfD", Components.interfaces.nsIFile );
break;
- case 'chrome' :
default:
+ case 'chrome' :
this._file = this.dirService.get( "AChrom", Components.interfaces.nsIFile );
this._file.append(myPackageDir);
this._file.append("content");
return this._file;
} catch(E) {
- this.error.sdump('D_ERROR',this._file.path + '\nutil.file.get(): ' + E);
+ this.error.standard_unexpected_error_alert('error in util.file.get('+fname+','+path+')',E);
throw(E);
}
},
var treeitem = document.createElement('treeitem');
treeitem.setAttribute('retrieve_id',params.retrieve_id);
- if (typeof params.to_top == 'undefined') {
+ if (typeof params.to_bottom != 'undefined') {
treechildren_node.appendChild( treeitem );
+ if (typeof params.no_auto_select == 'undefined') {
+ try { obj.node.view.selection.select(Number(obj.node.view.rowCount)-1); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
+ }
} else {
if (treechildren_node.firstChild) {
treechildren_node.insertBefore( treeitem, treechildren_node.firstChild );
} else {
treechildren_node.appendChild( treeitem );
}
+ if (typeof params.no_auto_select == 'undefined') {
+ try { obj.node.view.selection.select(0); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
+ }
}
var treerow = document.createElement('treerow');
treeitem.appendChild( treerow );
if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
// Remove oldest row
+ //if (typeof params.to_bottom != 'undefined') {
if (typeof params.to_top == 'undefined') {
treechildren_node.removeChild( treechildren_node.firstChild );
} else {
'NETWORK_FAILURE' : null,
'simple_request' : function(id,params,f,o_params) {
- return this.request(api[id].app,api[id].method,params,f,o_params);
+ var secure = true; if (typeof api[id].secure != 'undefined') secure = api[id].secure;
+ return this.request(api[id].app,api[id].method,params,f,o_params,secure);
},
'get_result' : function (req) {
return result;
},
- 'request' : function (app,name,params,f,o_params) {
- var request = this._request(app,name,params,f,o_params);
+ 'request' : function (app,name,params,f,o_params,secure) {
+ var request = this._request(app,name,params,f,o_params,secure);
if (request) {
return this.get_result(request);
} else {
}
},
- '_request' : function (app,name,params,f,o_params) {
+ '_request' : function (app,name,params,f,o_params,secure) {
var obj = this;
try {
var sparams = js2JSON(params);
obj.error.sdump('D_SES','request '+app+' '+name+' '+obj.error.pretty_print(sparams.slice(1,sparams.length-1))+
- '\no_params = ' + o_params +
+ '\no_params = ' + o_params + '\nsecure = ' + secure +
'\nResult #' + (++obj.link_id) + ( f ? ' asynced' : ' synced' ) );
var request = new RemoteRequest( app, name );
+ if (secure) {
+ request.setSecure(true);
+ } else {
+ request.setSecure(false);
+ }
for(var index in params) {
request.addParam(params[index]);
}
+ (json_string.length > 80 ? obj.error.pretty_print(json_string) : json_string)
+ '\n\nOriginal Request:\n\n'
+ 'request '+app+' '+name+' '+ sparams.slice(1,sparams.length-1));
- req = obj.rerequest_on_session_timeout(app,name,params,req,o_params);
- req = obj.rerequest_on_perm_failure(app,name,params,req,o_params);
+ req = obj.rerequest_on_session_timeout(app,name,params,req,o_params,secure);
+ req = obj.rerequest_on_perm_failure(app,name,params,req,o_params,secure);
if (o_params) {
- req = obj.rerequest_on_override(app,name,params,req,o_params);
+ req = obj.rerequest_on_override(app,name,params,req,o_params,secure);
}
- req = obj.check_for_offline(app,name,params,req,o_params);
+ req = obj.check_for_offline(app,name,params,req,o_params,secure);
f(req);
obj.NETWORK_FAILURE = null;
} catch(E) {
+ obj.link_id + '\n\n' + ( json_string.length > 80 ? obj.error.pretty_print(json_string) : json_string )
+ '\n\nOriginal Request:\n\n'
+ 'request '+app+' '+name+' '+ sparams.slice(1,sparams.length-1));
- request = obj.rerequest_on_session_timeout(app,name,params,request,o_params);
- request = obj.rerequest_on_perm_failure(app,name,params,request,o_params);
+ request = obj.rerequest_on_session_timeout(app,name,params,request,o_params,secure);
+ request = obj.rerequest_on_perm_failure(app,name,params,request,o_params,secure);
if (o_params) {
- request = obj.rerequest_on_override(app,name,params,request,o_params);
+ request = obj.rerequest_on_override(app,name,params,request,o_params,secure);
}
- request = obj.check_for_offline(app,name,params,request,o_params);
+ request = obj.check_for_offline(app,name,params,request,o_params,secure);
obj.NETWORK_FAILURE = null;
return request;
}
}
},
- 'check_for_offline' : function (app,name,params,req,o_params) {
+ 'check_for_offline' : function (app,name,params,req,o_params,secure) {
var obj = this;
var result = obj.get_result(req);
if (result != null) return req;
switch(r) {
case 0:
- req = obj._request(app,name,params,null,o_params);
+ req = obj._request(app,name,params,null,o_params,secure);
if (obj.get_result(req)) proceed = true; /* daily WTF, why am I even doing this? :) */
return req;
break;
}
},
- 'rerequest_on_session_timeout' : function(app,name,params,req,o_params) {
+ 'rerequest_on_session_timeout' : function(app,name,params,req,o_params,secure) {
try {
var obj = this;
var robj = obj.get_result(req);
if (obj.get_new_session(name,undefined,true)) {
JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
params[0] = data.session.key;
- req = obj._request(app,name,params,null,o_params);
+ req = obj._request(app,name,params,null,o_params,secure);
}
}
} catch(E) {
return req;
},
- 'rerequest_on_perm_failure' : function(app,name,params,req,o_params) {
+ 'rerequest_on_perm_failure' : function(app,name,params,req,o_params,secure) {
try {
var obj = this;
var robj = obj.get_result(req);
var data = new OpenILS.data(); data.init({'via':'stash'});
if (typeof data.temporary_session != 'undefined' && data.temporary_session != '') {
params[0] = data.temporary_session.key;
- req = obj._request(app,name,params,null,o_params);
+ req = obj._request(app,name,params,null,o_params,secure);
}
}
}
return req;
},
- 'rerequest_on_override' : function (app,name,params,req,o_params) {
+ 'rerequest_on_override' : function (app,name,params,req,o_params,secure) {
var obj = this;
try {
if (!o_params.text) o_params.text = {};
JSAN.use('OpenILS.data'); this.data = new OpenILS.data(); this.data.init( { 'via':'stash' } );
JSAN.use('util.window'); this.win = new util.window();
JSAN.use('util.functional');
+ JSAN.use('util.file');
return this;
};
}
var w;
+
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ obj.data.init({'via':'stash'});
+
+ if (params.print_strategy || obj.data.print_strategy) {
+
+ switch(params.print_strategy || obj.data.print_strategy) {
+ case 'dos.print':
+ /* FIXME - this it a kludge.. we're going to sidestep window-based html rendering for printing */
+ /* I'm using regexps to mangle the html receipt templates; it'd be nice to use xsl but the */
+ /* templates aren't guaranteed to be valid xml */
+ if (content_type=='text/html') {
+ w = msg.replace(/<br.*?>/gi,'\r\n').replace(/<table.*?>/gi,'\r\n').replace(/<tr.*?>/gi,'\r\n').replace(/<hr.*?>/gi,'\r\n').replace(/<p.*?>/gi,'\r\n').replace(/<block.*?>/gi,'\r\n').replace(/<li.*?>/gi,'\r\n * ').replace(/<.+?>/gi,'');
+ } else {
+ w = msg;
+ }
+ if (! params.no_form_feed) { w = w + '\r\n\r\n\r\n\r\n\r\n\r\n\f'; }
+ obj.NSPrint(w, silent, params);
+ return;
+ break;
+ }
+ }
+
switch(content_type) {
case 'text/html' :
- var jsrc = 'data:text/javascript,' + window.escape('var params = { "data" : ' + js2JSON(params.data) + ', "list" : ' + js2JSON(params.list) + '}; function my_init() { if (typeof go_print == "function") { go_print(); } else { alert("Please inform the developers that the go_print bug occurred. After this alert, we will try to print again."); window.print(); } /* FIXME - mozilla bug#301560 - xpcom kills it too */ if (' + (typeof params.modal != 'undefined' ? 'true' : 'false') + ') setTimeout(function(){ try { window.print(); window.close(); } catch(E) { alert(E); } },0); }');
+ var jsrc = 'data:text/javascript,' + window.escape('var params = { "data" : ' + js2JSON(params.data) + ', "list" : ' + js2JSON(params.list) + '}; function my_init() { if (typeof go_print == "function") { go_print(); } else { setTimeout( function() { if (typeof go_print == "function") { alert("Please tell the developers that the 2-second go_print workaround executed, and let them know whether this job printed successfully. Thanks!"); go_print(); } else { alert("Please tell the developers that the 2-second go_print workaround did not work. We will try to print one more time; there have been reports of wasted receipt paper at this point. Please check the settings in the print dialog and/or prepare to power off your printer. Thanks!"); window.print(); } }, 2000 ); } /* FIXME - mozilla bug#301560 - xpcom kills it too */ }');
w = obj.win.open('data:text/html,<html id="top"><head><script src="/xul/server/main/JSAN.js"></script><script src="' + window.escape(jsrc) + '"></script></head><body onload="try{my_init();}catch(E){alert(E);}">' + window.escape(msg) + '</body></html>','receipt_temp','chrome,resizable');
w.minimize();
w.go_print = function() {
-
- //setTimeout(
- // function() {
- try {
- obj.NSPrint(w, silent, params);
- } catch(E) {
- obj.error.standard_unexpected_error_alert("Print Error in util.print.simple. After this dialog we'll try a second print attempt. content_type = " + content_type,E);
- w.print();
- }
- w.minimize(); w.close();
- // }, 0
- //);
-
+ try {
+ obj.NSPrint(w, silent, params);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert("Print Error in util.print.simple. After this dialog we'll try a second print attempt. content_type = " + content_type,E);
+ w.print();
+ }
+ w.minimize(); w.close();
}
break;
default:
dump(E+'\n');
}
var cols = [];
- // FIXME -- This could be done better.. instead of finding the columns and handling a tree dump,
- // we could do a dump_with_keys instead
- /*
- switch(params.type) {
- case 'offline_checkout' :
- JSAN.use('circ.util');
- cols = util.functional.map_list(
- circ.util.offline_checkout_columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
-
- break;
- case 'offline_checkin' :
- JSAN.use('circ.util');
- cols = util.functional.map_list(
- circ.util.offline_checkin_columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
-
- break;
- case 'offline_renew' :
- JSAN.use('circ.util');
- cols = util.functional.map_list(
- circ.util.offline_renew_columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
- break;
- case 'offline_inhouse_use' :
- JSAN.use('circ.util');
- cols = util.functional.map_list(
- circ.util.offline_inhouse_use_columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
- break;
- case 'items':
- JSAN.use('circ.util');
- cols = util.functional.map_list(
- circ.util.columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
- break;
- case 'bills':
- JSAN.use('patron.util');
- cols = util.functional.map_list(
- patron.util.mbts_columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
- break;
- case 'payment':
- //cols = [ '%bill_id%','%payment%'];
- cols = [];
- break;
- case 'transits':
- cols = [];
- break;
- case 'holds':
- JSAN.use('circ.util');
- cols = util.functional.map_list(
- circ.util.hold_columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
- break;
- case 'patrons':
- JSAN.use('patron.util');
- cols = util.functional.map_list(
- patron.util.columns( {} ),
- function(o) {
- return '%' + o.id + '%';
- }
- );
- break;
- }
- */
- var s = this.template_sub( params.header, cols, params );
- for (var i = 0; i < params.list.length; i++) {
- params.row = params.list[i];
- s += this.template_sub( params.line_item, cols, params );
+ var s = '';
+ if (params.header) s += this.template_sub( params.header, cols, params );
+ if (params.list) {
+ for (var i = 0; i < params.list.length; i++) {
+ params.row = params.list[i];
+ params.row_idx = i;
+ s += this.template_sub( params.line_item, cols, params );
+ }
}
- s += this.template_sub( params.footer, cols, params );
+ if (params.footer) s += this.template_sub( params.footer, cols, params );
if (params.sample_frame) {
var jsrc = 'data:text/javascript,' + window.escape('var params = { "data" : ' + js2JSON(params.data) + ', "list" : ' + js2JSON(params.list) + '};');
JSAN.use('util.date');
var s = msg; var b;
+ try{b = s; s = s.replace(/%LINE_NO%/,Number(params.row_idx)+1);}
+ catch(E){s = b; this.error.sdump('D_WARN','string = <' + s + '> error = ' + js2JSON(E)+'\n');}
+
try{b = s; s = s.replace(/%patron_barcode%/,params.patron_barcode);}
catch(E){s = b; this.error.sdump('D_WARN','string = <' + s + '> error = ' + js2JSON(E)+'\n');}
catch(E){s = b; this.error.sdump('D_WARN','string = <' + s + '> error = ' + js2JSON(E)+'\n');}
try{b = s; s = s.replace(/%STAFF_BARCODE%/,params.staff.barcode); }
catch(E){s = b; this.error.sdump('D_WARN','string = <' + s + '> error = ' + js2JSON(E)+'\n');}
+ try{b = s; s = s.replace(/%STAFF_PROFILE%/,obj.data.hash.pgt[ params.staff.profile() ].name() ); }
+ catch(E){s = b; this.error.sdump('D_WARN','string = <' + s + '> error = ' + js2JSON(E)+'\n');}
try{b = s; s = s.replace(/%PATRON_FIRSTNAME%/,params.patron.first_given_name());}
catch(E){s = b; this.error.sdump('D_WARN','string = <' + s + '> error = ' + js2JSON(E)+'\n');}
try{b = s; s = s.replace(/%PATRON_LASTNAME%/,params.patron.family_name());}
try {
if (typeof params.row != 'undefined') {
if (params.row.length >= 0) {
- alert('debug pause');
+ alert('debug - please tell the developers that deprecated template code tried to execute');
for (var i = 0; i < cols.length; i++) {
var re = new RegExp(cols[i],"g");
try{b = s; s=s.replace(re, params.row[i]);}
if (!w) w = window;
var obj = this;
try {
+ if (!params) params = {};
+
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ obj.data.init({'via':'stash'});
- if (obj.data.print_strategy) {
+ if (params.print_strategy || obj.data.print_strategy) {
- switch(obj.data.print_strategy) {
+ switch(params.print_strategy || obj.data.print_strategy) {
case 'dos.print':
obj._NSPrint_dos_print(w,silent,params);
break;
}
} catch (e) {
- //alert('Probably not printing: ' + e);
+ alert('Probably not printing: ' + e);
this.error.sdump('D_ERROR','PRINT EXCEPTION: ' + js2JSON(e) + '\n');
}
'_NSPrint_dos_print' : function(w,silent,params) {
var obj = this;
try {
- /* This is a kludge/workaround. webBrowserPrint doesn't always work. So we're going to let
+
+ /* OLD way: This is a kludge/workaround. webBrowserPrint doesn't always work. So we're going to let
the html window handle our receipt template rendering, and then force a selection of all
the text nodes and dump that to a file, for printing through a dos utility */
+ /*
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
w.getSelection().selectAllChildren(w.document.firstChild);
var text = w.getSelection().toString();
+ */
+
+ /* NEW way: we just pass in the text */
- JSAN.use('util.file'); var file = new util.file('receipt.txt');
+ var text = w;
+
+ var file = new util.file('receipt.txt');
file.write_content('truncate',text); file.close();
file = new util.file('receipt.bat');
} catch (e) {
//alert('Probably not printing: ' + e);
- this.error.sdump('D_ERROR','PRINT EXCEPTION: ' + js2JSON(e) + '\n');
+ this.error.sdump('D_ERROR','_NSPrint_dos_print PRINT EXCEPTION: ' + js2JSON(e) + '\n');
}
},
// Pressing cancel is expressed as an NS_ERROR_ABORT return value,
// causing an exception to be thrown which we catch here.
// Unfortunately this will also consume helpful failures
- this.error.sdump('D_ERROR','PRINT EXCEPTION: ' + js2JSON(e) + '\n');
+ this.error.sdump('D_ERROR','_NSPrint_webBrowserPrint PRINT EXCEPTION: ' + js2JSON(e) + '\n');
}
},
'load_settings' : function() {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
- JSAN.use('util.file'); var file = new util.file('gPrintSettings');
+ var file = new util.file('gPrintSettings');
if (file._file.exists()) {
temp = file.get_object(); file.close();
for (var i in temp) {
'save_settings' : function() {
try {
+ var obj = this;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
- JSAN.use('util.file'); var file = new util.file('gPrintSettings');
- file.set_object(this.gPrintSettings); file.close();
+ var file = new util.file('gPrintSettings');
+ if (typeof obj.gPrintSettings == 'undefined') obj.GetPrintSettings();
+ if (obj.gPrintSettings) file.set_object(obj.gPrintSettings);
+ file.close();
} catch(E) {
this.error.standard_unexpected_error_alert("save_settings()",E);
}
<script type="text/javascript" src="/xul/server/main/JSAN.js"/>
<script>
<![CDATA[
+
function my_init() {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var url; try { url = g.cgi.param('url') || xulG.url } catch(E) { dump(E + '\n'); };
if (!url) url = urls.browser;
- JSAN.use('util.browser'); g.browser = new util.browser();
+ if (!g.browser) {
+ JSAN.use('util.browser'); g.browser = new util.browser();
+ }
var push_xulG = true;
if (g.cgi.param('no_xulG') || (typeof xulG == 'object' ? xulG.no_xulG : false)) push_xulG = false;
<button id="back" label="Go Back" command="cmd_back" accesskey="b" disabled="true" hidden="true"/>
<button id="forward" label="Go Forward" command="cmd_forward" accesskey="d" disabled="true" hidden="true"/>
<spacer flex="1"/>
- <button id="browser_print" label="Print Page" command="cmd_print" hidden="true"/>
+ <button id="browser_print" label="Print Page" oldcommand="cmd_print" hidden="true"
+ oncommand="netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); if (g.browser.alt_print) { JSAN.use('util.print'); var p = new util.print(); p.NSPrint(g.browser.get_content(),false,{}); } else { g.browser.get_content().print(); }"
+ />
+
</hbox>
<browser id="browser_browser" flex="1" type="content"/>
</vbox>
// This one is required for XUL Runner
pref("toolkit.defaultChromeURI", "chrome://open_ils_staff_client/content/main/main.xul");
+// This one is specific for Open-ILS
+pref("open-ils.write_in_user_chrome_directory", true);
+
// This one just makes things speedier. We use a lot of XMLHttpRequest
pref("network.http.max-persistent-connections-per-server",8);
pref("nglayout.debug.disable_xul_fastload",true);
pref("browser.xul.error_pages.enabled",true);
+pref("browser.download.useDownloadDir", true);
+pref("browser.download.folderList", 0);
+pref("browser.download.manager.showAlertOnComplete", true);
+pref("browser.download.manager.showAlertInterval", 2000);
+pref("browser.download.manager.retention", 2);
+pref("browser.download.manager.showWhenStarting", true);
+pref("browser.download.manager.useWindow", true);
+pref("browser.download.manager.closeWhenDone", false);
+pref("browser.download.manager.openDelay", 0);
+pref("browser.download.manager.focusWhenStarting", false);
+pref("browser.download.manager.flashCount", 2);
+
}
-function cdDrawRange( start, end ) {
+function cdDrawRange( start, end, alertSuccess ) {
start = (start) ? start : new Date().getYear() + 1900 + '-01-01';
end = (end) ? end : '3001-01-01';
+ if(alertSuccess) alertId('cd_update_success');
+
selectedStart = start;
selectedEnd = end;
function(r) {
var res = r.getResultObject();
if( checkILSEvent(res) ) alertILSEvent(res);
- cdDrawRange(selectedStart, selectedEnd);
+ cdDrawRange(selectedStart, selectedEnd, true);
}
)
req.send();
var data = str.split(/ /);
var year = data[0];
- var time = data[1];
+ var time = data[1];
if(!cdVerifyDate(year)) return alertId('cd_invalid_date');
if(!cdVerifyTime(time)) return alertId('cd_invalid_time');
var yeardata = year.split(/-/);
var timedata = time.split(/:/);
+
+ /* seed the date with day = 1, which is a valid day for any month.
+ this prevents automatic date correction by the date code for days that
+ fall outside of the current or target month */
+ date.setDate(1);
- date.setFullYear(yeardata[0]);
- date.setMonth(yeardata[1] - 1);
- date.setDate(yeardata[2]);
+ date.setFullYear(new Number(yeardata[0]));
+ date.setMonth(new Number(yeardata[1]) - 1);
+ date.setDate(new Number(yeardata[2]));
- date.setHours(timedata[0]);
- date.setMinutes(timedata[1]);
- date.setSeconds(timedata[2]);
+ date.setHours(new Number(timedata[0]));
+ date.setMinutes(new Number(timedata[1]));
+ date.setSeconds(new Number(timedata[2]));
return date;
}
if( ! $('cd_edit_allday_row').className.match(/hide_me/) ) {
var date = $('cd_edit_allday_start_date').value;
+
start = cdDateStrToDate(date + ' 00:00:00');
end = cdDateStrToDate(date + ' 23:59:59');
function(r) {
var res = r.getResultObject();
if( checkILSEvent(res) ) alertILSEvent(res);
- if(refresh) cdDrawRange(selectedStart, selectedEnd);
+ if(refresh) cdDrawRange(selectedStart, selectedEnd, true);
}
);
req.send();
<span class='hide_me' id='cd_confirm_delete'>Are you sure you wish to delete the selected close date?</span>
<span class='hide_me' id='cd_invalid_date'>Invalid date format</span>
<span class='hide_me' id='cd_invalid_time'>Invalid time format</span>
+ <span class='hide_me' id='cd_update_success'>Closed date successfully updated</span>
</center>
</body>
$n(row, 'copy_number').appendChild(text(copy.copy_number()));
try {
if (copy.age_protect()) {
- $n(row, 'age_protect').appendChild(text( (copy.age_protect() == null ? '<Unset>' : ( typeof copy.age_protect() == 'object' ? copy.age_protect().name() : g.data.hash.crahp[ copy.age_protect() ].name() )) ));
+ $n(row, 'age_protect').appendChild(text( (copy.age_protect() == null ? '<Unset>' : ( typeof copy.age_protect() == 'object' ? copy.age_protect().name() : g.data.hash.crahp[ copy.age_protect() ].name() )) + ' (' + copy.create_date().substr(0,10) + ')' ));
unHideMe($n(row, 'age_protect_span'));
}
} catch(E) { alert(E); }
}
} );
+ var export_button = document.getElementById('export_btn');
+ if (export_button) export_button.addEventListener(
+ 'command',
+ function(ev) {
+ try {
+ obj.error_list.on_all_fleshed =
+ function() {
+ try {
+ dump( obj.error_list.dump_csv() + '\n' );
+ copy_to_clipboard(obj.error_list.dump_csv());
+ setTimeout(function(){ obj.error_list.on_all_fleshed = null; },0);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('export',E);
+ }
+ }
+ obj.error_list.full_retrieve();
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('export',E);
+ }
+ },
+ false
+ );
+
+ var print_export_button = document.getElementById('print_export_btn');
+ if (print_export_button) print_export_button.addEventListener(
+ 'command',
+ function(ev) {
+ try {
+ obj.error_list.on_all_fleshed =
+ function() {
+ try {
+ dump( obj.error_list.dump_csv() + '\n' );
+ //copy_to_clipboard(obj.error_list.dump_csv());
+ JSAN.use('util.print'); var p = new util.print();
+ p.simple( obj.error_list.dump_csv(), { 'content_type' : 'text/plain' } );
+ setTimeout(function(){ obj.error_list.on_all_fleshed = null; },0);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('export',E);
+ }
+ }
+ obj.error_list.full_retrieve();
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ },
+ false
+ );
},
</description>
<vbox flex="1">
<hbox>
+ <button id='export_btn' label="Export List" />
+ <button id='print_export_btn' label="Print Export" />
<spacer flex="1"/>
<button id='retrieve_item' label="Retrieve Item" disabled="true"/>
<button id='retrieve_patron' label="Retrieve Patron" disabled="true"/>
var ORG_SETTINGS = {
'circ.lost_materials_processing_fee' : null,
'cat.default_item_price' : null,
-// 'circ.collections_fee' : null,
'auth.opac_timeout' : null,
'auth.staff_timeout' : null,
+ 'org.bounced_emails' : null,
};
function osEditorInit() {
<td><button id='cat.default_item_price.apply'>Apply</button></td>
<td><button id='cat.default_item_price.apply_all'>Apply to all Locations</button></td>
</tr>
- <!--
<tr>
- <td>Collections Fee</td>
- <td>$<input ismoney='1' type='text' id='circ.collections_fee' size='5'/></td>
- <td><button id='circ.collections_fee.apply'>Apply</button></td>
- <td><button id='circ.collections_fee.apply_all'>Apply to all Locations</button></td>
+ <td>"FROM" email address for patron notices<br/>(note: delivery failures will be returned this address)</td>
+ <td><input type='text' id='org.bounced_emails' size='25'/></td>
+ <td><button id='org.bounced_emails.apply'>Apply</button></td>
+ <td><button id='org.bounced_emails.apply_all'>Apply to all Locations</button></td>
</tr>
- -->
</tbody>
</table>
<br/>
g.printer_settings = function() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var w = document.getElementById('sample').contentWindow;
- g.print.NSPrint(w ? w : window);
+ g.print.NSPrint(w ? w : window, false, {});
g.print.save_settings();
}
cat.entries().sort( /* sort the entries by value */
function( a, b ) {
- if( a.value().toLowerCase() > b.value().toLowerCase()) return 1;
- if( a.value().toLowerCase() < b.value().toLowerCase()) return -1;
+ a = new String(a.value()).toLowerCase();
+ b = new String(b.value()).toLowerCase();
+ if( a > b ) return 1;
+ if( a < b ) return -1;
return 0;
}
);
var meta = req.getResultObject();
if (typeof meta.ilsevent != 'undefined') throw(meta);
meta = meta[0];
+ document.getElementById('tcn_source').appendChild(
+ document.createTextNode(meta.tcn_source())
+ );
+ g.network.simple_request('FM_AU_FLESHED_RETRIEVE_VIA_ID',[ses(),meta.creator().id()],
+ function(rreq) {
+ var creator_au = rreq.getResultObject();
+ document.getElementById('creator_bc').appendChild(
+ document.createTextNode(creator_au.card().barcode())
+ );
+ }
+ );
+ g.network.simple_request('FM_AU_FLESHED_RETRIEVE_VIA_ID',[ses(),meta.editor().id()],
+ function(rreq) {
+ var editor_au = rreq.getResultObject();
+ document.getElementById('editor_bc').appendChild(
+ document.createTextNode(editor_au.card().barcode())
+ );
+ }
+ );
document.getElementById('creator').appendChild(
- document.createTextNode(meta.creator().usrname())
+ document.createTextNode('('+data.hash.aou[meta.creator().home_ou()].shortname()+') ')
);
+ document.getElementById('creator_bc').setAttribute('au_id',meta.creator().id());
document.getElementById('editor').appendChild(
- document.createTextNode(meta.editor().usrname())
+ document.createTextNode('('+data.hash.aou[meta.editor().home_ou()].shortname()+') ')
);
+ document.getElementById('editor_bc').setAttribute('au_id',meta.editor().id());
document.getElementById('edit_date').appendChild(
document.createTextNode(
util.date.formatted_date(meta.edit_date(),"%D")
}
}
+ function spawn_patron(span) {
+ try {
+ var loc = urls.XUL_PATRON_DISPLAY; // + '?barcode=' + window.escape(barcode);
+
+ if (typeof window.xulG == 'object' && typeof window.xulG.set_tab == 'function') {
+ window.xulG.set_tab( loc, {}, { 'id' : span.getAttribute('au_id') } );
+ } else {
+ copy_to_clipboard( span.textContent );
+ }
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('spawning patron display',E);
+ }
+ }
+
]]>
</script>
</html:tr>
<html:tr valign="top">
<html:td>
- <html:span style="font-weight: bold;">TCN: </html:span><html:span id="tcn" style="text-decoration: underline; color: blue;" onclick="copy_to_clipboard(event)"/>
+ <html:span style="font-weight: bold;">TCN: (</html:span><html:span id="tcn_source"/><html:span style="font-weight: bold;">) </html:span><html:span id="tcn" style="text-decoration: underline; color: blue;" onclick="copy_to_clipboard(event)"/>
</html:td>
<html:td>
<html:span style="font-weight: bold;">Created By: </html:span><html:span id="creator" />
+ <html:span id="creator_bc" style="text-decoration: underline; color: blue;" onclick="try{spawn_patron(this);}catch(E){alert(E);}"/>
</html:td>
<html:td>
<html:span style="font-weight: bold;">Last Edited By: </html:span><html:span id="editor" />
+ <html:span id="editor_bc" style="text-decoration: underline; color: blue;" onclick="try{spawn_patron(this);}catch(E){alert(E);}"/>
</html:td>
<html:td>
<html:span style="font-weight: bold;">Last Edited On: </html:span><html:span id="edit_date" />
},
'skip_all_columns_except' : [0,1,2],
'retrieve_id' : 'aou_' + org.id(),
+ 'to_bottom' : true,
};
var acn_tree_list;
'skip_all_columns_except' : [0,1,2],
'retrieve_id' : 'acn_' + acn_tree.id(),
'node' : parent_node,
+ 'to_bottom' : true,
};
var node = obj.list.append(data);
obj.map_tree[ 'acn_' + acn_tree.id() ] = node;
},
'retrieve_id' : 'acp_' + acp_item.id(),
'node' : parent_node,
+ 'to_bottom' : true,
};
var node = obj.list.append(data);
obj.map_tree[ 'acp_' + acp_item.id() ] = node;
try {
JSAN.use('util.functional');
var sel = obj.list1.retrieve_selection();
+ document.getElementById('clip_button1').disabled = sel.length < 1;
obj.selection_list1 = util.functional.map_list(
sel,
function(o) { return JSON2js(o.getAttribute('retrieve_id')); }
try {
JSAN.use('util.functional');
var sel = obj.list2.retrieve_selection();
- document.getElementById('clip_button').disabled = sel.length < 1;
+ document.getElementById('clip_button2').disabled = sel.length < 1;
obj.selection_list2 = util.functional.map_list(
sel,
function(o) { return JSON2js(o.getAttribute('retrieve_id')); }
obj.controller.init(
{
'control_map' : {
- 'sel_clip' : [
+ 'save_columns2' : [
+ ['command'],
+ function() { obj.list2.save_columns(); }
+ ],
+ 'save_columns1' : [
+ ['command'],
+ function() { obj.list1.save_columns(); }
+ ],
+ 'sel_clip2' : [
['command'],
function() { obj.list2.clipboard(); }
],
+ 'sel_clip1' : [
+ ['command'],
+ function() { obj.list1.clipboard(); }
+ ],
'copy_buckets_menulist_placeholder' : [
['render'],
function(e) {
obj.list2.full_retrieve();
}
],
+ 'cmd_export1' : [
+ ['command'],
+ function() {
+ obj.list1.on_all_fleshed = function() {
+ try {
+ dump(obj.list1.dump_csv() + '\n');
+ copy_to_clipboard(obj.list1.dump_csv());
+ setTimeout(function(){obj.list1.on_all_fleshed = null;},0);
+ } catch(E) {
+ alert(E);
+ }
+ }
+ obj.list1.full_retrieve();
+ }
+ ],
+
+ 'cmd_print_export1' : [
+ ['command'],
+ function() {
+ try {
+ obj.list1.on_all_fleshed =
+ function() {
+ try {
+ dump( obj.list1.dump_csv() + '\n' );
+ //copy_to_clipboard(obj.list.dump_csv());
+ JSAN.use('util.print'); var print = new util.print();
+ print.simple(obj.list1.dump_csv(),{'content_type':'text/plain'});
+ setTimeout(function(){ obj.list1.on_all_fleshed = null; },0);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ obj.list1.full_retrieve();
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ ],
+
+
+ 'cmd_print_export2' : [
+ ['command'],
+ function() {
+ try {
+ obj.list2.on_all_fleshed =
+ function() {
+ try {
+ dump( obj.list2.dump_csv() + '\n' );
+ //copy_to_clipboard(obj.list.dump_csv());
+ JSAN.use('util.print'); var print = new util.print();
+ print.simple(obj.list2.dump_csv(),{'content_type':'text/plain'});
+ setTimeout(function(){ obj.list2.on_all_fleshed = null; },0);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ obj.list2.full_retrieve();
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ ],
'cmd_copy_buckets_reprint' : [
['command'],
</script>
<commandset id="copy_buckets_cmds">
- <command id="sel_clip" />
+ <command id="sel_clip1" />
+ <command id="save_columns1" />
+ <command id="sel_clip2" />
+ <command id="save_columns2" />
+ <command id="cmd_print_export1" />
+ <command id="cmd_export1" />
+ <command id="cmd_print_export2" />
<command id="cmd_copy_buckets_submit_barcode" />
<command id="cmd_copy_buckets_print" />
<command id="cmd_copy_buckets_export" />
</vbox>
<hbox id="pending_buckets_bottom_ui">
+ <button id="save_button1" command="save_columns1" label="Save Columns" />
+ <button id="clip_button1" command="sel_clip1" label="Copy to Clipboard" disabled="true" />
+ <button id="cmd_print_export_btn1" command="cmd_print_export1" label="Print Export" />
+ <button id="cmd_export_btn1" command="cmd_export1" label="Export" />
<spacer flex="1"/>
<button label="Add All" command="copy_buckets_add" accesskey="A" image="/xul/server/skin/media/images/down_arrow.gif"/>
<button label="Add Selected" command="copy_buckets_sel_add" accesskey="" image="/xul/server/skin/media/images/down_arrow.gif"/>
<button command="copy_buckets_delete_bucket" label="Delete Bucket"/>
<button id="refresh" label="Refresh"/>
<spacer flex="1"/>
- <button id="clip_button" command="sel_clip" label="Copy to Clipboard" disabled="true" />
+ <button id="save_button2" command="save_columns2" label="Save Columns" />
+ <button id="clip_button2" command="sel_clip2" label="Copy to Clipboard" disabled="true" />
<button command="copy_buckets_delete_item" label="Delete Selected" disabled="true" image="/xul/server/skin/media/images/icon_delete.gif"/>
<button command="copy_buckets_export" label="Add Selected" disabled="true" image="/xul/server/skin/media/images/up_arrow.gif"/>
</hbox>
<hbox id="copy_buckets_bottom_ui">
<button id="copy_buckets_print" label="Print" command="cmd_copy_buckets_print" accesskey="P"/>
+ <button id="cmd_print_export_btn2" command="cmd_print_export2" label="Print Export" />
<button id="copy_buckets_export"
label="Export"
command="cmd_copy_buckets_export"
}
/******************************************************************************************************/
+/* File picker for template export/import */
+
+function pick_file(mode) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var nsIFilePicker = Components.interfaces.nsIFilePicker;
+ var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance( nsIFilePicker );
+ fp.init(
+ window,
+ mode == 'open' ? "Import Templates File" : "Save Templates File As",
+ mode == 'open' ? nsIFilePicker.modeOpen : nsIFilePicker.modeSave
+ );
+ fp.appendFilters( nsIFilePicker.filterAll );
+ if ( fp.show( ) == nsIFilePicker.returnOK && fp.file ) {
+ return fp.file;
+ } else {
+ return null;
+ }
+}
+
+/******************************************************************************************************/
/* Retrieve Templates */
g.retrieve_templates = function() {
}
/******************************************************************************************************/
+/* Export Templates */
+
+g.export_templates = function() {
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ JSAN.use('util.file');
+ var f = pick_file('save');
+ if (f) {
+ if (f.exists()) {
+ var r = G.error.yns_alert(
+ 'Would you like to overwrite the existing file ' + f.leafName + '?',
+ 'Templates Export Warning',
+ 'Yes',
+ 'No',
+ null,
+ 'Check here to confirm this message'
+ );
+ if (r != 0) { file.close(); alert('Not overwriting file.'); return; }
+ }
+ var e_file = new util.file(''); e_file._file = f;
+ e_file.write_content( 'truncate', js2JSON( g.templates ) );
+ e_file.close();
+ alert('Templates exported as file ' + f.leafName);
+ } else {
+ alert('File not chosen for export.');
+ }
+
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('Error exporting templates',E);
+ }
+}
+
+/******************************************************************************************************/
+/* Import Templates */
+
+g.import_templates = function() {
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ JSAN.use('util.file');
+ var f = pick_file('open');
+ if (f && f.exists()) {
+ var i_file = new util.file(''); i_file._file = f;
+ var temp = JSON2js( i_file.get_content() );
+ i_file.close();
+ for (var i in temp) {
+
+ if (g.templates[i]) {
+
+ var r = g.error.yns_alert(
+ 'Replace the existing template with the imported template?\n' + g.error.pretty_print( js2JSON( temp[i] ) ),
+ 'Template ' + i + ' already exists.','Yes','No',null,'Click here'
+ );
+
+ if (r == 0 /* Yes */) g.templates[i] = temp[i];
+
+ } else {
+
+ g.templates[i] = temp[i];
+
+ }
+
+ }
+
+ var r = g.error.yns_alert(
+ 'Save all of these imported templates permanently to this account?',
+ 'Final Warning', 'Yes', 'No', null, 'Click here'
+ );
+
+ if (r == 0 /* Yes */) {
+ var robj = g.network.simple_request(
+ 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
+ );
+ if (typeof robj.ilsevent != 'undefined') {
+ throw(robj);
+ } else {
+ alert('All templates saved.');
+ setTimeout(
+ function() {
+ try {
+ g.retrieve_templates();
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('Error saving templates',E);
+ }
+ },0
+ );
+ }
+ } else {
+ util.widgets.remove_children('template_placeholder');
+ var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
+ g.template_menu = util.widgets.make_menulist( list );
+ $('template_placeholder').appendChild(g.template_menu);
+ alert("Note: These imported templates will get saved along with any new template you try to create, but if that doesn't happen, then these templates will dissappear with the next invocation of the item attribute editor.");
+ }
+
+ } else {
+ alert('File not chosen for import.');
+ }
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('Error importing templates',E);
+ }
+}
+
+
+/******************************************************************************************************/
/* Restore backup copies */
g.reset = function() {
g.apply = function(field,value) {
g.error.sdump('D_TRACE','applying field = <' + field + '> value = <' + value + '>\n');
if (value == '<HACK:KLUDGE:NULL>') value = null;
+ if (field == 'alert_message') { value = value.replace(/^\W+$/g,''); }
for (var i = 0; i < g.copies.length; i++) {
var copy = g.copies[i];
try {
"Alert Message",
{
render: 'fm.alert_message() == null ? "<Unset>" : fm.alert_message()',
- input: 'c = function(v){ g.apply("alert_message",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.setAttribute("multiline",true); g.populate_alert_message_input(x); x.addEventListener("apply",function(f){ return function(ev) { f( String(ev.target.value).replace(/^\s+$/,"") ); } }(c), false);',
+ input: 'c = function(v){ g.apply("alert_message",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.setAttribute("multiline",true); g.populate_alert_message_input(x); x.addEventListener("apply",function(f){ return function(ev) { f( ev.target.value ); } }(c), false);',
}
],
groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
if (typeof g.changed[fn] != 'undefined') groupbox.setAttribute('class','copy_editor_field_changed');
caption = document.createElement('caption'); groupbox.appendChild(caption);
- caption.setAttribute('label',fn);
+ caption.setAttribute('label',fn); caption.setAttribute('id','caption_'+fn);
vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
grid.setAttribute('flex','1');
function() {
g.summarize( g.copies );
g.render();
+ document.getElementById(caption.id).focus();
}, 0
);
} catch(E) {
apply.addEventListener('command',function() { c(x.value); },false);
var cancel = document.createElement('button');
cancel.setAttribute('label','Cancel');
- cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); }, 0); }, false);
+ cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); document.getElementById(caption.id).focus(); }, 0); }, false);
hbox2.appendChild(cancel);
setTimeout( function() { x.focus(); }, 0 );
}
<hbox id="template_placeholder"/>
<button id="apply_template" label="Apply" accesskey="y" oncommand="g.apply_template()"/>
<button id="delete_template" label="Delete" oncommand="g.delete_template()"/>
+ <button id="import_templates" label="Import" oncommand="g.import_templates()"/>
+ <button id="export_templates" label="Export" oncommand="g.export_templates()"/>
<button id="save_template" label="Save" oncommand="g.save_template()"/>
</hbox>
<spacer flex="1"/>
</vbox>
<splitter><grippy /></splitter>
<vbox flex="1">
- <label value="Location" style="font-weight: bold; font-size: large"/>
+ <button style="font-weight: bold; font-size: normal" label="Location" accesskey="1" oncommand="document.getElementById('right_pane').firstChild.firstChild.focus();"/>
<vbox id="right_pane" flex="1"/>
</vbox>
<splitter><grippy /></splitter>
<vbox flex="1">
- <label value="Circulation" style="font-weight: bold; font-size: large"/>
+ <button style="font-weight: bold; font-size: normal" label="Circulation" accesskey="2" oncommand="document.getElementById('right_pane2').firstChild.firstChild.focus();"/>
<vbox id="right_pane2" flex="1"/>
</vbox>
<splitter><grippy /></splitter>
<vbox flex="1">
- <label value="Miscellaneous" style="font-weight: bold; font-size: large"/>
+ <button style="font-weight: bold; font-size: normal" label="Miscellaneous" accesskey="3" oncommand="document.getElementById('right_pane3').firstChild.firstChild.focus();"/>
<vbox id="right_pane3" flex="1"/>
</vbox>
<splitter><grippy /></splitter>
<vbox flex="1">
- <label value="Statistics" style="font-weight: bold; font-size: large"/>
+ <button style="font-weight: bold; font-size: normal" label="Statistics" accesskey="4" oncommand="document.getElementById('right_pane4').firstChild.firstChild.focus();"/>
<vbox id="right_pane4" flex="1"/>
</vbox>
</hbox>
/* button bar */
var hb = document.createElement('hbox'); np.appendChild(hb);
- var spacer = document.createElement('spacer'); hb.appendChild(spacer); spacer.flex = 1;
var btn1 = document.createElement('button'); hb.appendChild(btn1);
btn1.setAttribute('label','Delete This Note');
btn1.setAttribute('image',"/xul/server/skin/media/images/up_arrow.gif");
} }(i),
false
);
+ var spacer = document.createElement('spacer'); hb.appendChild(spacer); spacer.flex = 1;
+ var btn2 = document.createElement('button'); hb.appendChild(btn2);
+ btn2.setAttribute('label','Close Window');
+ btn2.setAttribute('oncommand','window.close();');
}
}
if (g.data.temp_copy) {
copy = g.data.temp_copy; g.data.temp_copy = null; g.data.stash('temp_copy');
}
+ var callnumber;
+ if (g.data.temp_callnumber) {
+ callnumber = g.data.temp_callnumber; g.data.temp_callnumber = null; g.data.stash('temp_callnumber');
+ }
$('caption').setAttribute('tooltiptext','Copy ID = ' + (copy_id || copy.id() ) );
try {
var copy = req.getResultObject();
if (typeof copy.ilsevent != 'undefined') throw(copy);
- g.list.append({'row':{'my':{'acp':copy}}});
- g.network.simple_request(
- 'FM_ACN_RETRIEVE',
- [ copy.call_number() ],
- function (rreq) {
- try {
- $w('barcode',copy.barcode());
- $w('ref',get_bool(copy.ref()) ? 'Yes' : 'No');
- $w('opac_visible',get_bool(copy.opac_visible()) ? 'Yes' : 'No');
- $w('circulate',get_bool(copy.circulate()) ? 'Yes' : 'No');
- $w('holdable',get_bool(copy.holdable()) ? 'Yes' : 'No');
- $w('age_protect',copy.age_protect() == null ? '<Unset>' : ( typeof copy.age_protect() == 'object' ? copy.age_protect().name() : g.data.hash.crahp[ copy.age_protect() ].name() ) );
- $w('location',typeof copy.location() == 'object' ? copy.location().name() : g.data.lookup('acpl',copy.location()).name() );
- $w('create_date',util.date.formatted_date(copy.create_date(),'%F'));
- $w('edit_date',util.date.formatted_date(copy.edit_date(),'%F'));
- $w('status',typeof copy.status() == 'object' ? copy.status().name() : g.data.hash.ccs[ copy.status() ].name() );
- } catch(E) {
- g.error.standard_unexpected_error_alert('rendering copy',E);
- }
- try {
- var cn = rreq.getResultObject();
- if (typeof cn.ilsevent != 'undefined') {
- switch(cn.ilsevent) {
- case 1508 /* ASSET_CALL_NUMBER_NOT_FOUND */ :
- $w('callnumber','Not Cataloged');
- break;
- default:
- throw(cn);
- break;
- }
- } else {
- $w('callnumber',cn.label());
+
+ function acn_callback(rreq) {
+ try {
+ $w('barcode',copy.barcode());
+ $w('ref',get_bool(copy.ref()) ? 'Yes' : 'No');
+ $w('opac_visible',get_bool(copy.opac_visible()) ? 'Yes' : 'No');
+ $w('circulate',get_bool(copy.circulate()) ? 'Yes' : 'No');
+ $w('holdable',get_bool(copy.holdable()) ? 'Yes' : 'No');
+ $w('age_protect',copy.age_protect() == null ? '<Unset>' : ( typeof copy.age_protect() == 'object' ? copy.age_protect().name() : g.data.hash.crahp[ copy.age_protect() ].name() ) );
+ $w('location',typeof copy.location() == 'object' ? copy.location().name() : g.data.lookup('acpl',copy.location()).name() );
+ $w('create_date',util.date.formatted_date(copy.create_date(),'%F'));
+ $w('edit_date',util.date.formatted_date(copy.edit_date(),'%F'));
+ $w('status',typeof copy.status() == 'object' ? copy.status().name() : g.data.hash.ccs[ copy.status() ].name() );
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('rendering copy',E);
+ }
+ try {
+ var cn = rreq.getResultObject();
+ if (typeof cn.ilsevent != 'undefined') {
+ switch(cn.ilsevent) {
+ case 1508 /* ASSET_CALL_NUMBER_NOT_FOUND */ :
+ $w('callnumber','Not Cataloged');
+ break;
+ default:
+ throw(cn);
+ break;
}
- } catch(E) {
- g.error.standard_unexpected_error_alert('retrieving volume',E);
+ } else {
+ $w('callnumber',cn.label());
}
+ g.list.append({'row':{'my':{'acp':copy,'acn':cn}}});
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('retrieving volume',E);
}
- );
+ }
+
+ if (callnumber) {
+ acn_callback( { 'getResultObject' : function() { return callnumber; } } );
+ } else {
+ g.network.simple_request(
+ 'FM_ACN_RETRIEVE',
+ [ copy.call_number() ], acn_callback
+ );
+ }
} catch(E) {
g.error.standard_unexpected_error_alert('retrieving copy',E);
}
</grid>
</deck>
<hbox>
- <label value="Alternate View" style="text-decoration: underline; color: blue" onclick="toggle_deck()"/>
- <label id="save_columns" value="Save Columns" style="text-decoration: underline; color: blue" onclick="try { g.list.save_columns(); } catch(E) { alert(E); }"/>
- <label id="sel_clip" value="Copy to Clipboard" style="text-decoration: underline; color: blue" onclick="try { g.list.node.view.selection.selectAll(); g.list.clipboard(); } catch(E) { alert(E); }"/>
+ <button label="Alternate View" oncommand="toggle_deck()"/>
+ <button id="save_columns" label="Save Columns" oncommand="try { g.list.save_columns(); } catch(E) { alert(E); }"/>
+ <button id="sel_clip" label="Copy to Clipboard" oncommand="try { g.list.node.view.selection.selectAll(); g.list.clipboard(); } catch(E) { alert(E); }"/>
+ <button id="print_export" label="Print Export" oncommand="try { g.list.on_all_fleshed = function() { JSAN.use('util.print'); var p = new util.print(); p.simple( g.list.dump_csv(), { 'content_type' : 'text/plain' } ); setTimeout( function() { g.list.on_all_fleshed = null; }, 0); }; g.list.full_retrieve(); } catch(E) { alert(E); }"/>
</hbox>
</groupbox>
<script type="text/javascript" src="/xul/server/main/JSAN.js"/>
<script>
<![CDATA[
+
+ function $(id) { return document.getElementById(id); }
+
function my_init() {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
- if (typeof JSAN == 'undefined') { throw( "The JSAN library object is missing."); }
+ if (typeof JSAN == 'undefined') { throw( "The JSAN library object is missing."); }
JSAN.errorLevel = "die"; // none, warn, or die
JSAN.addRepository('/xul/server/');
JSAN.use('util.error'); g.error = new util.error();
g.error.sdump('D_TRACE','my_init() for example_template.xul');
- g.cgi = new CGI();
- var session = g.cgi.param('session');
-
if (typeof window.xulG == 'object' && typeof window.xulG.set_tab_name == 'function') {
- try { window.xulG.set_tab_name('Template'); } catch(E) { alert(E); }
+ try { window.xulG.set_tab_name('MARC Template'); } catch(E) { alert(E); }
}
+ JSAN.use('util.network'); g.network = new util.network();
+ JSAN.use('util.widgets');
+ JSAN.use('util.functional');
+
+ var templates = g.network.simple_request('MARC_XML_TEMPLATE_LIST',[]);
+ if (typeof templates.ilsevent != 'undefined') throw(templates);
+ var ml = util.widgets.make_menulist(
+ util.functional.map_list(
+ templates.sort(),
+ function(el) {
+ return [ el /* The menu entry label */, el /* The menu entry value */ ];
+ }
+ )
+ );
+ $('menu_placeholder').appendChild(ml);
+
+ $('load').addEventListener(
+ 'command',
+ function(ev) {
+
+ var template_name;
+ try {
+
+ template_name = $('menu_placeholder').firstChild.value;
+ var marc = g.network.simple_request(
+ 'MARC_XML_TEMPLATE_RETRIEVE',
+ [ template_name ]
+ );
+ if (typeof marc.ilsevent != 'undefined') throw(marc);
+
+ var url = urls.XUL_MARC_EDIT;
+ var params = {
+ 'record' : { 'marc' : marc },
+ 'save' : {
+ 'label' : 'Create Record',
+ 'func' : function(new_marcxml) {
+ try {
+ var robj = g.network.simple_request(
+ 'MARC_XML_RECORD_IMPORT',
+ [ ses(), new_marcxml, 'System Local', 1 ]
+ );
+ if (typeof robj.ilsevent != 'undefined') throw(robj);
+ alert('Record created.');
+
+ /* Replace tab with OPAC-view of record */
+
+ var opac_url = xulG.url_prefix( urls.opac_rdetail ) + '?r=' + robj.id();
+ var content_params = {
+ 'session' : ses(),
+ 'authtime' : ses('authtime'),
+ 'opac_url' : opac_url,
+ };
+ xulG.set_tab(
+ xulG.url_prefix(urls.XUL_OPAC_WRAPPER),
+ {'tab_name':'Retrieving title...'},
+ content_params
+ );
+
+ } catch(E) {
+ g.error.standard_unexpected_error_alert(
+ 'Error creating MARC record.', E
+ );
+ }
+ }
+ }
+ };
+ $('marc_editor').setAttribute('src',url);
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ $('marc_editor').contentWindow.xulG = params;
+
+ /* hide template widgets */
+ $('actions').hidden = true;
+
+ window.xulG.set_tab_name(template_name);
+
+ } catch(E) {
+ g.error.standard_unexpected_error_alert(
+ 'Error loading MARC template: ' + template_name,
+ E
+ );
+ }
+
+ },
+ false
+ );
+
} catch(E) {
- g.error.standard_unexpect_error_alert('cat/marc_new.xul',E);
+ g.error.standard_unexpected_error_alert('cat/marc_new.xul',E);
}
}
]]>
</script>
- <vbox>
-
+ <vbox flex="1">
+ <hbox id="actions">
+ <hbox id="menu_placeholder" />
+ <button id="load" label="Load" accesskey="L"/>
+ </hbox>
+ <iframe id="marc_editor" flex="1"/>
</vbox>
</window>
return cf;
}
+function xml_escape_unicode ( str ) {
+ return str.replace(
+ /([\u0080-\ufffe])/g,
+ function (r,s) { return "&#x" + s.charCodeAt(0).toString(16) + ";"; }
+ );
+}
+
function my_init() {
try {
// Fake xulG for standalone...
// End faking part...
document.getElementById('save-button').setAttribute('label', window.xulG.save.label);
- document.getElementById('save-button').setAttribute('oncommand', 'mangle_005(); window.xulG.save.func(xml_record.toXMLString()); loadRecord(xml_record);');
+ document.getElementById('save-button').setAttribute('oncommand',
+ 'mangle_005(); ' +
+ 'var xml_string = xml_escape_unicode( xml_record.toXMLString() ); ' +
+ 'window.xulG.save.func( xml_string ); ' +
+ 'loadRecord(xml_record);'
+ );
if (window.xulG.record.url) {
var req = new XMLHttpRequest();
var df = <datafield tag="" ind1="" ind2="" xmlns="http://www.loc.gov/MARC21/slim"><subfield code="" /></datafield>;
- index.parent().insertChildAfter( index, df );
+ if (event.shiftKey) { // ctrl+shift+enter
+ index.parent().insertChildBefore( index, df );
+ } else {
+ index.parent().insertChildAfter( index, df );
+ }
var new_df = marcDatafield(df);
if (row.parentNode.lastChild === row) {
row.parentNode.appendChild( new_df );
} else {
- row.parentNode.insertBefore( new_df, row.nextSibling );
+ if (event.shiftKey) { // ctrl+shift+enter
+ row.parentNode.insertBefore( new_df, row );
+ } else {
+ row.parentNode.insertBefore( new_df, row.nextSibling );
+ }
}
new_df.firstChild.focus();
<caption label="Options"/>
<hbox flex="1">
<checkbox persist="checked" accesskey='s' label="Stack subfields" onclick="stackSubfields(this);" checked="false" id="stackSubfields"/>
- <button label="Validate" oncommand="validateAuthority(this);"/>
- <button id="save-button"/>
- <button label="Help" oncommand="alert('Add Row: CTRL+Enter\nAdd Subfield: CTRL+D\nRemove Row: CTRL+Del\nRemove Subfield: SHIFT+Del\nCreate/Replace 006: CTRL+F6\nCreate/Replace 007: CTRL+F7\nCreate/Replace 008: CTRL+F8\n');"/>
+ <button label="Validate" accesskey="V" oncommand="validateAuthority(this);"/>
+ <button id="save-button" accesskey="d"/>
+ <button label="Help" accesskey="H" oncommand="alert('Add Row: CTRL+Enter\nInsert Row: CTRL+Shift+Enter\nAdd Subfield: CTRL+D\nRemove Row: CTRL+Del\nRemove Subfield: SHIFT+Del\nCreate/Replace 006: CTRL+F6\nCreate/Replace 007: CTRL+F7\nCreate/Replace 008: CTRL+F8\n');"/>
</hbox>
</groupbox>
try {
JSAN.use('util.functional');
var sel = obj.list1.retrieve_selection();
+ document.getElementById('clip_button1').disabled = sel.length < 1;
obj.selection_list1 = util.functional.map_list(
sel,
function(o) { return JSON2js(o.getAttribute('retrieve_id')); }
try {
JSAN.use('util.functional');
var sel = obj.list2.retrieve_selection();
- document.getElementById('clip_button').disabled = sel.length < 1;
+ document.getElementById('clip_button2').disabled = sel.length < 1;
obj.selection_list2 = util.functional.map_list(
sel,
function(o) { return JSON2js(o.getAttribute('retrieve_id')); }
obj.controller.init(
{
'control_map' : {
- 'sel_clip' : [
+ 'save_columns2' : [
+ ['command'],
+ function() { obj.list2.save_columns(); }
+ ],
+ 'save_columns1' : [
+ ['command'],
+ function() { obj.list1.save_columns(); }
+ ],
+ 'sel_clip2' : [
['command'],
function() { obj.list2.clipboard(); }
],
+ 'sel_clip1' : [
+ ['command'],
+ function() { obj.list1.clipboard(); }
+ ],
'record_buckets_menulist_placeholder' : [
['render'],
function(e) {
}
],
+ 'cmd_export1' : [
+ ['command'],
+ function() {
+ obj.list1.on_all_fleshed = function() {
+ try {
+ dump(obj.list1.dump_csv() + '\n');
+ copy_to_clipboard(obj.list1.dump_csv());
+ setTimeout(function(){obj.list1.on_all_fleshed = null;},0);
+ } catch(E) {
+ alert(E);
+ }
+ }
+ obj.list1.full_retrieve();
+ }
+ ],
+
+ 'cmd_print_export1' : [
+ ['command'],
+ function() {
+ try {
+ obj.list1.on_all_fleshed =
+ function() {
+ try {
+ dump( obj.list1.dump_csv() + '\n' );
+ //copy_to_clipboard(obj.list.dump_csv());
+ JSAN.use('util.print'); var print = new util.print();
+ print.simple(obj.list1.dump_csv(),{'content_type':'text/plain'});
+ setTimeout(function(){ obj.list1.on_all_fleshed = null; },0);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ obj.list1.full_retrieve();
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ ],
+
+
+ 'cmd_print_export2' : [
+ ['command'],
+ function() {
+ try {
+ obj.list2.on_all_fleshed =
+ function() {
+ try {
+ dump( obj.list2.dump_csv() + '\n' );
+ //copy_to_clipboard(obj.list.dump_csv());
+ JSAN.use('util.print'); var print = new util.print();
+ print.simple(obj.list2.dump_csv(),{'content_type':'text/plain'});
+ setTimeout(function(){ obj.list2.on_all_fleshed = null; },0);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ obj.list2.full_retrieve();
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('print export',E);
+ }
+ }
+ ],
+
'cmd_merge_records' : [
['command'],
function() {
</script>
<commandset id="record_buckets_cmds">
- <command id="sel_clip" />
+ <command id="sel_clip1" />
+ <command id="sel_clip2" />
+ <command id="save_columns1" />
+ <command id="save_columns2" />
+ <command id="cmd_print_export1" />
+ <command id="cmd_export1" />
+ <command id="cmd_print_export2" />
<command id="cmd_record_buckets_submit_barcode" />
<command id="cmd_record_buckets_print" />
<command id="cmd_record_buckets_export" />
</vbox>
<hbox id="pending_buckets_bottom_ui">
+ <button id="save_button1" command="save_columns1" label="Save Columns" />
+ <button id="clip_button1" command="sel_clip1" label="Copy to Clipboard" disabled="true" />
+ <button id="cmd_print_export_btn1" command="cmd_print_export1" label="Print Export" />
+ <button id="cmd_export_btn1" command="cmd_export1" label="Export" />
<spacer flex="1"/>
<button label="Add All" id="record_buckets_add" accesskey="A" image="/xul/server/skin/media/images/down_arrow.gif"/>
<button label="Add Selected" id="record_buckets_sel_add" accesskey="" image="/xul/server/skin/media/images/down_arrow.gif"/>
<button id="record_buckets_delete_bucket" label="Delete Bucket"/>
<button id="refresh" label="Refresh"/>
<spacer flex="1"/>
- <button id="clip_button" command="sel_clip" label="Copy to Clipboard" disabled="true" />
+ <button id="save_button2" command="save_columns2" label="Save Columns" />
+ <button id="clip_button2" command="sel_clip2" label="Copy to Clipboard" disabled="true" />
<button id="record_buckets_delete_item" label="Delete Selected" disabled="true" image="/xul/server/skin/media/images/icon_delete.gif"/>
<button id="record_buckets_export" label="Add Selected" disabled="true" image="/xul/server/skin/media/images/up_arrow.gif"/>
</hbox>
</hbox>
<hbox id="record_buckets_bottom_ui">
+ <button id="cmd_print_export_btn2" command="cmd_print_export2" label="Print Export" />
<button id="record_buckets_export"
label="Export"
command="cmd_record_buckets_export"
if (!copy) throw(copy);
var new_bc = window.prompt('Enter the replacement barcode for the copy with barcode ' + old_bc + ':','','Replace Barcode');
+ new_bc = String( new_bc ).replace(/\s/g,'');
if (!new_bc) {
alert('Rename aborted. Blank for barcode not allowed.');
return old_bc;
}
}
+ g.load_prefs();
+
} catch(E) {
var err_msg = "!! This software has encountered an error. Please tell your friendly " +
"system administrator or software developer the following:\ncat/volume_copy_creator.xul\n" +E+ '\n';
function render_copy_count_entry(ev) {
if (ev.target.disabled) return;
if (! isNaN( Number( ev.target.value) ) ) {
+ if ( Number( ev.target.value ) > 100 ) {
+ if (!window.confirm('Are you sure you would like to create ' + ev.target.value + ' volumes?')) return;
+ }
if (node) { row.removeChild(node); node = null; }
//ev.target.disabled = true;
node = g.render_callnumber_copy_count_entry(row,ou_id,ev.target.value);
x.setAttribute('value','Call Numbers'); x.setAttribute('style','font-weight: bold');
x = document.createElement('label'); r.appendChild(x);
x.setAttribute('value','# of Copies'); x.setAttribute('style','font-weight: bold');
+ x.setAttribute('size','3'); x.setAttribute('cols','3');
+
function handle_change(tb1,tb2,hb3) {
if (tb1.value == '') return;
if (isNaN( Number( tb2.value ) )) return;
+ if ( Number( tb2.value ) > 100 ) {
+ if (!window.confirm('Are you sure you would like to create ' + tb2.value + ' copies?')) return;
+ }
//if (tb1.disabled || tb2.disabled) return;
);
//tb.addEventListener('change',ready_to_create,false);
tb.addEventListener('change', function(ev) {
- var barcode = ev.target.value;
+ var barcode = String( ev.target.value ).replace(/\s/g,'');
+ if (barcode != ev.target.value) ev.target.value = barcode;
if ($('check_barcodes').checked && ! util.barcode.check(barcode) ) {
g.error.yns_alert( '"' + barcode + '" is an invalid barcode.','Invalid Barcode','OK',null,null,'Check here to confirm this message.');
setTimeout( function() { ev.target.select(); ev.target.focus(); }, 0);
);
if (typeof acn_id.ilsevent != 'undefined') {
- g.error.standard_unexpected_error_alert('Problem finding or creating ' + cn + '. We will skip item creation for this volume.',anc_id);
+ g.error.standard_unexpected_error_alert('Problem finding or creating ' + cn + '. We will skip item creation for this volume.',acn_id);
continue;
}
}
}
+g.load_prefs = function() {
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+ JSAN.use('util.file'); var file = new util.file('volume_copy_creator.prefs');
+ if (file._file.exists()) {
+ var prefs = file.get_object(); file.close();
+ if (prefs.check_barcodes) {
+ if ( prefs.check_barcodes == 'false' ) {
+ $('check_barcodes').checked = false;
+ } else {
+ $('check_barcodes').checked = prefs.check_barcodes;
+ }
+ } else {
+ $('check_barcodes').checked = false;
+ }
+ if (prefs.print_labels) {
+ if ( prefs.print_labels == 'false' ) {
+ $('print_labels').checked = false;
+ } else {
+ $('print_labels').checked = prefs.print_labels;
+ }
+ } else {
+ $('print_labels').checked = false;
+ }
+
+ }
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('Error retrieving stored preferences',E);
+ }
+}
+
+g.save_prefs = function () {
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+ JSAN.use('util.file'); var file = new util.file('volume_copy_creator.prefs');
+ file.set_object(
+ {
+ 'check_barcodes' : $('check_barcodes').checked,
+ 'print_labels' : $('print_labels').checked,
+ }
+ );
+ file.close();
+ } catch(E) {
+ g.error.standard_unexpected_error_alert('Error storing preferences',E);
+ }
+}
+
<hbox style="border-bottom: solid black thin">
<hbox id="marc_cn"/>
<spacer flex="1" />
- <checkbox id="check_barcodes" label="Check Barcodes?" persist="checked" accesskey="B"/>
- <checkbox id="print_labels" label="Print Labels?" persist="checked" accesskey="P"/>
+ <checkbox id="check_barcodes" label="Check Barcodes?" oncommand="g.save_prefs();" accesskey="B"/>
+ <checkbox id="print_labels" label="Print Labels?" oncommand="g.save_prefs();" accesskey="P"/>
<button id="Create" accesskey="C" label="Edit then Create" disabled="true" oncommand="g.stash_and_close();"/>
</hbox>
<grid flex="1">
var title = 'Import Collision';
var btn1 = 'Overlay';
var btn2 = typeof r.payload.new_tcn == 'undefined' ? null : 'Import with alternate TCN ' + r.payload.new_tcn;
+ if (btn2) {
+ JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
+ var robj = obj.network.simple_request(
+ 'PERM_CHECK',[
+ ses(),
+ data.list.au[0].id(),
+ data.list.au[0].ws_ou(),
+ [ 'ALLOW_ALT_TCN' ]
+ ]
+ );
+ if (typeof robj.ilsevent != 'undefined') {
+ obj.error.standard_unexpected_error_alert('check permission',E);
+ }
+ if (robj.length != 0) btn2 = null;
+ }
var btn3 = 'Cancel Import';
var p = obj.error.yns_alert(msg,title,btn1,btn2,btn3,'Check here to confirm this action');
obj.error.sdump('D_ERROR','option ' + p + 'chosen');
obj.controller.view.sel_edit.setAttribute('disabled','true');
obj.controller.view.sel_opac.setAttribute('disabled','true');
obj.controller.view.sel_patron.setAttribute('disabled','true');
+ obj.controller.view.sel_last_patron.setAttribute('disabled','true');
obj.controller.view.sel_copy_details.setAttribute('disabled','true');
obj.controller.view.sel_bucket.setAttribute('disabled','true');
obj.controller.view.sel_spine.setAttribute('disabled','true');
obj.controller.view.sel_edit.setAttribute('disabled','false');
obj.controller.view.sel_opac.setAttribute('disabled','false');
obj.controller.view.sel_patron.setAttribute('disabled','false');
+ obj.controller.view.sel_last_patron.setAttribute('disabled','false');
obj.controller.view.sel_copy_details.setAttribute('disabled','false');
obj.controller.view.sel_bucket.setAttribute('disabled','false');
obj.controller.view.sel_spine.setAttribute('disabled','false');
circ.util.show_last_few_circs(obj.selection_list);
}
],
+ 'sel_last_patron' : [
+ ['command'],
+ function() {
+ var patrons = {};
+ for (var i = 0; i < obj.selection_list.length; i++) {
+ var circs = obj.network.simple_request('FM_CIRC_RETRIEVE_VIA_COPY',[ses(),obj.selection_list[i].copy_id,1]);
+ if (circs.length > 0) {
+ patrons[circs[0].usr()] = 1;
+ } else {
+ alert('Item ' + obj.selection_list[i].barcode + ' has never circulated');
+ }
+ }
+ for (var i in patrons) {
+ xulG.new_tab(urls.XUL_PATRON_DISPLAY,{},{'id' : i});
+ }
+ }
+ ],
'sel_copy_details' : [
['command'],
function() {
//I could override map_row_to_column here
}
);
+ obj.list.node.view.selection.select(0);
JSAN.use('util.sound'); var sound = new util.sound(); sound.circ_good();
<command id="sel_edit" disabled="true"/>
<command id="sel_opac" disabled="true"/>
<command id="sel_patron" disabled="true"/>
+ <command id="sel_last_patron" disabled="true"/>
<command id="sel_copy_details" disabled="true"/>
<command id="sel_bucket" disabled="true"/>
<command id="sel_spine" disabled="true"/>
<menuitem command="sel_opac" label="Show in Catalog" accesskey="S" />
<menuitem command="sel_copy_details" label="Show Item Details" accesskey="I" />
<menuitem command="sel_patron" label="Show Last Few Circulations" accesskey="L"/>
+ <menuitem command="sel_last_patron" label="Retrieve Last Patron who circulated item" accesskey="R"/>
<menuseparator/>
<menuitem command="sel_edit" label="Edit Item Attributes" accesskey="E" />
<menuseparator />
<menuitem command="sel_opac" label="Show in Catalog" accesskey="S" />
<menuitem command="sel_copy_details" label="Show Item Details" accesskey="I" />
<menuitem command="sel_patron" label="Show Last Few Circulations" accesskey="L"/>
+ <menuitem command="sel_last_patron" label="Retrieve Last Patron who circulated item" accesskey="R"/>
<menuseparator />
<menuitem command="sel_edit" label="Edit Item Attributes" accesskey="E" />
<menuseparator />
'mvr' : checkout.payload.record,
'acp' : checkout.payload.copy
}
- }
+ },
+ 'to_top' : true,
//I could override map_row_to_column here
}
);
var robj = g.network.simple_request('FM_ACP_DETAILS', [ ses(), g.copy_id ] );
if (typeof robj.ilsevent != 'undefined') throw(robj);
if (robj.copy) g.copy = robj.copy; else throw(robj);
- g.hold = robj.hold; g.transit = robj.transit; g.circ = robj.circ;
+ g.hold = robj.hold; g.transit = robj.transit; g.circ = robj.circ; g.callnumber = robj.volume;
if (g.hold) $('hold_caption').setAttribute('tooltiptext','Hold ID = ' + g.hold.id());
if (g.transit) $('transit_caption').setAttribute('tooltiptext','Transit ID = ' + g.transit.id());
if (g.circ) $('circ_caption').setAttribute('tooltiptext','Circ ID = ' + g.circ.id());
- g.callnumber = g.network.simple_request('FM_ACN_RETRIEVE',[ g.copy.call_number() ]);
- if (typeof g.callnumber.ilsevent != 'undefined') throw(g.callnumber);
+ //g.callnumber = g.network.simple_request('FM_ACN_RETRIEVE',[ g.copy.call_number() ]);
+ //if (typeof g.callnumber.ilsevent != 'undefined') throw(g.callnumber);
$('top').setAttribute('src',urls.XUL_BIB_BRIEF + '?docid=' + g.callnumber.record());
- g.data.temp_copy = g.copy; g.data.stash('temp_copy'); $('item_summary').setAttribute('src',urls.XUL_COPY_SUMMARY);
+ g.data.temp_copy = g.copy; g.data.stash('temp_copy');
+ g.data.temp_callnumber = g.callnumber; g.data.stash('temp_callnumber');
+ $('item_summary').setAttribute('src',urls.XUL_COPY_SUMMARY);
$('r_last').disabled = true;
if (g.circ) {
}
}
],
+ 'cmd_copy_status_print_export' : [
+ ['command'],
+ function() {
+ try {
+ obj.list.on_all_fleshed =
+ function() {
+ try {
+ dump( obj.list.dump_csv() + '\n' );
+ //copy_to_clipboard(obj.list.dump_csv());
+ JSAN.use('util.print'); var print = new util.print();
+ print.simple(obj.list.dump_csv(),{'content_type':'text/plain'});
+ setTimeout(function(){ obj.list.on_all_fleshed = null; },0);
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('export',E);
+ }
+ }
+ obj.list.full_retrieve();
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('export',E);
+ }
+ }
+ ],
+
'cmd_add_items' : [
['command'],
function() {
if ( obj.test_barcode(barcode) ) { /* good */ } else { /* bad */ return; }
}
JSAN.use('circ.util');
- var copy = obj.network.simple_request( 'FM_ACP_RETRIEVE_VIA_BARCODE', [ barcode ]);
- if (copy == null) {
- throw('Something weird happened. null result');
- } else if (copy.ilsevent) {
- switch(copy.ilsevent) {
- case -1:
- obj.error.standard_network_error_alert();
- obj.controller.view.copy_status_barcode_entry_textbox.select();
- obj.controller.view.copy_status_barcode_entry_textbox.focus();
- break;
- case 1502 /* ASSET_COPY_NOT_FOUND */ :
- try { document.getElementById('last_scanned').setAttribute('value',barcode + ' was either mis-scanned or is not cataloged.'); } catch(E) {}
- obj.error.yns_alert(barcode + ' was either mis-scanned or is not cataloged.','Not Cataloged','OK',null,null,'Check here to confirm this message');
- obj.controller.view.copy_status_barcode_entry_textbox.select();
- obj.controller.view.copy_status_barcode_entry_textbox.focus();
- break;
- default:
- throw(copy);
- break;
- }
- } else {
- obj.network.simple_request('FM_ACP_DETAILS', [ ses(), copy.id() ], function(req) {
- try {
- var details = req.getResultObject();
- var msg = copy.barcode() + ' -- ';
- if (copy.call_number() == -1) msg += 'Item is a Pre-Cat. ';
- if (details.hold) msg += 'Item is captured for a Hold. ';
- if (details.transit) msg += 'Item is in Transit. ';
- if (details.circ && ! details.circ.checkin_time()) msg += 'Item is circulating. ';
- try { document.getElementById('last_scanned').setAttribute('value',msg); } catch(E) {}
- } catch(E) {
- alert(E);
+ obj.network.simple_request('FM_ACP_DETAILS_VIA_BARCODE', [ ses(), barcode ], function(req) {
+ try {
+ var details = req.getResultObject();
+ if (details == null) {
+ throw('Something weird happened. null result');
+ } else if (details.ilsevent) {
+ switch(details.ilsevent) {
+ case -1:
+ obj.error.standard_network_error_alert();
+ obj.controller.view.copy_status_barcode_entry_textbox.select();
+ obj.controller.view.copy_status_barcode_entry_textbox.focus();
+ return;
+ break;
+ case 1502 /* ASSET_COPY_NOT_FOUND */ :
+ try { document.getElementById('last_scanned').setAttribute('value',barcode + ' was either mis-scanned or is not cataloged.'); } catch(E) {}
+ obj.error.yns_alert(barcode + ' was either mis-scanned or is not cataloged.','Not Cataloged','OK',null,null,'Check here to confirm this message');
+ obj.controller.view.copy_status_barcode_entry_textbox.select();
+ obj.controller.view.copy_status_barcode_entry_textbox.focus();
+ return;
+ break;
+ default:
+ throw(details);
+ break;
+ }
}
- } );
- var my_mvr = obj.network.simple_request('MODS_SLIM_RECORD_RETRIEVE_VIA_COPY', [ copy.id() ]);
- if (document.getElementById('trim_list')) {
- var x = document.getElementById('trim_list');
- if (x.checked) { obj.list.trim_list = 20; } else { obj.list.trim_list = null; }
- }
- obj.list.append(
- {
- 'retrieve_id' : js2JSON( { 'renewable' : copy.circulations() ? 't' : 'f', 'copy_id' : copy.id(), 'acn_id' : (typeof copy.call_number() == 'object' ? copy.call_number().id() : copy.call_number()), 'barcode' : barcode, 'doc_id' : (typeof my_mvr.ilsevent == 'undefined' ? my_mvr.doc_id() : null ) } ),
- 'row' : {
- 'my' : {
- 'mvr' : my_mvr,
- 'acp' : copy,
- }
- },
- 'to_top' : true,
+ var msg = details.copy.barcode() + ' -- ';
+ if (details.copy.call_number() == -1) msg += 'Item is a Pre-Cat. ';
+ if (details.hold) msg += 'Item is captured for a Hold. ';
+ if (details.transit) msg += 'Item is in Transit. ';
+ if (details.circ && ! details.circ.checkin_time()) msg += 'Item is circulating. ';
+ try { document.getElementById('last_scanned').setAttribute('value',msg); } catch(E) {}
+ if (document.getElementById('trim_list')) {
+ var x = document.getElementById('trim_list');
+ if (x.checked) { obj.list.trim_list = 20; } else { obj.list.trim_list = null; }
}
- );
- obj.controller.view.copy_status_barcode_entry_textbox.value = '';
- obj.controller.view.copy_status_barcode_entry_textbox.focus();
- }
+ obj.list.append(
+ {
+ 'retrieve_id' : js2JSON(
+ {
+ 'renewable' : details.circ ? 't' : 'f',
+ 'copy_id' : details.copy.id(),
+ 'acn_id' : details.volume ? details.volume.id() : -1,
+ 'barcode' : barcode,
+ 'doc_id' : details.mvr ? details.mvr.doc_id() : null
+ }
+ ),
+ 'row' : {
+ 'my' : {
+ 'mvr' : details.mvr,
+ 'acp' : details.copy,
+ 'acn' : details.volume,
+ 'atc' : details.transit,
+ 'circ' : details.circ,
+ 'ahr' : details.hold,
+ }
+ },
+ 'to_top' : true,
+ }
+ );
+ } catch(E) {
+ obj.error.standard_unexpected_error_alert('',E);
+ }
+ } );
+ obj.controller.view.copy_status_barcode_entry_textbox.value = '';
+ obj.controller.view.copy_status_barcode_entry_textbox.focus();
+
} catch(E) {
obj.error.standard_unexpected_error_alert('',E);
obj.controller.view.copy_status_barcode_entry_textbox.select();
<command id="cmd_copy_status_submit_barcode" />
<command id="cmd_copy_status_print" />
<command id="cmd_copy_status_export" />
+ <command id="cmd_copy_status_print_export" />
<command id="cmd_copy_status_reprint" />
<command id="cmd_copy_status_done" />
<command id="save_columns" />
</hbox>
<hbox id="copy_status_bottom_ui">
- <button id="copy_status_print"
- label="Print"
- command="cmd_copy_status_print"
- accesskey="P"/>
- <button id="copy_status_export"
- label="Export"
- command="cmd_copy_status_export"
- accesskey=""/>
+ <button id="copy_status_print" label="Print" command="cmd_copy_status_print" accesskey="P"/>
+ <button id="copy_status_export" label="Export" command="cmd_copy_status_export" accesskey=""/>
+ <button id="copy_status_export" label="Print Export" command="cmd_copy_status_print_export" accesskey=""/>
<checkbox id="trim_list" label="Trim List (20 rows)" checked="true" persist="checked"/>
<checkbox id="strict_barcode" label="Strict Barcode" checked="false" persist="checked"/>
<spacer flex="1"/>
obj.save_template( obj.controller.view.template_name_menu.value );
}
],
+ 'export' : [
+ ['command'],
+ function() {
+ obj.export_templates();
+ }
+ ],
+ 'import' : [
+ ['command'],
+ function() {
+ obj.import_templates();
+ }
+ ],
'default' : [
['command'],
function() {
alert('Template Saved\n' + js2JSON(obj.data.print_list_templates[name]));
},
+ 'export_templates' : function() {
+ try {
+ var obj = this;
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ JSAN.use('util.file');
+ var f = obj.pick_file('save');
+ if (f) {
+ if (f.exists()) {
+ var r = obj.error.yns_alert(
+ 'Would you like to overwrite the existing file ' + f.leafName + '?',
+ 'Templates Export Warning',
+ 'Yes',
+ 'No',
+ null,
+ 'Check here to confirm this message'
+ );
+ if (r != 0) { file.close(); alert('Not overwriting file.'); return; }
+ }
+ var e_file = new util.file(''); e_file._file = f;
+ e_file.write_content( 'truncate', js2JSON( obj.data.print_list_templates ) );
+ e_file.close();
+ alert('Templates exported as file ' + f.leafName);
+ } else {
+ alert('File not chosen for export.');
+ }
+
+ } catch(E) {
+ this.error.standard_unexpected_error_alert('Error exporting templates',E);
+ }
+ },
+
+ 'import_templates' : function() {
+ try {
+ var obj = this;
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ JSAN.use('util.file');
+ var f = obj.pick_file('open');
+ if (f && f.exists()) {
+ var i_file = new util.file(''); i_file._file = f;
+ var temp = JSON2js( i_file.get_content() );
+ i_file.close();
+ var s = '';
+ function set_t(k,v) {
+ obj.data.print_list_templates[k] = v;
+ if (s) s+= ', '; s += k;
+ }
+ for (var i in temp) { set_t(i,temp[i]); }
+ obj.data.stash('print_list_templates');
+ alert('Imported these templates: ' + s);
+ if (xulG) {
+ xulG.set_tab(xulG.url_prefix(urls.XUL_PRINT_LIST_TEMPLATE_EDITOR), {}, {});
+ } else {
+ alert('Please reload this interface.');
+ }
+
+ } else {
+ alert('File not chosen for import.');
+ }
+ } catch(E) {
+ this.error.standard_unexpected_error_alert('Error importing templates',E);
+ }
+ },
+
+ 'pick_file' : function(mode) {
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var nsIFilePicker = Components.interfaces.nsIFilePicker;
+ var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance( nsIFilePicker );
+ fp.init(
+ window,
+ mode == 'open' ? "Import Templates File" : "Save Templates File As",
+ mode == 'open' ? nsIFilePicker.modeOpen : nsIFilePicker.modeSave
+ );
+ fp.appendFilters( nsIFilePicker.filterAll );
+ if ( fp.show( ) == nsIFilePicker.returnOK && fp.file ) {
+ return fp.file;
+ } else {
+ return null;
+ }
+ } catch(E) {
+ this.error.standard_unexpected_error_alert('error picking file',E);
+ }
+ },
+
}
dump('exiting print_list_template_editor.js\n');
<hbox id="template_type_menu_placeholder" />
</hbox>
</groupbox>
- <groupbox>
+ <groupbox orient="horizontal">
<caption label="Actions" />
- <button id="preview" label="Preview" accesskey="P" />
- <button id="save" label="Save To Disk" accesskey="S" />
- <button id="default" label="Default" accesskey="D" />
- <button id="macros" label="Macros" accesskey="M" />
+ <vbox>
+ <button id="preview" label="Preview" accesskey="P" />
+ <button id="macros" label="Macros" accesskey="M" />
+ </vbox>
+ <vbox>
+ <button id="default" label="Default" accesskey="D" />
+ <button id="save" label="Save Locally" accesskey="S" />
+ </vbox>
+ <vbox>
+ <description>Be sure to "Save Locally" before export</description>
+ <button id="export" label="Export" accesskey="E" />
+ <button id="import" label="Import" accesskey="I" />
+ </vbox>
</groupbox>
</hbox>
<hbox flex="1">
case 1225 /* TRANSIT_ABORT_NOT_ALLOWED */ :
alert('Copy Id = ' + copy_id + '\n' + robj.desc);
break;
+ case 1504 /* ACTION_TRANSIT_COPY_NOT_FOUND */ :
+ alert('This item was no longer in transit at the time of the abort. Perhaps this happened from a stale display?');
+ break;
case 5000 /* PERM_FAILURE */ :
break;
default:
'primary' : false, 'hidden' : true, 'render' : function(my) { return my.acp.circ_modifier(); },
},
{
+ 'persist' : 'hidden width ordinal', 'id' : 'checkout_lib', 'label' : 'Checkout Lib', 'flex' : 1,
+ 'primary' : false, 'hidden' : true, 'render' : function(my) { return my.circ ? data.hash.aou[ my.circ.circ_lib() ].shortname() : ( my.acp.circulations() ? data.hash.aou[ my.acp.circulations()[0].circ_lib() ].shortname() : ""); },
+ },
+ {
'persist' : 'hidden width ordinal', 'id' : 'xact_start_full', 'label' : 'Checkout Timestamp', 'flex' : 1,
'primary' : false, 'hidden' : true, 'render' : function(my) { return my.circ ? my.circ.xact_start() : (my.acp.circulations() ? my.acp.circulations()[0].xact_start() : ""); },
},
{
'persist' : 'hidden width ordinal', 'id' : 'request_timestamp', 'label' : 'Request Timestamp', 'flex' : 0,
'primary' : false, 'hidden' : true,
- 'render' : function(my) { return my.ahr.request_time().toString().substr(0,10); },
+ 'render' : function(my) { return my.ahr.request_time().toString(); },
},
{
'persist' : 'hidden width ordinal', 'id' : 'request_time', 'label' : 'Request Date', 'flex' : 0,
});
}
+ var msg = '';
+
+ if (check.payload && check.payload.cancelled_hold_transit) {
+ msg += 'Original hold for transit cancelled.\n\n';
+ }
+
/* SUCCESS / NO_CHANGE / ITEM_NOT_CATALOGED */
if (check.ilsevent == 0 || check.ilsevent == 3 || check.ilsevent == 1202) {
try { check.route_to = data.lookup('acpl', check.copy.location() ).name(); } catch(E) { msg += 'Please inform your helpdesk/developers of this error:\nFIXME: ' + E + '\n'; }
- var msg = '';
if (check.ilsevent == 3 /* NO_CHANGE */) {
//msg = 'This item is already checked in.\n';
if (document.getElementById('no_change_label')) {
var lib = data.hash.aou[ check.org ];
check.route_to = lib.shortname();
- var msg = 'Destination: ' + check.route_to + '.\n';
+ msg += 'Destination: ' + check.route_to + '.\n';
msg += '\n' + lib.name() + '\n';
try {
if (lib.holds_address() ) {
}
}
-circ.util.renew_via_barcode = function ( barcode, patron_id ) {
+circ.util.renew_via_barcode = function ( barcode, patron_id, async ) {
try {
var obj = {};
JSAN.use('util.network'); obj.network = new util.network();
var params = { barcode: barcode };
if (patron_id) params.patron = patron_id;
+ function renew_callback(req) {
+ try {
+ var renew = req.getResultObject();
+ if (typeof renew.ilsevent != 'undefined') renew = [ renew ];
+ for (var j = 0; j < renew.length; j++) {
+ switch(renew[j].ilsevent) {
+ case 0 /* SUCCESS */ : break;
+ case 5000 /* PERM_FAILURE */: break;
+ case 1212 /* PATRON_EXCEEDS_OVERDUE_COUNT */ : break;
+ case 1213 /* PATRON_BARRED */ : break;
+ case 1215 /* CIRC_EXCEEDS_COPY_RANGE */ : break;
+ case 1224 /* PATRON_ACCOUNT_EXPIRED */ : break;
+ case 7002 /* PATRON_EXCEEDS_CHECKOUT_COUNT */ : break;
+ case 7003 /* COPY_CIRC_NOT_ALLOWED */ : break;
+ case 7004 /* COPY_NOT_AVAILABLE */ : break;
+ case 7006 /* COPY_IS_REFERENCE */ : break;
+ case 7007 /* COPY_NEEDED_FOR_HOLD */ : break;
+ case 7008 /* MAX_RENEWALS_REACHED */ : break;
+ case 7009 /* CIRC_CLAIMS_RETURNED */ : break;
+ case 7010 /* COPY_ALERT_MESSAGE */ : break;
+ case 7013 /* PATRON_EXCEEDS_FINES */ : break;
+ default:
+ throw(renew);
+ break;
+ }
+ }
+ if (typeof async == 'function') async(renew);
+ return renew;
+ } catch(E) {
+ JSAN.use('util.error'); var error = new util.error();
+ error.standard_unexpected_error_alert('Renew Failed for ' + barcode,E);
+ return null;
+ }
+ }
+
var renew = obj.network.simple_request(
'CHECKOUT_RENEW',
[ ses(), params ],
- null,
+ async ? renew_callback : null,
{
'title' : 'Override Renew Failure?',
'overridable_events' : [
}
}
);
- if (typeof renew.ilsevent != 'undefined') renew = [ renew ];
- for (var j = 0; j < renew.length; j++) {
- switch(renew[j].ilsevent) {
- case 0 /* SUCCESS */ : break;
- case 5000 /* PERM_FAILURE */: break;
- case 1212 /* PATRON_EXCEEDS_OVERDUE_COUNT */ : break;
- case 1213 /* PATRON_BARRED */ : break;
- case 1215 /* CIRC_EXCEEDS_COPY_RANGE */ : break;
- case 7002 /* PATRON_EXCEEDS_CHECKOUT_COUNT */ : break;
- case 7003 /* COPY_CIRC_NOT_ALLOWED */ : break;
- case 7004 /* COPY_NOT_AVAILABLE */ : break;
- case 7006 /* COPY_IS_REFERENCE */ : break;
- case 7007 /* COPY_NEEDED_FOR_HOLD */ : break;
- case 7008 /* MAX_RENEWALS_REACHED */ : break;
- case 7009 /* CIRC_CLAIMS_RETURNED */ : break;
- case 7010 /* COPY_ALERT_MESSAGE */ : break;
- case 7013 /* PATRON_EXCEEDS_FINES */ : break;
- default:
- throw(renew);
- break;
- }
- }
- return renew;
+ if (! async ) return renew_callback( { 'getResultObject' : function() { return renew; } } );
} catch(E) {
JSAN.use('util.error'); var error = new util.error();
function handle_void() {
try {
- JSAN.use('util.functional');
- var msg = 'Are you sure you would like to void bill' + ( g.bill_list_selection.length > 1 ? 's ' : ' ') + util.functional.map_list( g.bill_list_selection, function(o) { return g.mb_list[o].id(); }) + '?';
+ var mb_list = util.functional.map_list(g.bill_list_selection, function(o){return g.mb_list[o];});
+ mb_list = util.functional.filter_list( mb_list, function(o) { return ! get_bool( o.voided() ) });
+
+ if (mb_list.length == 0) { alert('All selected billings have already voided.'); return; }
+
+ var sum = 0;
+ for (var i = 0; i < mb_list.length; i++) sum += util.money.dollars_float_to_cents_integer( mb_list[i].amount() );
+ sum = util.money.cents_as_dollars( sum );
+
+ var msg = 'Are you sure you would like to void $' + sum + ' worth of line-item billings?';
var r = g.error.yns_alert(msg,'Voiding Bills','Yes','No',null,'Check here to confirm this message');
if (r == 0) {
- g.data.stash_retrieve();
- for (var i = 0; i < g.bill_list_selection.length; i++) {
- var robj = g.network.simple_request('FM_MB_VOID',[ses(),g.mb_list[g.bill_list_selection[i]].id()]);
- if (! g.data.voided_billings ) g.data.voided_billings = [];
- if (robj.ilsevent) {
- switch(robj.ilsevent) {
- case -1 : g.error.standard_network_error_alert('Void of Bill #' + g.mb_list[g.bill_list_selection[i]].id() + ' failed.'); break;
- default: g.error.standard_unexpected_error_alert('Void of Bill #' + g.mb_list[g.bill_list_selection[i]].id() + ' failed.',robj); break;
- }
- } else {
- g.data.voided_billings.push( g.mb_list[g.bill_list_selection[i]] );
- g.data.stash('voided_billings');
+ var robj = g.network.simple_request('FM_MB_VOID',[ses()].concat(util.functional.map_list(mb_list,function(o){return o.id();})));
+ if (robj.ilsevent) {
+ switch(robj.ilsevent) {
+ default:
+ g.error.standard_unexpected_error_alert('Error voiding bills.',robj);
+ retrieve_mbts();
+ g.bill_list.clear();
+ retrieve_mb();
+ if (typeof window.xulG == 'object' && typeof window.xulG.refresh == 'function') { window.xulG.refresh(); }
+ return;
+ break;
}
}
- alert('Action completed.');
+
+ g.data.stash_retrieve(); if (! g.data.voided_billings ) g.data.voided_billings = [];
+ for (var i = 0; i < mb_list.length; i++) {
+ g.data.voided_billings.push( mb_list[i] );
+ }
+ g.data.stash('voided_billings');
+ alert('Billings voided.');
retrieve_mbts();
g.bill_list.clear();
retrieve_mb();
if (typeof window.xulG == 'object' && typeof window.xulG.refresh == 'function') { window.xulG.refresh(); }
}
+
} catch(E) {
try { g.error.standard_unexpected_error_alert('bill_details.xul, handle_void:',E); } catch(F) { alert(E); }
}
<caption label="Bills" style="color: red"/>
<tree id="bill_tree" flex="1" enableColumnDrag="true"/>
<hbox>
- <label value="Save Columns" class="click_link" onclick="g.bill_list.save_columns();"/>
- <label value="Copy to Clipboard" class="click_link" onclick="g.bill_list.clipboard();"/>
+ <button label="Save Columns" oncommand="g.bill_list.save_columns();"/>
+ <button label="Copy to Clipboard" oncommand="g.bill_list.clipboard();"/>
+ <button label="Print Export" oncommand="try { g.bill_list.on_all_fleshed = function() { JSAN.use('util.print'); var p = new util.print(); p.simple( g.bill_list.dump_csv(), { 'content_type' : 'text/plain' } ); setTimeout( function() { g.bill_list.on_all_fleshed = null; }, 0); }; g.bill_list.full_retrieve(); } catch(E) { alert(E); }"/>
<spacer flex="1"/>
<button id="void" label="Void selected billings" disabled="true"/>
</hbox>
<caption label="Payments" style="color: green"/>
<tree id="payment_tree" flex="1" enableColumnDrag="true"/>
<hbox>
- <label value="Save Columns" class="click_link" onclick="g.payment_list.save_columns();"/>
- <label value="Copy to Clipboard" class="click_link" onclick="g.payment_list.clipboard();"/>
+ <button label="Save Columns" oncommand="g.payment_list.save_columns();"/>
+ <button label="Copy to Clipboard" oncommand="g.payment_list.clipboard();"/>
+ <button label="Print Export" oncommand="try { g.payment_list.on_all_fleshed = function() { JSAN.use('util.print'); var p = new util.print(); p.simple( g.payment_list.dump_csv(), { 'content_type' : 'text/plain' } ); setTimeout( function() { g.payment_list.on_all_fleshed = null; }, 0); }; g.payment_list.full_retrieve(); } catch(E) { alert(E); }"/>
<spacer flex="1"/>
</hbox>
</groupbox>
if (typeof robj.ilsevent != 'undefined') {
switch(robj.ilsevent) {
case 0 /* SUCCESS */ : return true; break;
- case 1226 /* REFUND_EXCEEDS_DESK_PAYMENTS */ : alert(robj.desc); return false; break;
+ case 1226 /* REFUND_EXCEEDS_DESK_PAYMENTS */ : alert(robj.desc + '\n\nAnother way to "zero" this transaction is to use Add Billing and add a misc bill to counter the negative balance.'); return false; break;
default: throw(robj); break;
}
}
);
}
+ var btn4 = document.createElement('button');
+ btn_box.appendChild( btn4 );
+ btn4.setAttribute( 'label', 'Void All Billings' );
+ btn4.setAttribute( 'mobts_id', my.mobts.id() );
+ btn4.addEventListener(
+ 'command',
+ function(ev) {
+ obj.void_all_billings( my.mobts.id() );
+ },
+ false
+ );
+
return vbox;
} catch(E) {
obj.error.standard_unexpected_error_alert('bills -> info_box',E);
this.error.standard_unexpected_error_alert('bills -> payment_box',E);
}
},
+
+ 'void_all_billings' : function(mobts_id) {
+ try {
+ var obj = this;
+ JSAN.use('util.functional');
+
+ var mb_list = obj.network.simple_request( 'FM_MB_RETRIEVE_VIA_MBTS_ID', [ ses(), mobts_id ] );
+ if (typeof mb_list.ilsevent != 'undefined') throw(mb_list);
+
+ mb_list = util.functional.filter_list( mb_list, function(o) { return ! get_bool( o.voided() ) });
+
+ if (mb_list.length == 0) { alert('All billings already voided on this bill.'); return; }
+
+ var sum = 0;
+ for (var i = 0; i < mb_list.length; i++) sum += util.money.dollars_float_to_cents_integer( mb_list[i].amount() );
+ sum = util.money.cents_as_dollars( sum );
+
+ var msg = 'Are you sure you would like to void $' + sum + ' worth of line-item billings?';
+ var r = obj.error.yns_alert(msg,'Voiding Bills','Yes','No',null,'Check here to confirm this message');
+ if (r == 0) {
+ var robj = obj.network.simple_request('FM_MB_VOID',[ses()].concat(util.functional.map_list(mb_list,function(o){return o.id();})));
+ if (robj.ilsevent) {
+ switch(robj.ilsevent) {
+ default:
+ obj.error.standard_unexpected_error_alert('Error voiding bills.',robj);
+ obj.refresh(); return;
+ break;
+ }
+ }
+
+ obj.data.stash_retrieve(); if (! obj.data.voided_billings ) obj.data.voided_billings = [];
+ for (var i = 0; i < mb_list.length; i++) {
+ obj.data.voided_billings.push( mb_list[i] );
+ }
+ obj.data.stash('voided_billings');
+ alert('Billings voided.');
+ obj.refresh();
+ }
+ } catch(E) {
+ try { obj.error.standard_unexpected_error_alert('bills.js, void_all_billings():',E); } catch(F) { alert(E); }
+ }
+
+ },
'gen_map_row_to_column' : function() {
var obj = this;
);
}
],
+ 'cmd_patron_exit' : [
+ ['command'],
+ function(ev) {
+ xulG.set_tab(urls.XUL_PATRON_BARCODE_ENTRY,{},{});
+ }
+ ],
'cmd_patron_holds' : [
['command'],
function(ev) {
+ '?patron_id=' + window.escape( obj.patron.id() ),
{},
{
+ 'url_prefix' : xulG.url_prefix,
'on_money_change' : function(b) {
//alert('test');
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
function(req) {
try {
var msg = ''; obj.stop_checkouts = false;
- if (patron.alert_message()) msg += '"' + patron.alert_message() + '"\n';
+ if (patron.alert_message()) msg += 'Alert message: "' + patron.alert_message() + '"\n';
//alert('obj.barcode = ' + obj.barcode);
if (obj.barcode) {
if (patron.cards()) for (var i = 0; i < patron.cards().length; i++) {
if (holds.ready && holds.ready > 0) msg += 'Holds available: ' + holds.ready;
if (msg) {
if (msg != obj.old_msg) {
- obj.error.yns_alert(msg,'Alert Message','OK',null,null,'Check here to confirm this message.');
+ //obj.error.yns_alert(msg,'Alert Message','OK',null,null,'Check here to confirm this message.');
+ document.documentElement.firstChild.focus();
+ var data_url = window.escape("<img src='" + xulG.url_prefix('/xul/server/skin/media/images/stop_sign.png') + "'/>" + '<h1>Alert</h1><blockquote><pre>' + msg + '\r\n\r\nPress a navigation button above (e.g. Check Out) to clear this alert.</pre></blockquote>');
+ obj.right_deck.set_iframe('data:text/html,'+data_url,{},{});
obj.old_msg = msg;
} else {
obj.error.sdump('D_TRACE','Not re-displaying this alert message: ' + msg);
<command id="cmd_patron_bills" />
<command id="cmd_patron_edit" />
<command id="cmd_patron_info" />
+ <command id="cmd_patron_exit" />
<command id="cmd_patron_retrieve" />
<command id="cmd_search_form" />
</commandset>
label="&staff.patron_navbar.edit;" accesskey="&staff.patron_navbar.edit.accesskey;"/>
<button id="PatronNavBar_info" command="cmd_patron_info" class="nav"
label="&staff.patron_navbar.info;" accesskey="&staff.patron_navbar.info.accesskey;"/>
+ <button id="PatronNavBar_exit" command="cmd_patron_exit" class="nav"
+ label="Exit" accesskey="x"/>
</hbox>
<hbox id="PatronNavBar0">
/* button bar */
var hb = document.createElement('hbox'); np.appendChild(hb);
- var spacer = document.createElement('spacer'); hb.appendChild(spacer); spacer.flex = 1;
var btn1 = document.createElement('button'); hb.appendChild(btn1);
btn1.setAttribute('label','Delete This Note');
btn1.setAttribute('image',"/xul/server/skin/media/images/up_arrow.gif");
function retrieve_surveys() {
try {
- var surveys = g.data.list.asv;
+ var surveys = g.data.list.my_asv;
g.survey_responses = {};
for (var i = 0; i < surveys.length; i++) {
var responses = g.network.simple_request(
'sel_clip' : [ ['command'], function() { obj.list.clipboard(); } ],
'sel_clip2' : [ ['command'], function() { obj.list2.clipboard(); } ],
'sel_patron' : [ ['command'], function() { JSAN.use('circ.util'); circ.util.show_last_few_circs(obj.retrieve_ids); } ],
+ 'sel_bucket' : [
+ ['command'],
+ function() {
+ JSAN.use('cat.util');
+ cat.util.add_copies_to_bucket(util.functional.map_list( obj.retrieve_ids, function(o) { return o.copy_id; } ) );
+ }
+ ],
+ 'sel_bucket2' : [
+ ['command'],
+ function() {
+ JSAN.use('cat.util');
+ cat.util.add_copies_to_bucket(util.functional.map_list( obj.retrieve_ids2, function(o) { return o.copy_id; } ) );
+ }
+ ],
'sel_mark_items_damaged' : [
['command'],
function() {
'cmd_items_print2' : [ ['command'], function() { obj.items_print(2); } ],
'cmd_items_export' : [ ['command'], function() { obj.items_export(1); } ],
'cmd_items_export2' : [ ['command'], function() { obj.items_export(2); } ],
- 'cmd_items_renew' : [ ['command'], function() { obj.items_renew(1); alert('Action complete.'); obj.retrieve(); } ],
+ 'cmd_items_renew' : [ ['command'], function() { obj.items_renew(1); /*alert('Action complete.'); obj.retrieve();*/ } ],
'cmd_items_renew_all' : [ ['command'], function() { obj.items_renew_all(); } ],
- 'cmd_items_renew2' : [ ['command'], function() { obj.items_renew(2); alert('Action complete.'); obj.retrieve(); } ],
+ 'cmd_items_renew2' : [ ['command'], function() { obj.items_renew(2); /*alert('Action complete.'); obj.retrieve();*/ } ],
'cmd_items_edit' : [ ['command'], function() { obj.items_edit(1); alert('Action complete.'); obj.retrieve(); } ],
'cmd_items_edit2' : [ ['command'], function() { obj.items_edit(2); alert('Action complete.'); obj.retrieve(); } ],
'cmd_items_mark_lost' : [ ['command'], function() { obj.items_mark_lost(1); alert('Action complete.'); obj.retrieve(); } ],
obj.controller.view.sel_mark_items_missing2.setAttribute('disabled','true');
obj.controller.view.sel_clip.setAttribute('disabled','true');
obj.controller.view.sel_clip2.setAttribute('disabled','true');
+ obj.controller.view.sel_bucket.setAttribute('disabled','true');
+ obj.controller.view.sel_bucket2.setAttribute('disabled','true');
obj.controller.view.sel_copy_details.setAttribute('disabled','true');
obj.controller.view.sel_patron.setAttribute('disabled','true');
obj.controller.view.sel_copy_details2.setAttribute('disabled','true');
fake_copy.barcode( '' );
fake_copy.circ_lib( nc_circ.circ_lib() );
- obj.list.append( { 'row' : { 'my' : { 'circ' : fake_circ, 'mvr' : fake_record, 'acp' : fake_copy } }, } );
+ obj.list.append( { 'row' : { 'my' : { 'circ' : fake_circ, 'mvr' : fake_record, 'acp' : fake_copy } }, 'to_bottom' : true } );
} catch(F) {
obj.error.standard_unexpected_error_alert('Error showing NonCat #' + robj[ii].id(),F);
try {
obj.list.select_all();
obj.items_renew(1,true);
- setTimeout(function(){list.on_all_fleshed = null; alert('Action complete.'); obj.retrieve(); },0);
+ setTimeout(function(){list.on_all_fleshed = null; /*alert('Action complete.'); obj.retrieve();*/ },0);
} catch(E) {
obj.error.standard_unexpected_error_alert('2 All items were not likely renewed',E);
}
var r = window.confirm(msg);
if (!r) { return; }
}
+
+ var count = 0;
+
+ function gen_renew(bc) {
+ var x = document.getElementById('renew_msgs');
+ if (x) {
+ var l = document.createElement('label');
+ l.setAttribute('value','Renewing ' + bc);
+ x.appendChild(l);
+ }
+ var renew = circ.util.renew_via_barcode( barcode, obj.patron_id,
+ function(r) {
+ if ( instanceOf( r[0], 'circ' ) || (typeof r[0].ilsevent != 'undefined' && r[0].ilsevent == 0) ) {
+ l.setAttribute('value', bc + ' renewed.');
+ } else {
+ l.setAttribute('value', bc + ' not renewed. ' + r[0].desc);
+ }
+ count--;
+ if (count == 0) {
+ if (window.confirm('Action completed. Refresh list?')) obj.retrieve();
+ JSAN.use('util.widgets'); util.widgets.remove_children(x);
+ }
+ }
+ );
+ }
+
for (var i = 0; i < retrieve_ids.length; i++) {
try {
+ count++;
var barcode = retrieve_ids[i].barcode;
- //alert('Renew barcode = ' + barcode);
- var renew = circ.util.renew_via_barcode( barcode, obj.patron_id );
+ gen_renew(barcode);
} catch(E) {
obj.error.standard_unexpected_error_alert('Renew probably did not happen for barcode ' + barcode,E);
var columns = circ.util.columns(
{
'barcode' : { 'hidden' : false },
+ 'checkout_lib' : { 'hidden' : false },
'circ_lib' : { 'hidden' : false },
'title' : { 'hidden' : false, 'flex' : '3' },
'due_date' : { 'hidden' : false },
var columns2 = circ.util.columns(
{
'barcode' : { 'hidden' : false },
+ 'checkout_lib' : { 'hidden' : false },
'circ_lib' : { 'hidden' : false },
'title' : { 'hidden' : false, 'flex' : '3' },
'checkin_time' : { 'hidden' : false },
function(req) {
try {
var robj = req.getResultObject();
+ if (typeof robj.ilsevent != 'undefined') throw(robj);
+ if (typeof robj.ilsevent == 'null') throw('null result');
row.my.circ = robj.circ;
row.my.acp = robj.copy;
row.my.mvr = robj.mvr;
params.on_retrieve(row);
}
} catch(E) {
- obj.error.standard_unexpected_error_alert('circ details',E);
+ obj.error.standard_unexpected_error_alert('Error in callback for FM_CIRC_DETAILS in patron/items.js',E);
}
}
);
try {
switch(which_list) {
case 1:
- obj.list2.append( { 'row' : { 'my' : { 'circ_id' : circ_id } }, } );
+ obj.list2.append( { 'row' : { 'my' : { 'circ_id' : circ_id } }, 'to_bottom' : true } );
break;
default:
- obj.list.append( { 'row' : { 'my' : { 'circ_id' : circ_id } }, } );
+ obj.list.append( { 'row' : { 'my' : { 'circ_id' : circ_id } }, 'to_bottom' : true } );
break;
}
} catch(E) {
obj.controller.view.cmd_items_mark_lost.setAttribute('disabled','false');
obj.controller.view.cmd_show_catalog.setAttribute('disabled','false');
obj.controller.view.sel_copy_details.setAttribute('disabled','false');
+ obj.controller.view.sel_bucket.setAttribute('disabled','false');
obj.controller.view.sel_patron.setAttribute('disabled','false');
obj.controller.view.sel_mark_items_damaged.setAttribute('disabled','false');
obj.controller.view.sel_mark_items_missing.setAttribute('disabled','false');
obj.controller.view.cmd_items_mark_lost2.setAttribute('disabled','false');
obj.controller.view.cmd_show_catalog2.setAttribute('disabled','false');
obj.controller.view.sel_copy_details2.setAttribute('disabled','false');
+ obj.controller.view.sel_bucket2.setAttribute('disabled','false');
obj.controller.view.sel_patron2.setAttribute('disabled','false');
obj.controller.view.sel_mark_items_damaged2.setAttribute('disabled','false');
obj.controller.view.sel_mark_items_missing2.setAttribute('disabled','false');
<commandset id="items_cmds">
<command id="save_columns" />
+ <command id="sel_bucket" disabled="true"/>
<command id="sel_clip" />
<command id="sel_copy_details"/>
<command id="sel_patron"/>
<command id="cmd_show_noncats" />
<command id="save_columns2" />
+ <command id="sel_bucket2" disabled="true"/>
<command id="sel_clip2" />
<command id="sel_copy_details2"/>
<command id="sel_patron2"/>
<popupset id="items_popupset">
<popup id="items_actions" position="at_pointer">
<menuitem command="sel_clip" label="Copy to Clipboard" accesskey="C" />
+ <menuitem command="sel_bucket" label="Add to Item Bucket" accesskey="A"/>
<menuitem label="Show in Catalog" command="cmd_show_catalog" />
<menuitem command="sel_copy_details" label="Show Item Details" accesskey="I" />
<menuitem command="sel_patron" label="Show Last Few Circulations" accesskey="L"/>
</popup>
<popup id="items_actions2" position="at_pointer">
<menuitem command="sel_clip2" label="Copy to Clipboard" accesskey="C" />
+ <menuitem command="sel_bucket2" label="Add to Item Bucket" accesskey="A"/>
<menuitem label="Show in Catalog" command="cmd_show_catalog2" />
<menuitem command="sel_copy_details2" label="Show Item Details" accesskey="I" />
<menuitem command="sel_patron2" label="Show Last Few Circulations" accesskey="L"/>
<vbox flex="0">
<hbox id="items_top_ui" />
</vbox>
+ <vbox id="renew_msgs" />
<tree id="items_list" flex="1" enableColumnDrag="true" context="items_actions"/>
<vbox flex="0">
<hbox id="items_bottom_ui" />
<menu label="Actions for Selected Items" accesskey="S">
<menupopup>
<menuitem command="sel_clip" label="Copy to Clipboard" accesskey="C" />
+ <menuitem command="sel_bucket" label="Add to Item Bucket" accesskey="A"/>
<menuitem label="Show in Catalog" command="cmd_show_catalog" />
<menuitem command="sel_copy_details" label="Show Item Details" accesskey="I" />
<menuitem command="sel_patron" label="Show Last Few Circulations" accesskey="L"/>
<menu label="Actions for Selected Items" old_accesskey="S">
<menupopup>
<menuitem command="sel_clip2" label="Copy to Clipboard" accesskey="C" />
+ <menuitem command="sel_bucket2" label="Add to Item Bucket" accesskey="A"/>
<menuitem label="Show in Catalog" command="cmd_show_catalog2" />
<menuitem command="sel_copy_details2" label="Show Item Details" accesskey="I" />
<menuitem command="sel_patron2" label="Show Last Few Circulations" accesskey="L"/>
function gen_func(r) {
return function() {
- obj.list.append( { 'retrieve_id' : r, 'row' : {} } );
+ obj.list.append( { 'retrieve_id' : r, 'row' : {}, 'to_bottom' : true } );
}
}
};
}
],
+ 'patron_date_of_exp' : [
+ ['render'],
+ function(e) {
+ return function() {
+ e.setAttribute('value',
+ 'Expires on ' + (
+ obj.patron.expire_date() ?
+ obj.patron.expire_date().substr(0,10) :
+ '<Unset>'
+ )
+ );
+ };
+ }
+ ],
'patron_date_of_birth' : [
['render'],
function(e) {
<row id="pdsgr5a">
<label id="patron_net_access" class="net_access value"/>
</row>
+ <row id="pdsgr5aa">
+ <label id="patron_date_of_exp" class="expire_date value"/>
+ </row>
</rows></grid>
<grid id="PatronSummaryStatus_grid" flex="1"/>
try {
+ var save_perms = [];
for (var i in user_perms) {
+ // Group based perm? skip it.
+ if (user_perms[i].id() < 0) continue;
+
if (user_perms[i].depth() == null) {
var p;
for (var j in perm_list) {
}
throw "Depth is required on the " + p.code() + " permission.";
}
+
+ save_perms.push( user_perms[i] );
}
- var req = new RemoteRequest( 'open-ils.actor', 'open-ils.actor.user.permissions.update', ses_id, user_perms );
+ var req = new RemoteRequest( 'open-ils.actor', 'open-ils.actor.user.permissions.update', ses_id, save_perms );
req.send(true);
var ok = req.getResultObject();
if (user.id() > 0) {
req = new RemoteRequest( 'open-ils.actor', 'open-ils.actor.permissions.user_perms.retrieve', ses_id, user.id() );
req.send(true);
- var up = req.getResultObject();
- for (var i in up) {
- if (up[i].id() > 0)
- user_perms.push(up[i]);
- }
+ user_perms = req.getResultObject();
req = new RemoteRequest( 'open-ils.actor', 'open-ils.actor.permissions.retrieve' );
req.send(true);
}
for (var i in user_perms) {
- if (perm_def.id() == user_perms[i].perm() && user_perms[i].id() > 0)
+ if (perm_def.id() == user_perms[i].perm())
up = user_perms[i];
}
var dis = false;
- if (!sp || !sp.grantable()) dis = true;
+ if ((up && up.id() < 0) || !sp || !sp.grantable()) dis = true;
if (all) dis = false;
var label_cell = findNodeByName(prow,'plabel');
.PATRON_EXPIRED .patronNameLarge { background-color: #666666; color: white;}
.PATRON_EXPIRED label.expired_indicator { display: inline; color: black; }
+.PATRON_EXPIRED label.expire_date { background-color: #666666; color: white }
.PATRON_BARRED .patronNameLarge { background-color: #CC3300; color: white; }
.PATRON_BARRED label.barred_indicator { display: inline; color: #CC3300; }
.PATRON_NET_ACCESS_2 .net_access { color: green; } /* Unfiltered */
.PATRON_NET_ACCESS_3 .net_access { color: #CC3300; } /* No Access */
+.bad_barcode { color: red; }
+.line_item { font-family: monospace; }
+.checking_barcode { color: orange; text-decoration: blink; }
+
pid=$(cat $pidfile);
echo "Stopping $item : $pid";
- kill -s INT $pid;
+ kill -s INT $pid 2> /dev/null;
+ sleep 1;
+ kill -9 $pid 2> /dev/null;
rm -f $pidfile;
fi;
# --------------------------------------
-# log file names
-[logs]
-debug = debug.log
-error = error.log
-transport = transport.log
-message = message.log
-method = method.log
-trace = trace.log
-opac = opac.log
-
-
list of router domains we should register with.
We must at least have our default jabber domain in here
-->
- <router>127.0.0.1</router>
+ <router>localhost</router>
</routers>
<domains>
<!-- Our jabber domain, currenlty only one domain is supported -->
- <domain>127.0.0.1</domain>
+ <domain>localhost</domain>
</domains>
<username>client</username>
<!-- Update this if you use ChopChop -->
<chopchop> <!-- Our jabber server -->
- <domain>127.0.0.1</domain>
+ <domain>localhost</domain>
<port>5222</port>
<!-- used when multiple servers need to communicate -->
<!-- The section between <gateway>...</gateway> is a standard OpenSRF C stack config file -->
<gateway>
+ <!-- we consider ourselves to the the "originating" client for requests,
+ which means we define the log XID string for log traces -->
+ <client>true</client>
+
<!-- the routers's name on the network -->
<router_name>router</router_name>
<!-- jabber domains to connect to (domain1, domain2, ...) -->
<domains>
- <domain>127.0.0.1</domain>
+ <domain>localhost</domain>
</domains>
<!-- These are the services that the gateway will serve.
<rest_gateway>
<router_name>router</router_name>
<domains>
- <domain>127.0.0.1</domain>
+ <domain>localhost</domain>
</domains>
<username>mylogin</username>
<passwd>mypassword</passwd>
<trusted_domains>
<!-- Trusted servers are allowed to register apps with the router -->
- <server>127.0.0.1</server>
+ <server>localhost</server>
<!-- Trusted clients are allowed to send packets through the router -->
- <client>127.0.0.1</client>
+ <client>localhost</client>
</trusted_domains>
<transport>
<!-- jabber server are we connecting to -->
- <server>127.0.0.1</server>
+ <server>localhost</server>
<port>5222</port>
<!-- do not change this -->
libstack/xml_utils.o \
libstack/osrf_transgroup.o \
libstack/osrf_list.o \
- libstack/osrf_big_list.o \
libstack/osrf_hash.o \
- libstack/osrf_big_hash.o \
utils/socket_bundle.o \
utils/string_array.o \
utils/utils.o \
utils/log.o \
utils/md5.o \
- utils/sha.o \
+ utils/sha.o
OPENSRF_HEADERS = libtransport/transport_session.h \
libtransport/transport_client.h \
libstack/xml_utils.h \
libstack/osrf_transgroup.h \
libstack/osrf_list.h \
- libstack/osrf_big_list.h \
libstack/osrf_hash.h \
- libstack/osrf_big_hash.h \
utils/socket_bundle.h \
utils/string_array.h \
utils/utils.h \
utils/log.h \
utils/md5.h \
- utils/sha.h \
-
+ utils/sha.h
all: prep \
libopensrf.so \
@echo stack
make -C libstack
@echo $@
- $(CC) -shared -W1 $(LDFLAGS) -lJudy -lxml2 -lmemcache -lobjson $(OPENSRF_TARGETS) -o $(TMPDIR)/$(LIBOPENSRF)
+ $(CC) -shared -W1 $(LDFLAGS) -lxml2 -lmemcache -lobjson $(OPENSRF_TARGETS) -o $(TMPDIR)/$(LIBOPENSRF)
@echo apps
make -C c-apps
libstack/opensrf.o: libstack/opensrf.c libopensrf.so
libstack/opensrf: libstack/opensrf.o
@echo $@
- $(CC) $(CFLAGS) $(LDFLAGS) -lJudy -lxml2 -lopensrf -lobjson libstack/opensrf.o -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) -lxml2 -lopensrf -lobjson libstack/opensrf.o -o $@
router: libopensrf.so
int osrfAppInitialize();
int osrfAppChildInit();
+void osrfAppChildExit();
int osrfMathRun( osrfMethodContext* );
return 0;
}
+/* called when this process is just coming into existence */
int osrfAppChildInit() {
return 0;
}
+/* called when this process is about to exit */
+void osrfAppChildExit() {
+ osrfLogDebug(OSRF_LOG_MARK, "Child is exiting...");
+}
+
+
int osrfMathRun( osrfMethodContext* ctx ) {
OSRF_METHOD_VERIFY_CONTEXT(ctx); /* see osrf_application.h */
a_l = apacheGetFirstParamValue( params, "api_level" );
mparams = apacheGetParamValues( params, "param" ); /* free me */
+ /* set the user defined timeout value */
+ int timeout = 60;
+ char* tout = apacheGetFirstParamValue( params, "timeout" ); /* request timeout in seconds */
+ if( tout ) {
+ timeout = atoi(tout);
+ osrfLogDebug(OSRF_LOG_MARK, "Client supplied timeout of %d", timeout);
+ }
+
+
if (a_l)
api_level = atoi(a_l);
fflush(stderr);
*/
-
- /* ----------------------------------------------------------------- */
- /* log all requests to the activity log */
- const char* authtoken = apr_table_get(r->headers_in, "X-OILS-Authtoken");
- if(!authtoken) authtoken = "";
- growing_buffer* act = buffer_init(128);
- buffer_fadd(act, "[%s] [%s] %s %s", r->connection->remote_ip, authtoken, service, method );
- char* str; int i = 0;
- while( (str = osrfStringArrayGetString(mparams, i++)) )
- if( i == 1 ) buffer_fadd(act, " %s", str);
- else buffer_fadd(act, ", %s", str);
-
- osrfLogActivity( OSRF_LOG_MARK, act->buf );
- buffer_free(act);
- /* ----------------------------------------------------------------- */
-
osrfAppSession* session = osrf_app_client_session_init(service);
double starttime = get_timestamp_millis();
exit(1);
}
+
+ /* ----------------------------------------------------------------- */
+ /* log all requests to the activity log */
+ const char* authtoken = apr_table_get(r->headers_in, "X-OILS-Authtoken");
+ if(!authtoken) authtoken = "";
+ growing_buffer* act = buffer_init(128);
+ buffer_fadd(act, "[%s] [%s] %s %s", r->connection->remote_ip, authtoken, service, method );
+ char* str; int i = 0;
+ while( (str = osrfStringArrayGetString(mparams, i++)) ) {
+ if( i == 1 ) {
+ OSRF_BUFFER_ADD(act, " ");
+ OSRF_BUFFER_ADD(act, str);
+ } else {
+ OSRF_BUFFER_ADD(act, ", ");
+ OSRF_BUFFER_ADD(act, str);
+ }
+ }
+
+ osrfLogActivity( OSRF_LOG_MARK, act->buf );
+ buffer_free(act);
+ /* ----------------------------------------------------------------- */
+
+
osrf_message* omsg = NULL;
int statuscode = 200;
char* statustext = NULL;
char* output = NULL;
- while((omsg = osrfAppSessionRequestRecv( session, req_id, 60 ))) {
+ while((omsg = osrfAppSessionRequestRecv( session, req_id, timeout ))) {
statuscode = omsg->status_code;
jsonObject* res;
string_array_destroy(mparams);
osrfLogDebug(OSRF_LOG_MARK, "Gateway served %d requests", ++numserved);
+ osrfLogClearXid();
return ret;
}
# provided to any method is not at least as large as the 'argc' setting for the method
CFLAGS += -DASSUME_STATELESS -DOSRF_LOG_PARAMS -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing
-LDLIBS += -lxml2 -lobjson -ldl -lmemcache -LJudy
+LDLIBS += -lxml2 -lobjson -ldl -lmemcache
TARGETS = osrf_message.o \
osrf_app_session.o \
osrf_cache.o \
osrf_transgroup.o \
osrf_list.o \
- osrf_big_list.o \
osrf_hash.o \
- osrf_big_hash.o \
- xml_utils.o
+ xml_utils.o
HEADERS = osrf_message.h \
osrf_app_session.h \
osrf_cache.h \
osrf_transgroup.h \
osrf_list.h \
- osrf_big_list.h \
osrf_hash.h \
- osrf_big_hash.h \
xml_utils.h
all: xml_utils.o $(TARGETS) copy
osrf_application.o: osrf_application.c osrf_application.h
osrf_cache.o: osrf_cache.c osrf_cache.h
osrf_list.o: osrf_list.c osrf_list.h
-osrf_big_list.o: osrf_big_list.c osrf_big_list.h
+#osrf_big_list.o: osrf_big_list.c osrf_big_list.h
osrf_hash.o: osrf_hash.c osrf_hash.h
-osrf_big_hash.o: osrf_big_hash.c osrf_big_hash.h
+#osrf_big_hash.o: osrf_big_hash.c osrf_big_hash.h
clean:
osrfHashFree(osrfAppSessionCache);
}
+
+
/** Frees memory used by an app_request object */
void _osrf_app_request_free( void * req ){
if( req == NULL ) return;
char* method_name, int protocol, string_array* param_strings ) {
if(session == NULL) return -1;
+ osrfLogMkXid();
+
osrf_message* req_msg = osrf_message_init( REQUEST, ++(session->thread_trace), protocol );
osrf_message_set_method(req_msg, method_name);
if(params) {
transport_message* t_msg = message_init(
string, "", session->session_id, session->remote_id, NULL );
+ message_set_osrf_xid( t_msg, osrfLogGetXid() );
retval = client_send_message( session->transport_handle, t_msg );
void osrfAppSessionCleanup();
+
#endif
osrfApplication* app = safe_malloc(sizeof(osrfApplication));
app->handle = dlopen (soFile, RTLD_NOW);
+ app->onExit = NULL;
if(!app->handle) {
osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, dlerror() );
osrfLogSetAppname(appName);
+ osrfAppSetOnExit(app, appName);
+
return 0;
}
+
+void osrfAppSetOnExit(osrfApplication* app, char* appName) {
+ if(!(app && appName)) return;
+
+ /* see if we can run the initialize method */
+ char* error;
+ void (*onExit) (void);
+ *(void **) (&onExit) = dlsym(app->handle, "osrfAppChildExit");
+
+ if( (error = dlerror()) != NULL ) {
+ osrfLogDebug(OSRF_LOG_MARK, "No exit handler defined for %s", appName);
+ return;
+ }
+
+ osrfLogInfo(OSRF_LOG_MARK, "registering exit handler for %s", appName);
+ app->onExit = (*onExit);
+ //if( (ret = (*onExit)()) ) {
+}
+
+
int osrfAppRunChildInit(char* appname) {
osrfApplication* app = _osrfAppFindApplication(appname);
if(!app) return -1;
}
+void osrfAppRunExitCode() {
+ osrfHashIterator* itr = osrfNewHashIterator(__osrfAppHash);
+ osrfApplication* app;
+ while( (app = osrfHashIteratorNext(itr)) ) {
+ if( app->onExit ) {
+ osrfLogInfo(OSRF_LOG_MARK, "Running onExit handler for app %s", itr->current);
+ app->onExit();
+ }
+ }
+}
+
+
int osrfAppRegisterMethod( char* appName, char* methodName,
char* symbolName, char* notes, int argc, int options ) {
struct _osrfApplicationStruct {
void* handle; /* the lib handle */
osrfHash* methods;
+ void (*onExit) (void);
};
typedef struct _osrfApplicationStruct osrfApplication;
/**
* Tells the backend process to run its child init function */
int osrfAppRunChildInit(char* appname);
+void osrfAppSetOnExit(osrfApplication* app, char* appName);
+void osrfAppRunExitCode();
#include "osrf_list.h"
/* 0x100 is a good size for small hashes */
-#define OSRF_HASH_LIST_SIZE 0x100 /* size of the main hash list */
+//#define OSRF_HASH_LIST_SIZE 0x100 /* size of the main hash list */
+#define OSRF_HASH_LIST_SIZE 0x10 /* size of the main hash list */
+
/* used internally */
#define OSRF_HASH_NODE_FREE(h, n) \
osrfLogDebug( OSRF_LOG_MARK, "Child init hook for child %d", child->pid);
char* resc = va_list_to_string("%s_drone",child->appname);
+ /* if we're a source-client, tell the logger now that we're a new process*/
+ char* isclient = osrfConfigGetValue(NULL, "/client");
+ if( isclient && !strcasecmp(isclient,"true") )
+ osrfLogSetIsClient(1);
+ free(isclient);
+
+
/* we want to remove traces of our parents socket connection
* so we can have our own */
osrfSystemIgnoreTransportClient();
osrfLogError( OSRF_LOG_MARK,
"Unable to bootstrap client in prefork_child_process_request()");
sleep(1);
- exit(1);
+ osrf_prefork_child_exit(child);
}
}
if( prefork_child_init_hook(child) == -1 ) {
osrfLogError(OSRF_LOG_MARK,
"Forker child going away because we could not connect to OpenSRF...");
- exit(1);
+ osrf_prefork_child_exit(child);
}
prefork_child_wait( child );
- exit(0); /* just to be sure */
+ osrf_prefork_child_exit(child); /* just to be sure */
}
return NULL;
}
+void osrf_prefork_child_exit(prefork_child* child) {
+ osrfAppRunExitCode();
+ exit(0);
+}
void prefork_launch_children( prefork_simple* forker ) {
if(!forker) return;
if( errno == EAGAIN ) n = 0;
+ if( errno == EPIPE ) {
+ osrfLogWarning(OSRF_LOG_MARK, "C child attempted read on broken pipe, exiting...");
+ break;
+ }
+
if( n < 0 ) {
osrfLogWarning( OSRF_LOG_MARK, "Prefork child read returned error with errno %d", errno );
break;
osrfLogDebug( OSRF_LOG_MARK, "Child with max-requests=%d, num-served=%d exiting...[%d]",
child->max_requests, i, getpid() );
- exit(0);
+ osrf_prefork_child_exit(child); /* just to be sure */
}
void osrf_prefork_register_routers( char* appname );
-
+void osrf_prefork_child_exit( prefork_child* );
if(!msg) return NULL;
+ osrfLogSetXid(msg->osrf_xid);
+
osrfLogDebug( OSRF_LOG_MARK, "Transport handler received new message \nfrom %s "
"to %s with body \n\n%s\n", msg->sender, msg->recipient, msg->body );
char* domain = strdup(osrfStringArrayGetString( arr, 0 )); /* just the first for now */
osrfStringArrayFree(arr);
+ /* if we're a source-client, tell the logger */
+ char* isclient = osrfConfigGetValue(NULL, "/client");
+ if( isclient && !strcasecmp(isclient,"true") )
+ osrfLogSetIsClient(1);
+ free(isclient);
int llevel = 0;
int iport = 0;
xmlChar* router_to = xmlGetProp( root, BAD_CAST "router_to" );
xmlChar* router_class= xmlGetProp( root, BAD_CAST "router_class" );
xmlChar* broadcast = xmlGetProp( root, BAD_CAST "broadcast" );
+ xmlChar* osrf_xid = xmlGetProp( root, BAD_CAST "osrf_xid" );
+
+ if( osrf_xid ) {
+ message_set_osrf_xid( new_msg, (char*) osrf_xid);
+ xmlFree(osrf_xid);
+ }
if( router_from ) {
new_msg->sender = strdup((char*)router_from);
if( new_msg->body == NULL )
new_msg->body = strdup("");
- int bufsize;
- xmlChar* xmlbuf;
- char* encoded_body;
-
- xmlDocDumpFormatMemory( msg_doc, &xmlbuf, &bufsize, 0 );
- encoded_body = strdup( (char*) xmlbuf );
-
- if( encoded_body == NULL )
- osrfLogError(OSRF_LOG_MARK, "message_to_xml(): Out of Memory");
-
- xmlFree(xmlbuf);
- xmlFreeDoc(msg_doc);
- xmlCleanupParser();
-
- /*** remove the XML declaration */
- int len = strlen(encoded_body);
- char tmp[len];
- memset( tmp, 0, len );
- int i;
- int found_at = 0;
-
- /* when we reach the first >, take everything after it */
- for( i = 0; i!= len; i++ ) {
- if( encoded_body[i] == 62) { /* ascii > */
-
- /* found_at holds the starting index of the rest of the doc*/
- found_at = i + 1;
- break;
- }
- }
+ new_msg->msg_xml = xmlDocToString(msg_doc, 0);
+ xmlFreeDoc(msg_doc);
+ xmlCleanupParser();
- if( found_at ) {
- /* move the shortened doc into the tmp buffer */
- strncpy( tmp, encoded_body + found_at, len - found_at );
- /* move the tmp buffer back into the allocated space */
- memset( encoded_body, 0, len );
- strcpy( encoded_body, tmp );
- }
-
- new_msg->msg_xml = encoded_body;
return new_msg;
-
}
+void message_set_osrf_xid( transport_message* msg, char* osrf_xid ) {
+ if(!msg) return;
+ if( osrf_xid )
+ msg->osrf_xid = strdup(osrf_xid);
+ else msg->osrf_xid = strdup("");
+}
void message_set_router_info( transport_message* msg, char* router_from,
char* router_to, char* router_class, char* router_command, int broadcast_enabled ) {
free(msg->router_to);
free(msg->router_class);
free(msg->router_command);
+ free(msg->osrf_xid);
if( msg->error_type != NULL ) free(msg->error_type);
if( msg->msg_xml != NULL ) free(msg->msg_xml);
free(msg);
xmlNewProp( message_node, BAD_CAST "router_to", BAD_CAST msg->router_to );
xmlNewProp( message_node, BAD_CAST "router_class", BAD_CAST msg->router_class );
xmlNewProp( message_node, BAD_CAST "router_command", BAD_CAST msg->router_command );
+ xmlNewProp( message_node, BAD_CAST "osrf_xid", BAD_CAST msg->osrf_xid );
if( msg->broadcast )
xmlNewProp( message_node, BAD_CAST "broadcast", BAD_CAST "1" );
#include <libxml/xmlmemory.h>
#include "opensrf/utils.h"
+#include "opensrf/xml_utils.h"
#include "opensrf/log.h"
#ifndef TRANSPORT_MESSAGE_H
char* router_to;
char* router_class;
char* router_command;
+ char* osrf_xid;
int is_error;
char* error_type;
int error_code;
void message_set_router_info( transport_message* msg, char* router_from,
char* router_to, char* router_class, char* router_command, int broadcast_enabled );
+void message_set_osrf_xid( transport_message* msg, char* osrf_xid );
+
// ---------------------------------------------------------------------------------
// Formats the Jabber message as XML for encoding.
// Returns NULL on error
/* for OpenSRF extensions */
session->router_to_buffer = buffer_init( JABBER_JID_BUFSIZE );
session->router_from_buffer = buffer_init( JABBER_JID_BUFSIZE );
+ session->osrf_xid_buffer = buffer_init( JABBER_JID_BUFSIZE );
session->router_class_buffer = buffer_init( JABBER_JID_BUFSIZE );
session->router_command_buffer = buffer_init( JABBER_JID_BUFSIZE );
buffer_free(session->message_error_type);
buffer_free(session->router_to_buffer);
buffer_free(session->router_from_buffer);
+ buffer_free(session->osrf_xid_buffer);
buffer_free(session->router_class_buffer);
buffer_free(session->router_command_buffer);
buffer_free(session->session_id);
buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) );
buffer_add( ses->recipient_buffer, get_xml_attr( atts, "to" ) );
buffer_add( ses->router_from_buffer, get_xml_attr( atts, "router_from" ) );
+ buffer_add( ses->osrf_xid_buffer, get_xml_attr( atts, "osrf_xid" ) );
buffer_add( ses->router_to_buffer, get_xml_attr( atts, "router_to" ) );
buffer_add( ses->router_class_buffer, get_xml_attr( atts, "router_class" ) );
buffer_add( ses->router_command_buffer, get_xml_attr( atts, "router_command" ) );
ses->router_command_buffer->buf,
ses->router_broadcast );
+ message_set_osrf_xid( msg, ses->osrf_xid_buffer->buf );
+
if( ses->message_error_type->n_used > 0 ) {
set_msg_error( msg, ses->message_error_type->buf, ses->message_error_code );
}
buffer_reset( ses->from_buffer );
buffer_reset( ses->recipient_buffer );
buffer_reset( ses->router_from_buffer );
+ buffer_reset( ses->osrf_xid_buffer );
buffer_reset( ses->router_to_buffer );
buffer_reset( ses->router_class_buffer );
buffer_reset( ses->router_command_buffer );
growing_buffer* router_from_buffer;
growing_buffer* router_class_buffer;
growing_buffer* router_command_buffer;
+ growing_buffer* osrf_xid_buffer;
int router_broadcast;
/* this can be anything. It will show up in the
char* ret = "json_parse_json_bool(): truncated bool";
- if( *index >= (current_strlen - 5))
+ if( *index > (current_strlen - 4))
return json_handle_error(string, index, ret);
-
- if(!strncasecmp( string + (*index), "false", 5)) {
- (*index) += 5;
- obj->value.b = 0;
+
+ if(!strncasecmp( string + (*index), "true", 4)) {
+ (*index) += 4;
+ obj->value.b = 1;
obj->type = JSON_BOOL;
return 0;
}
- if( *index >= (current_strlen - 4))
+ if( *index > (current_strlen - 5))
return json_handle_error(string, index, ret);
-
- if(!strncasecmp( string + (*index), "true", 4)) {
- (*index) += 4;
- obj->value.b = 1;
+
+ if(!strncasecmp( string + (*index), "false", 5)) {
+ (*index) += 5;
+ obj->value.b = 0;
obj->type = JSON_BOOL;
return 0;
}
/* ----------------------------------------------------------------------- */
/* The following chunk was borrowed with permission from
json-c http://oss.metaparadigm.com/json-c/ */
- unsigned char utf_out[3];
- memset(utf_out,0,3);
+ unsigned char utf_out[4];
+ memset(utf_out,0,4);
#define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
}
+int jsonBoolIsTrue( const jsonObject* o ) {
+ return (o && o->type == JSON_BOOL && o->value.b);
+}
+
+
*/
char* jsonObjectToSimpleString( const jsonObject* o );
+int jsonBoolIsTrue( const jsonObject* o );
+
/* ------------------------------------------------------------------------ */
/* XPATH */
my $meth = shift;
return unless $self;
+ # tell the logger to create a new xid - the logger will decide if it's really necessary
+ $logger->mk_osrf_xid;
+
my $method;
if (!ref $meth) {
$method = new OpenSRF::DomainObject::oilsMethod ( method => $meth );
}
}
- $logger->debug( "AppSession sending doc: " . JSON->perl2JSON(\@doc), INTERNAL );
-
+ my $json = JSON->perl2JSON(\@doc);
+ $logger->internal("AppSession sending doc: $json");
$self->{peer_handle}->send(
to => $self->remote_id,
thread => $self->session_id,
- body => JSON->perl2JSON(\@doc) );
+ body => $json );
if( $disconnect) {
$self->state( DISCONNECTED );
use Time::HiRes qw/time/;
use OpenSRF::EX qw/:try/;
use Carp;
+use JSON;
#use OpenSRF::UnixServer; # to get the server class from UnixServer::App
sub DESTROY{};
}
my $start = time();
- warn "About to run...\n";
$resp = $coderef->run( $appreq, @args);
- warn "Done running...\n";
my $time = sprintf '%.3f', time() - $start;
$log->debug( "Method duration for [$method_name]: ". $time );
package OpenSRF::Application::Settings;
use OpenSRF::Application;
use OpenSRF::Utils::SettingsParser;
+use OpenSRF::Utils::Logger qw/$logger/;
use base 'OpenSRF::Application';
+sub child_exit {
+ $logger->debug("settings server child exiting...$$");
+}
__PACKAGE__->register_method( method => 'get_host_config', api_name => 'opensrf.settings.host_config.get' );
my $body = $helper->get_body();
my $type = $helper->get_msg_type();
+ $logger->set_osrf_xid($helper->get_osrf_xid);
if (defined($type) and $type eq 'error') {
throw OpenSRF::EX::Session ("$remote_id IS NOT CONNECTED TO THE NETWORK!!!");
$msg->setBody( $body );
$msg->set_router_command( $router_command );
$msg->set_router_class( $router_class );
-
+ $msg->set_osrf_xid($logger->get_osrf_xid);
$logger->transport(
"JabberClient Sending message to $to with thread $thread and body: \n$body", INTERNAL );
}
}
+sub set_osrf_xid {
+ my( $self, $xid ) = @_;
+ $self->{msg_node}->setAttribute( osrf_xid => $xid );
+}
+
+
+sub get_osrf_xid {
+ my $self = shift;
+ $self->{msg_node}->getAttribute('osrf_xid');
+}
+
+
1;
use strict; use warnings;
use base qw/OpenSRF/;
use OpenSRF::EX qw(:try);
-use OpenSRF::Utils::Logger qw(:level);
+use OpenSRF::Utils::Logger qw(:level $logger);
use OpenSRF::Transport::PeerHandle;
use OpenSRF::Application;
use OpenSRF::AppSession;
use IO::Socket::INET;
use IO::Socket::UNIX;
-# XXX Need to add actual logging statements in the code
-my $logger = "OpenSRF::Utils::Logger";
-
sub DESTROY { confess "Dying $$"; }
-
=head1 What am I
All inbound messages are passed on to the UnixServer for processing.
return OpenSRF::Application->application_implementation;
}
-sub child_finish_hook {
- my $self = shift;
-}
-
sub child_init_hook {
$0 =~ s/master/drone/g;
return OpenSRF::Transport::PeerHandle->retrieve;
}
+sub child_finish_hook {
+ $logger->debug("attempting to call child exit handler...");
+ OpenSRF::Application->application_implementation->child_exit
+ if (OpenSRF::Application->application_implementation->can('child_exit'));
+}
+
+
1;
sub INTERNAL { return 5; }
sub ALL { return 100; }
+my $isclient; # true if we control the osrf_xid
+
# load up our config options
sub set_config {
} else { $actfile = "$logdir/$actfile"; }
- #warn "Level: $loglevel, Fac: $facility, Act: $actfac\n";
+ $isclient = (OpenSRF::Utils::Config->current->bootstrap->client =~ /^true$/iog) ? 1 : 0;
}
sub _fac_to_const {
}
+# ----------------------------------------------------------------------
+# creates a new xid if necessary
+# ----------------------------------------------------------------------
+my $osrf_xid = '';
+my $osrf_xid_inc = 0;
+sub mk_osrf_xid {
+ return unless $isclient;
+ $osrf_xid_inc++;
+ return $osrf_xid = "$^T${$}$osrf_xid_inc";
+}
+
+sub set_osrf_xid {
+ return if $isclient; # if we're a client, we control our xid
+ $osrf_xid = $_[1];
+}
+
+sub get_osrf_xid { return $osrf_xid; }
+# ----------------------------------------------------------------------
+
sub _log_message {
my( $msg, $level ) = @_;
return if $level > $loglevel;
elsif ($level == INTERNAL()) {$l = LOG_DEBUG; $n = "INTL"; }
elsif ($level == ACTIVITY()) {$l = LOG_INFO; $n = "ACT"; $fac = $actfac; }
- #my( $pack, $file, $line_no ) = @caller;
+ my( undef, $file, $line_no ) = caller(1);
+ $file =~ s#/.*/##og;
# help syslog with the formatting
$msg =~ s/\%/\%\%/gso if( is_act_syslog() or is_syslog() );
- $msg = "[$n:"."$$".":::] $msg";
+ $msg = "[$n:"."$$".":$file:$line_no:$osrf_xid] $msg";
$msg = substr($msg, 0, 1536);
while( (msg = client_recv( class->connection, 0 )) ) {
+ osrfLogSetXid(msg->osrf_xid);
+
if( msg->sender ) {
osrfLogDebug(OSRF_LOG_MARK,
}
}
+ osrfLogClearXid();
message_free( msg );
}
transport_message* error = message_init(
node->lastMessage->body, node->lastMessage->subject,
node->lastMessage->thread, node->lastMessage->router_from, node->lastMessage->recipient );
+ message_set_osrf_xid(error, node->lastMessage->osrf_xid);
set_msg_error( error, "cancel", 501 );
/* send the error message back to the original sender */
lastSent = message_init( node->lastMessage->body,
node->lastMessage->subject, node->lastMessage->thread, "", node->lastMessage->router_from );
message_set_router_info( lastSent, node->lastMessage->router_from, NULL, NULL, NULL, 0 );
+ message_set_osrf_xid( lastSent, node->lastMessage->osrf_xid );
}
} else {
transport_message* new_msg= message_init( msg->body,
msg->subject, msg->thread, node->remoteId, msg->sender );
message_set_router_info( new_msg, msg->sender, NULL, NULL, NULL, 0 );
+ message_set_osrf_xid( new_msg, msg->osrf_xid );
osrfLogInfo( OSRF_LOG_MARK, "Routing message:\nfrom: [%s]\nto: [%s]",
new_msg->router_from, new_msg->recipient );
while( (node = osrfHashIteratorNext(rclass->itr)) )
osrfRouterClassRemoveNode( rclass->router, classname, node->remoteId );
+ osrfHashIteratorFree(rclass->itr);
+ osrfHashFree(rclass->nodes);
+
free(rclass);
}
char* __osrfLogAppname = NULL;
int __osrfLogLevel = OSRF_LOG_INFO;
int __osrfLogActivityEnabled = 1;
+int __osrfLogIsClient = 0;
+
+
+int __osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
+char* __osrfLogXid = NULL; /* current xid */
+char* __osrfLogXidPfx = NULL; /* xid prefix string */
void osrfLogCleanup() {
openlog(__osrfLogAppname, 0, __osrfLogFacility );
}
+static void __osrfLogSetXid(char* xid) {
+ if(xid) {
+ if(__osrfLogXid) free(__osrfLogXid);
+ __osrfLogXid = strdup(xid);
+ }
+}
+
+void osrfLogClearXid() { __osrfLogSetXid(""); }
+void osrfLogSetXid(char* xid) {
+ if(!__osrfLogIsClient) __osrfLogSetXid(xid);
+}
+
+void osrfLogMkXid() {
+ if(__osrfLogIsClient) {
+ char buf[32];
+ memset(buf, 0x0, 32);
+ snprintf(buf, 32, "%s%d", __osrfLogXidPfx, __osrfLogXidInc);
+ __osrfLogSetXid(buf);
+ __osrfLogXidInc++;
+ }
+}
+
+char* osrfLogGetXid() {
+ return __osrfLogXid;
+}
+
+void osrfLogSetIsClient(int is) {
+ __osrfLogIsClient = is;
+ if(!is) return;
+ /* go ahead and create the xid prefix so it will be consistent later */
+ static char buff[32];
+ memset(buff, 0x0, 32);
+ snprintf(buff, 32, "%d%d", (int)time(NULL), getpid());
+ __osrfLogXidPfx = buff;
+}
+
void osrfLogSetType( int logtype ) {
if( logtype != OSRF_LOG_TYPE_FILE &&
logtype != OSRF_LOG_TYPE_SYSLOG ) {
break;
}
+ char* xid = (__osrfLogXid) ? __osrfLogXid : "";
+
if(__osrfLogType == OSRF_LOG_TYPE_SYSLOG ) {
char buf[1536];
memset(buf, 0x0, 1536);
buf[1533] = '.';
buf[1534] = '.';
buf[1535] = '\0';
- syslog( fac | lvl, "[%s:%d:%s:%d] %s", l, getpid(), filename, line, buf );
+ syslog( fac | lvl, "[%s:%d:%s:%d:%s] %s", l, getpid(), filename, line, xid, buf );
}
else if( __osrfLogType == OSRF_LOG_TYPE_FILE )
- _osrfLogToFile("[%s:%d:%s:%d] %s", l, getpid(), filename, line, msg );
+ _osrfLogToFile("[%s:%d:%s:%d:%s] %s", l, getpid(), filename, line, xid, msg );
}
void osrfLogCleanup();
+void osrfLogClearXid();
+void osrfLogSetXid(char* xid);
+void osrfLogMkXid();
+void osrfLogSetIsClient(int is);
+char* osrfLogGetXid();
+
/* sets the activity flag */
void osrfLogSetActivityEnabled( int enabled );
#include "utils.h"
#include <errno.h>
-
inline void* safe_malloc( int size ) {
void* ptr = (void*) malloc( size );
if( ptr == NULL ) {
char* uescape( const char* string, int size, int full_escape ) {
growing_buffer* buf = buffer_init(size + 64);
+ int clen = 0;
int idx = 0;
- long unsigned int c = 0;
+ unsigned long int c = 0x0;
while (string[idx]) {
-
- c ^= c;
-
- if ((string[idx] & 0xF0) == 0xF0) {
- c = string[idx]<<18;
-
- if( size - idx < 4 ) return NULL;
-
- idx++;
- c |= (string[idx] & 0x3F)<<12;
-
- idx++;
- c |= (string[idx] & 0x3F)<<6;
-
- idx++;
- c |= (string[idx] & 0x3F);
-
- c ^= 0xFF000000;
-
- buffer_fadd(buf, "\\u%0.4x", c);
-
- } else if ((string[idx] & 0xE0) == 0xE0) {
- c = string[idx]<<12;
- if( size - idx < 3 ) return NULL;
-
- idx++;
- c |= (string[idx] & 0x3F)<<6;
-
- idx++;
- c |= (string[idx] & 0x3F);
-
- c ^= 0xFFF80000;
-
- buffer_fadd(buf, "\\u%0.4x", c);
-
- } else if ((string[idx] & 0xC0) == 0xC0) {
- // Two byte char
- c = string[idx]<<6;
- if( size - idx < 2 ) return NULL;
-
- idx++;
- c |= (string[idx] & 0x3F);
-
- c ^= 0xFFFFF000;
-
- buffer_fadd(buf, "\\u%0.4x", c);
+
+ c = 0x0;
+
+ if ((unsigned char)string[idx] >= 0x80) { // not ASCII
+
+ if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
+
+ clen = 1;
+ if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
+ clen = 3;
+ c = (unsigned char)string[idx] ^ 0xF0;
+
+ } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
+ clen = 2;
+ c = (unsigned char)string[idx] ^ 0xE0;
+
+ } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
+ clen = 1;
+ c = (unsigned char)string[idx] ^ 0xC0;
+ }
+
+ for (;clen;clen--) {
+
+ idx++; // look at the next byte
+ c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
+
+ }
+
+ buffer_fadd(buf, "\\u%04x", c);
+
+ } else {
+ return NULL;
+ }
} else {
c = string[idx];
OSRF_BUFFER_ADD_CHAR(buf, '\\');
break;
- case 30: /* record separator */
- OSRF_BUFFER_ADD(buf, "\\u001E");
- break;
-
- case 1: /* record separator */
- OSRF_BUFFER_ADD(buf, "\\u0001");
- break;
-
-
default:
- OSRF_BUFFER_ADD_CHAR(buf, c);
+ if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
+ else OSRF_BUFFER_ADD_CHAR(buf, c);
}
} else {
CONFIG_FILE="install.conf";
DEFAULT_CONFIG_FILE="install.conf.default";
+USE_DEFAULT="$1";
function buildConfig {
fi;
fi;
+ if [ -n "$USE_DEFAULT" ]; then
+ prompt "Default config requested, not prompting for values...\n";
+ writeConfig;
+ return 0;
+ fi;
+
echo "";
echo "-----------------------------------------------------------------------";
XSLDIR="$PREFIX/var/xsl";
REPORTERDIR="$PREFIX/var/reporter";
TMP="$(pwd)/.tmp";
-
- prompt "Web domain for OPAC in Staff Client [$NEW_OPAC_URL] "
- read X; if [ ! -z "$X" ]; then NEW_OPAC_URL="$X"; fi;
-
- prompt "Package Name for Staff Client [$NEW_XUL_PACKAGE_NAME] "
- read X; if [ ! -z "$X" ]; then NEW_XUL_PACKAGE_NAME="$X"; fi;
-
- prompt "Package Label for Staff Client [$NEW_XUL_PACKAGE_LABEL] "
- read X; if [ ! -z "$X" ]; then NEW_XUL_PACKAGE_LABEL="$X"; fi;
+ ADMINDIR="$PREFIX/var/admin";
prompt "Apache2 apxs binary [$APXS2] "
read X; if [ ! -z "$X" ]; then APXS2="$X"; fi;
writeConfig;
}
-function prompt { echo ""; echo -n "$*"; }
+function prompt { echo ""; echo -en "$*"; }
function writeConfig {
_write "PENALTYRULESDIR=\"$PENALTYRULESDIR\"";
_write "XSLDIR=\"$XSLDIR\"";
- _write "NEW_OPAC_URL=\"$NEW_OPAC_URL\"";
- _write "NEW_XUL_PACKAGE_NAME=\"$NEW_XUL_PACKAGE_NAME\"";
- _write "NEW_XUL_PACKAGE_LABEL=\"$NEW_XUL_PACKAGE_LABEL\"";
-
# print out the targets
STR="TARGETS=(";
for target in ${TARGETS[@]:0}; do
_write "DBUSER=\"$DBUSER\"";
_write "DBPW=\"$DBPW\"";
_write "REPORTERDIR=\"$REPORTERDIR\"";
+ _write "ADMINDIR=\"$ADMINDIR\"";
# Now we'll write out the DB bootstrapping config
# If you only want to build the client app, then just build evergreen_xul_client.
# --------------------------------------------------------------------
-TARGETS=("opensrf_all" "openils_all" "evergreen_core");
+TARGETS=("opensrf_all" "openils_core" "openils_web" "evergreen_core");
# --------------------------------------------------------------------
# to the published API.
# --------------------------------------------------------------------
-APXS2="/opt/bin/apxs";
+APXS2="/usr/bin/apxs2";
# --------------------------------------------------------------------
# be set when building the mod_ils_gateway C plugin for allowing web
# access to the published API.
# --------------------------------------------------------------------
-APACHE2_HEADERS="/opt/include/";
-APR_HEADERS="/opt/include/";
+APACHE2_HEADERS="/usr/include/apache2";
+APR_HEADERS="/usr/include/apr-1.0/";
# --------------------------------------------------------------------
WEBDIR=$WEBDIR TEMPLATEDIR=$TEMPLATEDIR ETCDIR=$ETCDIR REPORTERDIR=$REPORTERDIR\
OPENSRFDIR=$OPENSRFDIR OPENILSDIR=$OPENILSDIR EVERGREENDIR=$EVERGREENDIR \
CIRCRULESDIR=$CIRCRULESDIR CATALOGSCRIPTDIR=$CATALOGSCRIPTDIR CGIDIR=$CGIDIR \
- DBDRVR=$DBDRVR DBHOST=$DBHOST DATADIR=$DATADIR\
+ DBDRVR=$DBDRVR DBHOST=$DBHOST DATADIR=$DATADIR ADMINDIR=$ADMINDIR\
PENALTYRULESDIR=$PENALTYRULESDIR DBNAME=$DBNAME DBUSER=$DBUSER DBPW=$DBPW XSLDIR=$XSLDIR NEW_OPAC_URL=$NEW_OPAC_URL \
NEW_XUL_PACKAGE_NAME=$NEW_XUL_PACKAGE_NAME NEW_XUL_PACKAGE_LABEL=$NEW_XUL_PACKAGE_LABEL";