merge NG auth, RT#21563
[freeside.git] / FS / FS / reason.pm
1 package FS::reason;
2
3 use strict;
4 use vars qw( @ISA $DEBUG $me );
5 use DBIx::DBSchema;
6 use DBIx::DBSchema::Table;
7 use DBIx::DBSchema::Column;
8 use FS::Record qw( qsearch qsearchs dbh dbdef );
9 use FS::reason_type;
10
11 @ISA = qw(FS::Record);
12 $DEBUG = 0;
13 $me = '[FS::reason]';
14
15 =head1 NAME
16
17 FS::reason - Object methods for reason records
18
19 =head1 SYNOPSIS
20
21   use FS::reason;
22
23   $record = new FS::reason \%hash;
24   $record = new FS::reason { 'column' => 'value' };
25
26   $error = $record->insert;
27
28   $error = $new_record->replace($old_record);
29
30   $error = $record->delete;
31
32   $error = $record->check;
33
34 =head1 DESCRIPTION
35
36 An FS::reason object represents a reason message.  FS::reason inherits from
37 FS::Record.  The following fields are currently supported:
38
39 =over 4
40
41 =item reasonnum - primary key
42
43 =item reason_type - index into FS::reason_type
44
45 =item reason - text of the reason
46
47 =item disabled - 'Y' or ''
48
49 =item unsuspend_pkgpart - for suspension reasons only, the pkgpart (see
50 L<FS::part_pkg>) of a package to be ordered when the package is unsuspended.
51 Typically this will be some kind of reactivation fee.  Attaching it to 
52 a suspension reason allows the reactivation fee to be charged for some
53 suspensions but not others.
54
55 =item unsuspend_hold - 'Y' or ''.  If unsuspend_pkgpart is set, this tells
56 whether to bill the unsuspend package immediately ('') or to wait until 
57 the customer's next invoice ('Y').
58
59 =back
60
61 =head1 METHODS
62
63 =over 4
64
65 =item new HASHREF
66
67 Creates a new reason.  To add the example to the database, see L<"insert">.
68
69 Note that this stores the hash reference, not a distinct copy of the hash it
70 points to.  You can ask the object for a copy with the I<hash> method.
71
72 =cut
73
74 sub table { 'reason'; }
75
76 =item insert
77
78 Adds this record to the database.  If there is an error, returns the error,
79 otherwise returns false.
80
81 =cut
82
83 =item delete
84
85 Delete this record from the database.
86
87 =cut
88
89 =item replace OLD_RECORD
90
91 Replaces the OLD_RECORD with this one in the database.  If there is an error,
92 returns the error, otherwise returns false.
93
94 =cut
95
96 =item check
97
98 Checks all fields to make sure this is a valid reason.  If there is
99 an error, returns the error, otherwise returns false.  Called by the insert
100 and replace methods.
101
102 =cut
103
104 sub check {
105   my $self = shift;
106
107   my $error = 
108     $self->ut_numbern('reasonnum')
109     || $self->ut_number('reason_type')
110     || $self->ut_foreign_key('reason_type', 'reason_type', 'typenum')
111     || $self->ut_text('reason')
112     || $self->ut_flag('disabled')
113   ;
114   return $error if $error;
115
116   if ( $self->reasontype->class eq 'S' ) {
117     $error = $self->ut_numbern('unsuspend_pkgpart')
118           || $self->ut_foreign_keyn('unsuspend_pkgpart', 'part_pkg', 'pkgpart')
119           || $self->ut_flag('unsuspend_hold')
120     ;
121     return $error if $error;
122   } else {
123     $self->set('unsuspend_pkgpart' => '');
124     $self->set('unsuspend_hold'    => '');
125   }
126
127   $self->SUPER::check;
128 }
129
130 =item reasontype
131
132 Returns the reason_type (see L<FS::reason_type>) associated with this reason.
133
134 =cut
135
136 sub reasontype {
137   qsearchs( 'reason_type', { 'typenum' => shift->reason_type } );
138 }
139
140 =back
141
142 =head1 CLASS METHODS
143
144 =over 4
145
146 =item new_or_existing reason => REASON, type => TYPE, class => CLASS
147
148 Fetches the reason matching these parameters if there is one.  If not,
149 inserts one.  Will also insert the reason type if necessary.  CLASS must
150 be one of 'C' (cancel reasons), 'R' (credit reasons), or 'S' (suspend reasons).
151
152 This will die if anything fails.
153
154 =cut
155
156 sub new_or_existing {
157   my $class = shift;
158   my %opt = @_;
159
160   my $error = '';
161   my %hash = ('class' => $opt{'class'}, 'type' => $opt{'type'});
162   my $reason_type = qsearchs('reason_type', \%hash)
163                     || FS::reason_type->new(\%hash);
164
165   $error = $reason_type->insert unless $reason_type->typenum;
166   die "error inserting reason type: $error\n" if $error;
167
168   %hash = ('reason_type' => $reason_type->typenum, 'reason' => $opt{'reason'});
169   my $reason = qsearchs('reason', \%hash)
170                || FS::reason->new(\%hash);
171
172   $error = $reason->insert unless $reason->reasonnum;
173   die "error inserting reason: $error\n" if $error;
174
175   $reason;
176 }
177
178
179 =head1 BUGS
180
181 Here by termintes.  Don't use on wooden computers.
182
183 =head1 SEE ALSO
184
185 L<FS::Record>, schema.html from the base documentation.
186
187 =cut
188
189 1;
190