allow Configuration ACL to edit templates, RT#8324
[freeside.git] / FS / FS / msg_template.pm
1 package FS::msg_template;
2
3 use strict;
4 use base qw( FS::Record );
5 use Text::Template;
6 use FS::Misc qw( generate_email send_email );
7 use FS::Conf;
8 use FS::Record qw( qsearch qsearchs );
9
10 =head1 NAME
11
12 FS::msg_template - Object methods for msg_template records
13
14 =head1 SYNOPSIS
15
16   use FS::msg_template;
17
18   $record = new FS::msg_template \%hash;
19   $record = new FS::msg_template { 'column' => 'value' };
20
21   $error = $record->insert;
22
23   $error = $new_record->replace($old_record);
24
25   $error = $record->delete;
26
27   $error = $record->check;
28
29 =head1 DESCRIPTION
30
31 An FS::msg_template object represents a customer message template.
32 FS::msg_template inherits from FS::Record.  The following fields are currently
33 supported:
34
35 =over 4
36
37 =item msgnum
38
39 primary key
40
41 =item msgname
42
43 msgname
44
45 =item agentnum
46
47 agentnum
48
49 =item mime_type
50
51 mime_type
52
53 =item body
54
55 body
56
57 =item disabled
58
59 disabled
60
61
62 =back
63
64 =head1 METHODS
65
66 =over 4
67
68 =item new HASHREF
69
70 Creates a new template.  To add the template to the database, see L<"insert">.
71
72 Note that this stores the hash reference, not a distinct copy of the hash it
73 points to.  You can ask the object for a copy with the I<hash> method.
74
75 =cut
76
77 # the new method can be inherited from FS::Record, if a table method is defined
78
79 sub table { 'msg_template'; }
80
81 =item insert
82
83 Adds this record to the database.  If there is an error, returns the error,
84 otherwise returns false.
85
86 =cut
87
88 # the insert method can be inherited from FS::Record
89
90 =item delete
91
92 Delete this record from the database.
93
94 =cut
95
96 # the delete method can be inherited from FS::Record
97
98 =item replace OLD_RECORD
99
100 Replaces the OLD_RECORD with this one in the database.  If there is an error,
101 returns the error, otherwise returns false.
102
103 =cut
104
105 # the replace method can be inherited from FS::Record
106
107 =item check
108
109 Checks all fields to make sure this is a valid template.  If there is
110 an error, returns the error, otherwise returns false.  Called by the insert
111 and replace methods.
112
113 =cut
114
115 # the check method should currently be supplied - FS::Record contains some
116 # data checking routines
117
118 sub check {
119   my $self = shift;
120
121   my $error = 
122     $self->ut_numbern('msgnum')
123     || $self->ut_text('msgname')
124     || $self->ut_foreign_keyn('agentnum', 'agent', 'agentnum')
125     || $self->ut_textn('mime_type')
126     || $self->ut_anything('subject')
127     || $self->ut_anything('body')
128     || $self->ut_enum('disabled', [ '', 'Y' ] )
129   ;
130   return $error if $error;
131
132   $self->mime_type('text/html') unless $self->mime_type;
133
134   $self->SUPER::check;
135 }
136
137 =item send OPTION => VALUE, ...
138
139 Fills in the template and emails it to the customer.
140
141 Options are passed as a list of name/value pairs:
142
143 =over 4
144
145 =item cust_main
146
147 Customer object (required).
148
149 =item object
150
151 Additional context object (currently, can be a cust_main object, cust_pkg
152 object, or cust_bill object).
153
154 =back
155
156 =cut
157
158 sub send {
159   my( $self, %opt ) = @_;
160
161   my $cust_main = $opt{'cust_main'};
162   my $object = $opt{'object'};
163
164   ###
165   # fill-in
166   ###
167
168   my $subs = $self->substitutions;
169   
170   #XXX html escape this stuff
171   my %hash = map { $_ => $cust_main->$_() } @{ $subs->{'cust_main'} };
172   unless ( ! $object || $object->table eq 'cust_main' ) {
173     %hash = ( %hash, map { $_ => $object->$_() } @{ $subs->{$object->table} } );
174   }
175
176   my $subject_tmpl = new Text::Template (
177     TYPE   => 'STRING',
178     SOURCE => $self->subject,
179   );
180   my $subject = $subject_tmpl->fill_in( HASH => \%hash );
181
182   my $body_tmpl = new Text::Template (
183     TYPE   => 'STRING',
184     SOURCE => $self->body,
185   );
186   my $body = $body_tmpl->fill_in( HASH => \%hash );
187
188   ###
189   # and email
190   ###
191
192   my @to = $cust_main->invoicing_list_emailonly;
193   #unless (@to) { #XXX do something }
194
195   my $conf = new FS::Conf;
196
197   send_email(
198     generate_email(
199        #XXX override from in event?
200       'from' => scalar( $conf->config('invoice_from', $cust_main->agentnum) ),
201       'to'   => \@to,
202       'subject'   => $subject,
203       'html_body' => $body,
204       #XXX auto-make a text copy w/HTML::FormatText?
205       #  alas, us luddite mutt/pine users just aren't that big a deal
206     )
207   );
208
209 }
210
211 #return contexts and fill-in values
212 sub substitutions {
213   { 'cust_main' => [qw(
214       display_custnum agentnum agent_name
215
216       last first company
217       name name_short contact contact_firstlast
218       address1 address2 city county state zip
219       country
220       daytime night fax
221
222       has_ship_address
223       ship_last ship_first ship_company
224       ship_name ship_name_short ship_contact ship_contact_firstlast
225       ship_address1 ship_address2 ship_city ship_county ship_state ship_zip
226       ship_country
227       ship_daytime ship_night ship_fax
228
229       payby paymask payname paytype payip
230       num_cancelled_pkgs num_ncancelled_pkgs num_pkgs
231       classname categoryname
232       balance
233       invoicing_list_emailonly
234       cust_status ucfirst_cust_status cust_statuscolor
235     )],
236     #XXX make these pretty: signupdate dundate paydate_monthyear usernum
237     # next_bill_date
238
239     'cust_pkg'  => [qw(
240     )],
241     #XXX these are going to take more pretty-ing up
242
243     'cust_bill' => [qw(
244       invnum
245     )],
246     #XXX not really thinking about cust_bill substitutions quite yet
247
248   };
249 }
250
251 =back
252
253 =head1 BUGS
254
255 =head1 SEE ALSO
256
257 L<FS::Record>, schema.html from the base documentation.
258
259 =cut
260
261 1;
262