+ # and get all fields from the table
+# my $columns = $columns{$table};
+# unless ($columns) {
+# $columns = $columns{$table} = C4::Context->dbh->selectcol_arrayref("SHOW COLUMNS FROM $table");
+# }
+# foreach my $field (@$columns) {
+
+ while ( my ($field, $val) = each %$values ) {
+ my $replacetablefield = "<<$table.$field>>";
+ my $replacefield = "<<$field>>";
+ $val =~ s/\p{P}(?=$)//g if $val;
+ my $replacedby = defined ($val) ? $val : '';
+ ($letter->{title} ) and do {
+ $letter->{title} =~ s/$replacetablefield/$replacedby/g;
+ $letter->{title} =~ s/$replacefield/$replacedby/g;
+ };
+ ($letter->{content}) and do {
+ $letter->{content} =~ s/$replacetablefield/$replacedby/g;
+ $letter->{content} =~ s/$replacefield/$replacedby/g;
+ };
+ }
+
+ if ($table eq 'borrowers' && $letter->{content}) {
+ if ( my $attributes = GetBorrowerAttributes($values->{borrowernumber}) ) {
+ my %attr;
+ foreach (@$attributes) {
+ my $code = $_->{code};
+ my $val = $_->{value_description} || $_->{value};
+ $val =~ s/\p{P}(?=$)//g if $val;
+ next unless $val gt '';
+ $attr{$code} ||= [];
+ push @{ $attr{$code} }, $val;
+ }
+ while ( my ($code, $val_ar) = each %attr ) {
+ my $replacefield = "<<borrower-attribute:$code>>";
+ my $replacedby = join ',', @$val_ar;
+ $letter->{content} =~ s/$replacefield/$replacedby/g;
+ }
+ }
+ }
+ return $letter;
+}
+
+=head2 EnqueueLetter
+
+ my $success = EnqueueLetter( { letter => $letter,
+ borrowernumber => '12', message_transport_type => 'email' } )
+
+places a letter in the message_queue database table, which will
+eventually get processed (sent) by the process_message_queue.pl
+cronjob when it calls SendQueuedMessages.
+
+return true on success
+
+=cut
+
+sub EnqueueLetter ($) {
+ my $params = shift or return undef;
+
+ return unless exists $params->{'letter'};
+ return unless exists $params->{'borrowernumber'};
+ return unless exists $params->{'message_transport_type'};
+
+ # If we have any attachments we should encode then into the body.
+ if ( $params->{'attachments'} ) {
+ $params->{'letter'} = _add_attachments(
+ { letter => $params->{'letter'},
+ attachments => $params->{'attachments'},
+ message => MIME::Lite->new( Type => 'multipart/mixed' ),
+ }
+ );
+ }
+
+ my $dbh = C4::Context->dbh();
+ my $statement = << 'ENDSQL';
+INSERT INTO message_queue
+( borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, content_type )
+VALUES
+( ?, ?, ?, ?, ?, ?, ?, NOW(), ?, ?, ? )
+ENDSQL
+
+ my $sth = $dbh->prepare($statement);
+ my $result = $sth->execute(
+ $params->{'borrowernumber'}, # borrowernumber
+ $params->{'letter'}->{'title'}, # subject
+ $params->{'letter'}->{'content'}, # content
+ $params->{'letter'}->{'metadata'} || '', # metadata
+ $params->{'letter'}->{'code'} || '', # letter_code
+ $params->{'message_transport_type'}, # message_transport_type
+ 'pending', # status
+ $params->{'to_address'}, # to_address
+ $params->{'from_address'}, # from_address
+ $params->{'letter'}->{'content-type'}, # content_type
+ );
+ return $result;
+}
+
+=head2 SendQueuedMessages ([$hashref])
+
+ my $sent = SendQueuedMessages( { verbose => 1 } );
+
+sends all of the 'pending' items in the message queue.
+
+returns number of messages sent.
+
+=cut
+
+sub SendQueuedMessages (;$) {
+ my $params = shift;
+
+ my $unsent_messages = _get_unsent_messages();
+ MESSAGE: foreach my $message ( @$unsent_messages ) {
+ # warn Data::Dumper->Dump( [ $message ], [ 'message' ] );
+ warn sprintf( 'sending %s message to patron: %s',
+ $message->{'message_transport_type'},
+ $message->{'borrowernumber'} || 'Admin' )
+ if $params->{'verbose'} or $debug;
+ # This is just begging for subclassing
+ next MESSAGE if ( lc($message->{'message_transport_type'}) eq 'rss' );
+ if ( lc( $message->{'message_transport_type'} ) eq 'email' ) {
+ _send_message_by_email( $message, $params->{'username'}, $params->{'password'}, $params->{'method'} );
+ }
+ elsif ( lc( $message->{'message_transport_type'} ) eq 'sms' ) {
+ _send_message_by_sms( $message );
+ }
+ }
+ return scalar( @$unsent_messages );
+}
+
+=head2 GetRSSMessages
+
+ my $message_list = GetRSSMessages( { limit => 10, borrowernumber => '14' } )
+
+returns a listref of all queued RSS messages for a particular person.
+
+=cut
+
+sub GetRSSMessages {
+ my $params = shift;
+
+ return unless $params;
+ return unless ref $params;
+ return unless $params->{'borrowernumber'};
+
+ return _get_unsent_messages( { message_transport_type => 'rss',
+ limit => $params->{'limit'},
+ borrowernumber => $params->{'borrowernumber'}, } );
+}
+
+=head2 GetPrintMessages
+
+ my $message_list = GetPrintMessages( { borrowernumber => $borrowernumber } )
+
+Returns a arrayref of all queued print messages (optionally, for a particular
+person).
+
+=cut
+
+sub GetPrintMessages {
+ my $params = shift || {};
+
+ return _get_unsent_messages( { message_transport_type => 'print',
+ borrowernumber => $params->{'borrowernumber'}, } );
+}
+
+=head2 GetQueuedMessages ([$hashref])
+
+ my $messages = GetQueuedMessage( { borrowernumber => '123', limit => 20 } );
+
+fetches messages out of the message queue.
+
+returns:
+list of hashes, each has represents a message in the message queue.
+
+=cut
+
+sub GetQueuedMessages {
+ my $params = shift;
+
+ my $dbh = C4::Context->dbh();
+ my $statement = << 'ENDSQL';
+SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued
+FROM message_queue
+ENDSQL
+
+ my @query_params;
+ my @whereclauses;
+ if ( exists $params->{'borrowernumber'} ) {
+ push @whereclauses, ' borrowernumber = ? ';
+ push @query_params, $params->{'borrowernumber'};