fix some dangling records on upgrade, #32456 and #38765
[freeside.git] / FS / FS / reg_code.pm
1 package FS::reg_code;
2
3 use strict;
4 use vars qw( @ISA );
5 use FS::Record qw(qsearch dbh);
6 use FS::agent;
7 use FS::reg_code_pkg;
8
9 @ISA = qw(FS::Record);
10
11 =head1 NAME
12
13 FS::reg_code - One-time registration codes
14
15 =head1 SYNOPSIS
16
17   use FS::reg_code;
18
19   $record = new FS::reg_code \%hash;
20   $record = new FS::reg_code { 'column' => 'value' };
21
22   $error = $record->insert;
23
24   $error = $new_record->replace($old_record);
25
26   $error = $record->delete;
27
28   $error = $record->check;
29
30 =head1 DESCRIPTION
31
32 An FS::reg_code object is a one-time registration code.  FS::reg_code inherits
33 from FS::Record.  The following fields are currently supported:
34
35 =over 4
36
37 =item codenum - primary key
38
39 =item code - registration code string
40
41 =item agentnum - Agent (see L<FS::agent>)
42
43 =back
44
45 =head1 METHODS
46
47 =over 4
48
49 =item new HASHREF
50
51 Creates a new registration code.  To add the code to the database, see
52 L<"insert">.
53
54 Note that this stores the hash reference, not a distinct copy of the hash it
55 points to.  You can ask the object for a copy with the I<hash> method.
56
57 =cut
58
59 # the new method can be inherited from FS::Record, if a table method is defined
60
61 sub table { 'reg_code'; }
62
63 =item insert [ PKGPART_ARRAYREF ] 
64
65 Adds this record to the database.  If an arrayref of pkgparts
66 (see L<FS::part_pkg>) is specified, the appropriate reg_code_pkg records
67 (see L<FS::reg_code_pkg>) will be inserted.
68
69 If there is an error, returns the error, otherwise returns false.
70
71 =cut
72
73 sub insert {
74   my $self = shift;
75
76   local $SIG{HUP} = 'IGNORE';
77   local $SIG{INT} = 'IGNORE';
78   local $SIG{QUIT} = 'IGNORE';
79   local $SIG{TERM} = 'IGNORE';
80   local $SIG{TSTP} = 'IGNORE';
81   local $SIG{PIPE} = 'IGNORE';
82
83   my $oldAutoCommit = $FS::UID::AutoCommit;
84   local $FS::UID::AutoCommit = 0;
85   my $dbh = dbh;
86
87   my $error = $self->SUPER::insert;
88   if ( $error ) {
89     $dbh->rollback if $oldAutoCommit;
90     return $error;
91   }
92
93   if ( @_ ) {
94     my $pkgparts = shift;
95     foreach my $pkgpart ( @$pkgparts ) {
96       my $reg_code_pkg = new FS::reg_code_pkg ( {
97         'codenum' => $self->codenum,
98         'pkgpart' => $pkgpart,
99       } );
100       $error = $reg_code_pkg->insert;
101       if ( $error ) {
102         $dbh->rollback if $oldAutoCommit;
103         return $error;
104       }
105     }
106   }
107
108   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
109   '';
110
111 }
112
113 =item delete
114
115 Delete this record (and all associated reg_code_pkg records) from the database.
116
117 =cut
118
119 sub delete {
120   my $self = shift;
121
122   local $SIG{HUP} = 'IGNORE';
123   local $SIG{INT} = 'IGNORE';
124   local $SIG{QUIT} = 'IGNORE';
125   local $SIG{TERM} = 'IGNORE';
126   local $SIG{TSTP} = 'IGNORE';
127   local $SIG{PIPE} = 'IGNORE';
128
129   my $oldAutoCommit = $FS::UID::AutoCommit;
130   local $FS::UID::AutoCommit = 0;
131   my $dbh = dbh;
132
133   foreach my $reg_code_pkg ( $self->reg_code_pkg ) {
134     my $error = $reg_code_pkg->delete;
135     if ( $error ) {
136       $dbh->rollback if $oldAutoCommit;
137       return $error;
138     }
139   }
140
141   my $error = $self->SUPER::delete;
142   if ( $error ) {
143     $dbh->rollback if $oldAutoCommit;
144     return $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 # the replace method can be inherited from FS::Record
160
161 =item check
162
163 Checks all fields to make sure this is a valid registration code.  If there is
164 an error, returns the error, otherwise returns false.  Called by the insert
165 and replace methods.
166
167 =cut
168
169 # the check method should currently be supplied - FS::Record contains some
170 # data checking routines
171
172 sub check {
173   my $self = shift;
174
175   my $error = 
176     $self->ut_numbern('codenum')
177     || $self->ut_alpha('code')
178     || $self->ut_foreign_key('agentnum', 'agent', 'agentnum')
179   ;
180   return $error if $error;
181
182   $self->SUPER::check;
183 }
184
185 =item part_pkg
186
187 Returns all package definitions (see L<FS::part_pkg> for this registration
188 code.
189
190 =cut
191
192 sub part_pkg {
193   my $self = shift;
194   map { $_->part_pkg } $self->reg_code_pkg;
195 }
196
197 =item reg_code_pkg
198
199 Returns all FS::reg_code_pkg records for this registration code.
200
201 =cut
202
203 sub reg_code_pkg {
204   my $self = shift;
205   qsearch('reg_code_pkg', { 'codenum' => $self->codenum } );
206 }
207
208
209 =back
210
211 =head1 BUGS
212
213 Feeping creaturitis.
214
215 =head1 SEE ALSO
216
217 L<FS::reg_code_pkg>, L<FS::Record>, schema.html from the base documentation.
218
219 =cut
220
221 1;
222
223