#21564, external message services: REST client
[freeside.git] / FS / FS / msg_template / http.pm
1 package FS::msg_template::http;
2 use base qw( FS::msg_template );
3
4 use strict;
5 use vars qw( $DEBUG $conf );
6
7 # needed to talk to the external service
8 use LWP::UserAgent;
9 use HTTP::Request::Common;
10 use JSON;
11
12 # needed to manage prepared messages
13 use FS::cust_msg;
14
15 our $DEBUG = 1;
16 our $me = '[FS::msg_template::http]';
17
18 sub extension_table { 'msg_template_http' }
19
20 =head1 NAME
21
22 FS::msg_template::http - Send messages via a web service.
23
24 =head1 DESCRIPTION
25
26 FS::msg_template::http is a message processor in which the message is exported
27 to a web service, at both the prepare and send stages.
28
29 =head1 METHODS
30
31 =cut
32
33 sub check {
34   my $self = shift;
35   return 
36        $self->ut_textn('prepare_url')
37     || $self->ut_textn('send_url')
38     || $self->ut_textn('username')
39     || $self->ut_textn('password')
40     || $self->ut_anything('content')
41     || $self->SUPER::check;
42 }
43
44 sub prepare {
45
46   my( $self, %opt ) = @_;
47
48   my $json = JSON->new->canonical(1);
49
50   my $cust_main = $opt{'cust_main'}; # or die 'cust_main required';
51   my $object = $opt{'object'} or die 'object required';
52
53   my $hashref = $self->prepare_substitutions(%opt);
54
55   my $document = $json->decode( $self->content || '{}' );
56   $document = {
57     'msgname' => $self->msgname,
58     'msgtype' => $opt{'msgtype'},
59     %$document,
60     %$hashref
61   };
62
63   my $request_content = $json->encode($document);
64   warn "$me ".$self->prepare_url."\n" if $DEBUG;
65   warn "$request_content\n\n" if $DEBUG > 1;
66   my $ua = LWP::UserAgent->new;
67   my $request = POST(
68     $self->prepare_url,
69     'Content-Type' => 'application/json',
70     'Content' => $request_content,
71   );
72   if ( $self->username ) {
73     $request->authorization_basic( $self->username, $self->password );
74   }
75   my $response = $ua->request($request);
76   warn "$me received:\n" . $response->as_string . "\n\n" if $DEBUG;
77
78   my $cust_msg = FS::cust_msg->new({
79       'custnum'   => $cust_main->custnum,
80       'msgnum'    => $self->msgnum,
81       '_date'     => time,
82       'msgtype'   => ($opt{'msgtype'} || ''),
83   });
84
85   if ( $response->is_success ) {
86     $cust_msg->set(body => $response->decoded_content);
87     $cust_msg->set(status => 'prepared');
88   } else {
89     $cust_msg->set(status => 'failed');
90     $cust_msg->set(error => $response->decoded_content);
91   }
92
93   $cust_msg;
94 }
95
96 =item send_prepared CUST_MSG
97
98 Takes the CUST_MSG object and sends it to its recipient.
99
100 =cut
101
102 sub send_prepared {
103   my $self = shift;
104   my $cust_msg = shift or die "cust_msg required";
105   # don't just fail if called as a class method
106   if (!ref $self) {
107     $self = $cust_msg->msg_template;
108   }
109
110   # use cust_msg->header for anything? we _could_...
111   my $request_content = $cust_msg->body;
112
113   warn "$me ".$self->send_url."\n" if $DEBUG;
114   warn "$request_content\n\n" if $DEBUG > 1;
115   my $ua = LWP::UserAgent->new;
116   my $request = POST(
117     $self->send_url,
118     'Content-Type' => 'application/json',
119     'Content' => $request_content,
120   );
121   if ( $self->username ) {
122     $request->authorization_basic( $self->username, $self->password );
123   }
124   my $response = $ua->request($request);
125   warn "$me received:\n" . $response->as_string . "\n\n" if $DEBUG;
126
127   my $error;
128   if ( $response->is_success ) {
129     $cust_msg->set(status => 'sent');
130   } else {
131     $error = $response->decoded_content;
132     $cust_msg->set(error => $error);
133     $cust_msg->set(status => 'failed');
134   }
135
136   if ( $cust_msg->custmsgnum ) {
137     $cust_msg->replace;
138   } else {
139     $cust_msg->insert;
140   }
141
142   $error;
143 }
144
145 =back
146
147 =head1 BUGS
148
149 =head1 SEE ALSO
150
151 L<FS::Record>, schema.html from the base documentation.
152
153 =cut
154
155 1;