);
}
+__PACKAGE__->register_method(
+ method => "generate_patron_barcode",
+ api_name => "open-ils.actor.generate_patron_barcode",
+ signature => {
+ desc => "Generates a new patron barcode. If a user ID is supplied," .
+ "that user's card will be updated to point at the new barcode." ,
+ params => [
+ {desc => 'Authentication token', type => 'string'},
+ {desc => 'User ID', type => 'number'},
+ {desc => 'prefix', type => 'string'},
+ ],
+ return => {desc => 'Generated barcode on success'}
+ }
+);
+
+# evergreen.actor_update_barcode(user_id[, prefix]) generates a barcode, creates
+# an actor.card object, and points actor.usr.card to the new actor.card.id;
+# prefix is an optional prefix for the barcode
+#
+# evergreen.actor_generate_barcode([prefix]) just generates a barcode, with
+# prefix as an optional prefix for the barcode
+sub generate_patron_barcode {
+
+ my( $self, $client, $auth, $user_id, $prefix ) = @_;
+
+ my $e = new_editor( authtoken=>$auth );
+ return $e->die_event unless $e->checkauth;
+
+ my $barcode;
+ if ($user_id) {
+ return $e->die_event unless $e->allowed('UPDATE_USER');
+ my $args = ['evergreen.actor_update_barcode', $user_id];
+ if ($prefix) {
+ push @$args, $prefix;
+ }
+ $barcode = $e->json_query(
+ {from => $args})->[0]
+ or return $e->die_event;
+ } else {
+ my $args = ['evergreen.actor_generate_barcode'];
+ if ($prefix) {
+ push @$args, $prefix;
+ }
+ $barcode = $e->json_query(
+ {from => $args})->[0]
+ or return $e->die_event;
+ }
+
+ return $barcode;
+}
+
# Putting the following method in open-ils.actor is a bad fit, except in that
# it serves an interface that lives under 'actor' in the templates directory,
# and in that there's nowhere else obvious to put it (open-ils.trigger is
--- /dev/null
+-- Provides support for generating patron barcodes, with optional prefixes
+-- If all digits, then a mod10 check digit is calculated and appended
+CREATE SEQUENCE evergreen.actor_barcode_seq;
+
+CREATE OR REPLACE FUNCTION evergreen.mod10(barcode TEXT)
+RETURNS TEXT AS $$
+use strict;
+use warnings;
+
+my $barcode = shift;
+my $total = 0;
+my $position = 0;
+foreach my $digit (split('', $barcode)) {
+ $digit = sprintf('%d', $digit);
+ $position++;
+ if ($position % 2) {
+ # Double it
+ $digit *= 2;
+ # If less than 10, add to the total
+ if ($digit < 10) {
+ $total += $digit;
+ } else {
+ $total += $digit - 9;
+ }
+ } else {
+ $total += $digit;
+ }
+}
+my $rem = $total % 10;
+if ($rem) {
+ return 10 - $rem;
+}
+return $rem;
+$$ LANGUAGE plperlu;
+
+CREATE OR REPLACE FUNCTION evergreen.actor_generate_barcode(prefix TEXT DEFAULT 'AUTOBC')
+RETURNS TEXT AS $$
+DECLARE
+ bc_gen TEXT;
+ mod TEXT;
+ bc_serial RECORD;
+ bc_holder TEXT;
+BEGIN
+ LOOP
+ SELECT lpad(NEXTVAL('evergreen.actor_barcode_seq')::text, 7, '0') AS bc INTO bc_serial;
+ bc_gen := rpad(COALESCE(prefix, '0'), 6, '0') || bc_serial.bc::text;
+ IF unnest(regexp_matches(bc_gen, '\D')) IS NOT NULL THEN
+ bc_gen := rpad(bc_gen, 14, '0');
+ ELSE
+ bc_gen := bc_gen || evergreen.mod10(bc_gen);
+ END IF;
+
+ SELECT barcode INTO bc_holder FROM actor.card WHERE barcode = bc_gen;
+ EXIT WHEN bc_holder IS NULL;
+ END LOOP;
+
+ RETURN bc_gen;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION evergreen.actor_update_barcode(usr_id INT, prefix TEXT DEFAULT NULL)
+RETURNS TEXT AS $$
+DECLARE
+ bc_gen TEXT;
+ bc_holder TEXT;
+BEGIN
+
+ LOOP
+ IF prefix IS NULL THEN
+ bc_gen := evergreen.actor_generate_barcode();
+ ELSE
+ bc_gen := evergreen.actor_generate_barcode(prefix);
+ END IF;
+
+ SELECT barcode INTO bc_holder FROM actor.card WHERE barcode = bc_gen;
+ EXIT WHEN bc_holder IS NULL;
+ END LOOP;
+
+ INSERT INTO actor.card (usr, barcode) VALUES (usr_id, bc_gen);
+
+ UPDATE actor.usr
+ SET card = CURRVAL('actor.card_id_seq')
+ WHERE id = usr_id;
+
+ RETURN bc_gen;
+END;
+$$ LANGUAGE plpgsql;