3 # Copyright Liblime 2009
4 # Copyright Catalyst IT 2012
6 # This file is part of Koha.
8 # Koha is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # Koha is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with Koha; if not, see <http://www.gnu.org/licenses>.
25 use C4::Letters qw( GetPreparedLetter EnqueueLetter );
26 use YAML::XS qw( Dump );
32 C4::Message - object for messages in the message_queue table
36 How to add a new message to the queue:
40 my $borrower = { borrowernumber => 1 };
41 my $item = Koha::Items->find($itemnumber)->unblessed;
42 my $letter = C4::Letters::GetPreparedLetter (
43 module => 'circulation',
44 letter_code => 'CHECKOUT',
45 branchcode => $branch,
47 'biblio', $item->{biblionumber},
48 'biblioitems', $item->{biblionumber},
51 C4::Message->enqueue($letter, $borrower->{borrowernumber}, 'email');
53 How to update a borrower's last checkout message:
56 my $borrower = { borrowernumber => 1 };
57 my $message = C4::Message->find_last_message($borrower, 'CHECKOUT', 'email');
58 $message->append("you also checked out some other book....");
63 This module presents an OO interface to the message_queue. Previously,
64 you could only add messages to the message_queue via
65 C<C4::Letters::EnqueueMessage()>. With this module, you can also get
66 previously inserted messages, manipulate them, and save them back to the
77 =head3 C4::Message->new(\%attributes)
79 This method creates an in-memory version of a message object.
83 # C4::Message->new(\%attributes) -- constructor
85 my ($class, $opts) = @_;
87 bless {%$opts} => $class;
91 =head3 C4::Message->find($id)
93 This method searches the message_queue table for a row with the given
94 C<message_id> and it'll return a C4::Message object if it finds one.
98 # C4::Message->find($id) -- find a message by its message_id
100 my ($class, $id) = @_;
101 my $dbh = C4::Context->dbh;
102 my $msgs = $dbh->selectall_arrayref(
103 qq{SELECT * FROM message_queue WHERE message_id = ?},
108 return $class->new($msgs->[0]);
114 =head3 C4::Message->find_last_message($borrower, $letter_code, $transport)
116 This method is used to get the borrower's most recent, pending, check-in or
117 checkout message. (This makes it possible to add more information to the
118 message before it gets sent out.)
122 # C4::Message->find_last_message($borrower, $letter_code, $transport)
123 # -- get the borrower's most recent pending checkin or checkout notification
124 sub find_last_message {
125 my ($class, $borrower, $letter_code, $transport) = @_;
126 # $type is the message_transport_type
127 $transport ||= 'email';
128 my $dbh = C4::Context->dbh;
129 my $msgs = $dbh->selectall_arrayref(
133 WHERE status = 'pending'
134 AND borrowernumber = ?
136 AND message_transport_type = ?
139 $borrower->{borrowernumber},
144 return $class->new($msgs->[0]);
151 =head3 C4::Message->enqueue($letter, $borrower, $transport)
153 This is a front-end for C<C4::Letters::EnqueueLetter()> that adds metadata to
158 # C4::Message->enqueue($letter, $borrower, $transport)
160 my ($class, $letter, $borrower, $transport) = @_;
161 my $metadata = _metadata($letter);
162 my $to_address = _to_address($borrower, $transport);
164 # Same as render_metadata
165 my $format ||= sub { $_[0] || "" };
166 my $body = join('', map { $format->($_) } @{$metadata->{body}});
167 $letter->{content} = $metadata->{header} . $body . $metadata->{footer};
169 $letter->{metadata} = Encode::decode_utf8(Dump($metadata));
170 C4::Letters::EnqueueLetter({
172 borrowernumber => $borrower->{borrowernumber},
173 message_transport_type => $transport,
174 to_address => $to_address,
178 # based on message $transport, pick an appropriate address to send to
180 my ($borrower, $transport) = @_;
182 if ($transport eq 'email') {
183 $address = $borrower->{email}
184 || $borrower->{emailpro}
185 || $borrower->{B_email};
186 } elsif ($transport eq 'sms') {
187 $address = $borrower->{smsalertnumber};
189 warn "'$transport' is an unknown message transport.";
191 if (not defined $address) {
192 warn "An appropriate $transport address "
193 . "for borrower $borrower->{userid} "
194 . "could not be found.";
199 # _metadata($letter) -- return the letter split into head/body/footer
202 if ($letter->{content} =~ /----/) {
203 my ($header, $body, $footer) = split(/----\r?\n?/, $letter->{content});
212 body => [$letter->{content}],
218 =head2 Instance Methods
220 =head3 $message->update()
222 This saves the $message object back to the database. It needs to have
223 already been created via C<enqueue> for this to work.
227 # $object->update -- save object to database
230 my $dbh = C4::Context->dbh;
240 message_transport_type = ?,
249 $self->borrowernumber,
252 $self->{metadata}, # we want the raw YAML here
254 $self->message_transport_type,
264 =head3 $message->metadata(\%new_metadata)
266 This method automatically serializes and deserializes the metadata
267 attribute. (It is stored in YAML format.)
271 # $object->metadata -- this is a YAML serialized column that contains a
272 # structured representation of $object->content
274 my ($self, $data) = @_;
276 $data->{header} ||= '';
277 $data->{body} ||= [];
278 $data->{footer} ||= '';
279 $self->{metadata} = Encode::decode_utf8(Dump($data));
280 $self->content($self->render_metadata);
283 return YAML::XS::Load(Encode::encode_utf8($self->{metadata}));
287 # turn $object->metadata into a string suitable for $object->content
288 sub render_metadata {
289 my ($self, $format) = @_;
290 $format ||= sub { $_[0] || "" };
291 my $metadata = $self->metadata;
292 my $body = $metadata->{body};
293 my $text = join('', map { $format->($_) } @$body);
294 return $metadata->{header} . $text . $metadata->{footer};
297 =head3 $message->append(\%letter)
299 If passed a hashref, this method will assume that the hashref is in the form
300 that C<C4::Letters::getletter()> returns. It will append the body of the
301 letter to the message.
303 =head3 $message->append($string)
305 If passed a string, it'll append the string to the message.
309 # $object->append($letter_or_item) -- add a new item to a message's content
311 my ($self, $letter_or_item, $format) = @_;
312 my ( $item, $header, $footer );
313 if (ref($letter_or_item)) {
314 my $letter = $letter_or_item;
315 my $metadata = _metadata($letter);
316 $header = $metadata->{header};
317 $footer = $metadata->{footer};
318 $item = $metadata->{body}->[0];
320 $item = $letter_or_item;
322 if (not $self->metadata) {
323 carp "Can't append to messages that don't have metadata.";
326 my $metadata = $self->metadata;
327 push @{$metadata->{body}}, $item;
328 $metadata->{header} = $header;
329 $metadata->{footer} = $footer;
330 $self->metadata($metadata);
331 my $new_content = $self->render_metadata($format);
332 return $self->content($new_content);
335 =head2 Attributes Accessors
337 =head3 $message->message_id
341 =head3 $message->borrowernumber
345 =head3 $message->subject
349 =head3 $message->content
353 =head3 $message->metadata
357 =head3 $message->letter_code
361 =head3 $message->message_transport_type
365 =head3 $message->status
369 =head3 $message->time_queued
373 =head3 $message->to_address
377 =head3 $message->from_address
381 =head3 $message->content_type
385 # $object->$method -- treat keys as methods
387 my ($self, @args) = @_;
388 my $attr = $AUTOLOAD;
390 if (ref($self->{$attr}) eq 'CODE') {
391 $self->{$attr}->($self, @args);
394 $self->{$attr} = $args[0];
407 L<C4::Circulation>, L<C4::Letters>, L<C4::Members::Messaging>
411 John Beppu <john.beppu@liblime.com>