self-service support usage improvements (1733)
[freeside.git] / FS / FS / acct_rt_transaction.pm
1 package FS::acct_rt_transaction;
2
3 use strict;
4 use vars qw( @ISA );
5 use FS::Record qw( qsearch qsearchs dbh );
6
7 @ISA = qw(FS::Record);
8
9 =head1 NAME
10
11 FS::acct_rt_transaction - Object methods for acct_rt_transaction records
12
13 =head1 SYNOPSIS
14
15   use FS::acct_rt_transaction;
16
17   $record = new FS::acct_rt_transaction \%hash;
18   $record = new FS::acct_rt_transaction { 'column' => 'value' };
19
20   $error = $record->insert;
21
22   $error = $new_record->replace($old_record);
23
24   $error = $record->delete;
25
26   $error = $record->check;
27
28 =head1 DESCRIPTION
29
30 An FS::acct_rt_transaction object represents an application of time
31 from a rt transaction to a svc_acct.  FS::acct_rt_transaction inherits from
32 FS::Record.  The following fields are currently supported:
33
34 =over 4
35
36 =item svcrtid - primary key
37
38 =item svcnum -  the svcnum of the svc_acct to which the time applies
39
40 =item transaction_id -  the id of the rt transtaction from which the time applies
41
42 =item seconds - the amount of time applied from tickets
43
44 =item support - the amount of time applied to support services
45
46
47 =back
48
49 =head1 METHODS
50
51 =over 4
52
53 =item new HASHREF
54
55 Creates a new acct_rt_transaction.  To add the example to the database, see L<"insert">.
56
57 Note that this stores the hash reference, not a distinct copy of the hash it
58 points to.  You can ask the object for a copy with the I<hash> method.
59
60 =cut
61
62 sub table { 'acct_rt_transaction'; }
63
64 =item insert
65
66 Adds this record to the database.  If there is an error, returns the error,
67 otherwise returns false.
68
69 =cut
70
71 sub insert {
72   my( $self, %options ) = @_;
73   
74   local $SIG{HUP} = 'IGNORE';
75   local $SIG{INT} = 'IGNORE';
76   local $SIG{QUIT} = 'IGNORE';
77   local $SIG{TERM} = 'IGNORE';
78   local $SIG{TSTP} = 'IGNORE';
79   local $SIG{PIPE} = 'IGNORE';
80
81   my $oldAutoCommit = $FS::UID::AutoCommit;
82   local $FS::UID::AutoCommit = 0;
83   my $dbh = dbh;
84
85   my $error = $self->SUPER::insert($options{options} ? %{$options{options}} : ());
86   if ( $error ) {
87     $dbh->rollback if $oldAutoCommit;
88     return $error;
89   }
90
91   my $svc_acct = qsearchs('svc_acct', {'svcnum' => $self->svcnum});
92   unless ($svc_acct) {
93     $dbh->rollback if $oldAutoCommit;
94     return "Can't find svc_acct " . $self->svcnum;
95   }
96
97   $error = $svc_acct->decrement_seconds($self->support);
98   if ( $error ) {
99     $dbh->rollback if $oldAutoCommit;
100     return "Error incrementing service seconds: $error";
101   }
102   
103   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
104   '';
105
106 }
107
108
109 =item delete
110
111 Delete this record from the database.
112
113 =cut
114
115 sub delete { 
116   my $self = shift;
117
118   local $SIG{HUP} = 'IGNORE';
119   local $SIG{INT} = 'IGNORE';
120   local $SIG{QUIT} = 'IGNORE';
121   local $SIG{TERM} = 'IGNORE';
122   local $SIG{TSTP} = 'IGNORE';
123   local $SIG{PIPE} = 'IGNORE';
124
125   my $oldAutoCommit = $FS::UID::AutoCommit;
126   local $FS::UID::AutoCommit = 0;
127   my $dbh = dbh;
128
129   my $error = $self->SUPER::delete;
130   if ( $error ) {
131     $dbh->rollback if $oldAutoCommit;
132     return $error;
133   }
134
135   my $svc_acct = qsearchs('svc_acct', {'svcnum' => $self->svcnum});
136   unless ($svc_acct) {
137     $dbh->rollback if $oldAutoCommit;
138     return "Can't find svc_acct " . $self->svcnum;
139   }
140
141   $error = $svc_acct->increment_seconds($self->support);
142   if ( $error ) {
143     $dbh->rollback if $oldAutoCommit;
144     return "Error incrementing service seconds: $error";
145   }
146   
147   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
148   '';
149
150 }
151
152 =item replace OLD_RECORD
153
154 Replaces the OLD_RECORD with this one in the database.  If there is an error,
155 returns the error, otherwise returns false.
156
157 =cut
158
159 =item check
160
161 Checks all fields to make sure this is a valid acct_rt_transaction.  If there is
162 an error, returns the error, otherwise returns false.  Called by the insert
163 and replace methods.
164
165 =cut
166
167 sub check {
168   my $self = shift;
169
170   my ($selfref) = $self->hashref;
171
172   my $error = 
173     $self->ut_numbern('svcrtid')
174     || $self->ut_numbern('svcnum')
175     || $self->ut_number('transaction_id')
176     || $self->ut_numbern('_date')
177     || $self->ut_snumber('seconds')
178     || $self->ut_snumber('support')
179   ;
180   return $error if $error;
181
182   $self->_date(time) unless $self->_date;
183
184   if ($selfref->{custnum}) {
185     my $conf = new FS::Conf;
186     my %packages = map { $_ => 1 } $conf->config('support_packages');
187     my $cust_main = qsearchs('cust_main',{ 'custnum' => $selfref->{custnum} } );
188     return "Invalid custnum: " . $selfref->{custnum} unless $cust_main;
189
190     my (@svcs) = map { $_->svcnum } $cust_main->support_services;
191     return "svcnum ". $self->svcnum. " invalid for custnum ".$selfref->{custnum}
192       unless (!$self->svcnum || scalar(grep { $_ == $self->svcnum } @svcs));
193
194     $self->svcnum($svcs[0]) unless $self->svcnum;
195     return "Can't find support service for custnum ".$selfref->{custnum}
196       unless $self->svcnum;
197   }
198
199   $self->SUPER::check;
200 }
201
202 =item creator
203
204 Returns the creator of the RT transaction associated with this object.
205
206 =cut
207
208 sub creator {
209   my $self = shift;
210   FS::TicketSystem->transaction_creator($self->transaction_id);
211 }
212
213 =item ticketid
214
215 Returns the number of the RT ticket associated with this object.
216
217 =cut
218
219 sub ticketid {
220   my $self = shift;
221   FS::TicketSystem->transaction_ticketid($self->transaction_id);
222 }
223
224 =item subject
225
226 Returns the subject of the RT ticket associated with this object.
227
228 =cut
229
230 sub subject {
231   my $self = shift;
232   FS::TicketSystem->transaction_subject($self->transaction_id);
233 }
234
235 =item status
236
237 Returns the status of the RT ticket associated with this object.
238
239 =cut
240
241 sub status {
242   my $self = shift;
243   FS::TicketSystem->transaction_status($self->transaction_id);
244 }
245
246 =item batch_insert SVC_ACCT_RT_TRANSACTION_OBJECT, ...
247
248 Class method which inserts multiple time applications.  Takes a list of
249 FS::acct_rt_transaction objects.  If there is an error inserting any
250 application, the entire transaction is rolled back, i.e. all time is applied
251 or none is.
252
253 For example:
254
255   my $errors = FS::acct_rt_transaction->batch_insert(@transactions);
256   if ( $error ) {
257     #success; all payments were inserted
258   } else {
259     #failure; no payments were inserted.
260   }
261
262 =cut
263
264 sub batch_insert {
265   my $self = shift; #class method
266
267   local $SIG{HUP} = 'IGNORE';
268   local $SIG{INT} = 'IGNORE';
269   local $SIG{QUIT} = 'IGNORE';
270   local $SIG{TERM} = 'IGNORE';
271   local $SIG{TSTP} = 'IGNORE';
272   local $SIG{PIPE} = 'IGNORE';
273
274   my $oldAutoCommit = $FS::UID::AutoCommit;
275   local $FS::UID::AutoCommit = 0;
276   my $dbh = dbh;
277
278   my $error;
279   foreach (@_) {
280     $error = $_->insert;
281     last if $error;
282   }
283
284   if ( $error ) {
285     $dbh->rollback if $oldAutoCommit;
286   } else {
287     $dbh->commit or die $dbh->errstr if $oldAutoCommit;
288   }
289
290   $error;
291
292 }
293
294 =back
295
296 =head1 BUGS
297
298 Possibly the delete method or others.
299
300 =head1 SEE ALSO
301
302 L<FS::Record>, schema.html from the base documentation.
303
304 =cut
305
306 1;
307