fix upgrade: clear bad cust_refund.source_paynum before encrypting, RT#81508
[freeside.git] / FS / FS / cust_msg.pm
1 package FS::cust_msg;
2
3 use strict;
4 use base qw( FS::cust_main_Mixin FS::Record );
5 use FS::Record qw( qsearch qsearchs );
6 use MIME::Parser;
7 use vars qw( @statuses );
8
9 =head1 NAME
10
11 FS::cust_msg - Object methods for cust_msg records
12
13 =head1 SYNOPSIS
14
15   use FS::cust_msg;
16
17   $record = new FS::cust_msg \%hash;
18   $record = new FS::cust_msg { 'column' => 'value' };
19
20   $error = $record->insert;
21
22   $error = $record->check;
23
24 =head1 DESCRIPTION
25
26 An FS::cust_msg object represents an email message generated by Freeside 
27 and sent to a customer (see L<FS::msg_template>).  FS::cust_msg inherits 
28 from FS::Record.  The following fields are currently supported:
29
30 =over 4
31
32 =item custmsgnum - primary key
33
34 =item custnum - customer number
35
36 =item msgnum - template number
37
38 =item msgtype - the message type
39
40 =item _date - the time the message was sent
41
42 =item env_from - envelope From address
43
44 =item env_to - envelope To addresses, including Bcc, separated by newlines
45
46 =item header - message header
47
48 =item body - message body
49
50 =item error - Email::Sender error message (or null for success)
51
52 =back
53
54 =head1 METHODS
55
56 =over 4
57
58 =item new HASHREF
59
60 Creates a new 
61
62 =cut
63
64 # the new method can be inherited from FS::Record, if a table method is defined
65
66 sub table { 'cust_msg'; }
67
68 sub nohistory_fields { ('header', 'body'); } 
69 # history is kind of pointless on this table
70
71 @statuses = qw( prepared sent failed );
72
73 =item insert
74
75 Adds this record to the database.  If there is an error, returns the error 
76 and emits a warning; otherwise returns false.
77
78 =cut
79
80 sub insert {
81   # warn of all errors here; failing to insert/update one of these should 
82   # cause a warning at worst
83   my $self = shift;
84   my $error = $self->SUPER::insert;
85   warn "[cust_msg] error logging message status: $error\n" if $error;
86   return $error;
87 }
88
89 =item delete
90
91 Delete this record from the database.  There's no reason to do this.
92
93 =cut
94
95 sub delete {
96   my $self = shift;
97   warn "[cust_msg] log entry deleted\n";
98   return $self->SUPER::delete;
99 }
100
101 =item replace OLD_RECORD
102
103 Replaces the OLD_RECORD with this one in the database.  If there is an error,
104 returns the error and emits a warning, otherwise returns false.
105
106 =cut
107
108 sub replace {
109   my $self = shift;
110   my $error = $self->SUPER::replace(@_);
111   warn "[cust_msg] error logging message status: $error\n" if $error;
112   return $error;
113 }
114
115 =item check
116
117 Checks all fields to make sure this is a valid example.  If there is
118 an error, returns the error, otherwise returns false.  Called by the insert
119 and replace methods.
120
121 =cut
122
123 # the check method should currently be supplied - FS::Record contains some
124 # data checking routines
125
126 sub check {
127   my $self = shift;
128
129   my $error = 
130     $self->ut_numbern('custmsgnum')
131     || $self->ut_numbern('custnum')
132     || $self->ut_foreign_keyn('custnum', 'cust_main', 'custnum')
133     || $self->ut_numbern('msgnum')
134     || $self->ut_foreign_keyn('msgnum', 'msg_template', 'msgnum')
135     || $self->ut_numbern('_date')
136     || $self->ut_textn('env_from')
137     || $self->ut_textn('env_to')
138     || $self->ut_anything('header')
139     || $self->ut_anything('body')
140     || $self->ut_enum('status', \@statuses)
141     || $self->ut_textn('error')
142     || $self->ut_enum('msgtype', [  '',
143                                     'invoice',
144                                     'receipt',
145                                     'admin',
146                                     'report',
147                                  ])
148   ;
149   return $error if $error;
150
151   $self->SUPER::check;
152 }
153
154 =item entity
155
156 Returns the complete message as a L<MIME::Entity>.
157
158 =item parts
159
160 Returns a list of the MIME parts contained in the message, as L<MIME::Entity>
161 objects.
162
163 =cut
164
165 sub entity {
166   my $self = shift;
167   if ( !exists($self->{entity}) ) {
168     my $parser = MIME::Parser->new;
169     my $output_dir = "$FS::UID::cache_dir/cache.$FS::UID::datasrc/mimeparts";
170     mkdir($output_dir) unless -d $output_dir;
171     $parser->output_under($output_dir);
172     $self->{entity} =
173       $parser->parse_data( $self->header . "\n" . $self->body );
174   }
175   $self->{entity};
176 }
177
178 sub parts {
179   my $self = shift;
180   # return only the parts with bodies, not the multipart containers
181   grep { $_->bodyhandle } $self->entity->parts_DFS;
182 }
183
184 =back
185
186 =head1 SEE ALSO
187
188 L<FS::msg_template>, L<FS::cust_main>, L<FS::Record>.
189
190 =cut
191
192 1;
193