6 use FS::Record qw( qsearch qsearchs dbh );
15 use FS::domain_record;
17 @ISA = qw( FS::Record );
21 my ( $hashref, $cache ) = @_;
22 if ( $hashref->{'username'} ) {
23 $self->{'_svc_acct'} = FS::svc_acct->new($hashref, '');
25 if ( $hashref->{'svc'} ) {
26 $self->{'_svcpart'} = FS::part_svc->new($hashref);
32 FS::cust_svc - Object method for cust_svc objects
38 $record = new FS::cust_svc \%hash
39 $record = new FS::cust_svc { 'column' => 'value' };
41 $error = $record->insert;
43 $error = $new_record->replace($old_record);
45 $error = $record->delete;
47 $error = $record->check;
49 ($label, $value) = $record->label;
53 An FS::cust_svc represents a service. FS::cust_svc inherits from FS::Record.
54 The following fields are currently supported:
58 =item svcnum - primary key (assigned automatically for new services)
60 =item pkgnum - Package (see L<FS::cust_pkg>)
62 =item svcpart - Service definition (see L<FS::part_svc>)
72 Creates a new service. To add the refund to the database, see L<"insert">.
73 Services are normally created by creating FS::svc_ objects (see
74 L<FS::svc_acct>, L<FS::svc_domain>, and L<FS::svc_forward>, among others).
78 sub table { 'cust_svc'; }
82 Adds this service to the database. If there is an error, returns the error,
83 otherwise returns false.
87 Deletes this service from the database. If there is an error, returns the
88 error, otherwise returns false.
90 Called by the cancel method of the package (see L<FS::cust_pkg>).
92 =item replace OLD_RECORD
94 Replaces the OLD_RECORD with this one in the database. If there is an error,
95 returns the error, otherwise returns false.
100 my ( $new, $old ) = ( shift, shift );
102 local $SIG{HUP} = 'IGNORE';
103 local $SIG{INT} = 'IGNORE';
104 local $SIG{QUIT} = 'IGNORE';
105 local $SIG{TERM} = 'IGNORE';
106 local $SIG{TSTP} = 'IGNORE';
107 local $SIG{PIPE} = 'IGNORE';
109 my $oldAutoCommit = $FS::UID::AutoCommit;
110 local $FS::UID::AutoCommit = 0;
113 my $error = $new->SUPER::replace($old);
115 $dbh->rollback if $oldAutoCommit;
116 return $error if $error;
119 if ( $new->svcpart != $old->svcpart ) {
120 my $svc_x = $new->svc_x;
121 my $new_svc_x = ref($svc_x)->new({$svc_x->hash});
122 my $error = $new_svc_x->replace($svc_x);
124 $dbh->rollback if $oldAutoCommit;
125 return $error if $error;
129 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
136 Checks all fields to make sure this is a valid service. If there is an error,
137 returns the error, otehrwise returns false. Called by the insert and
146 $self->ut_numbern('svcnum')
147 || $self->ut_numbern('pkgnum')
148 || $self->ut_number('svcpart')
150 return $error if $error;
152 my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
153 return "Unknown svcpart" unless $part_svc;
155 if ( $self->pkgnum ) {
156 my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
157 return "Unknown pkgnum" unless $cust_pkg;
158 my $pkg_svc = qsearchs( 'pkg_svc', {
159 'pkgpart' => $cust_pkg->pkgpart,
160 'svcpart' => $self->svcpart,
162 # or new FS::pkg_svc ( { 'pkgpart' => $cust_pkg->pkgpart,
163 # 'svcpart' => $self->svcpart,
164 # 'quantity' => 0 } );
166 my @cust_svc = qsearch('cust_svc', {
167 'pkgnum' => $self->pkgnum,
168 'svcpart' => $self->svcpart,
170 return "Already ". scalar(@cust_svc). " ". $part_svc->svc.
171 " services for pkgnum ". $self->pkgnum
172 if scalar(@cust_svc) >= $pkg_svc->quantity;
180 Returns the definition for this service, as a FS::part_svc object (see
188 ? $self->{'_svcpart'}
189 : qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
194 Returns the definition for this service, as a FS::part_svc object (see
201 qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
206 Returns a list consisting of:
207 - The name of this service (from part_svc)
208 - A meaningful identifier (username, domain, or mail alias)
209 - The table name (i.e. svc_domain) for this service
215 my $svcdb = $self->part_svc->svcdb;
216 my $svc_x = $self->svc_x
217 or die "can't find $svcdb.svcnum ". $self->svcnum;
219 if ( $svcdb eq 'svc_acct' ) {
220 $tag = $svc_x->email;
221 } elsif ( $svcdb eq 'svc_acct_sm' ) {
222 my $domuser = $svc_x->domuser eq '*' ? '(anything)' : $svc_x->domuser;
223 my $svc_domain = qsearchs ( 'svc_domain', { 'svcnum' => $svc_x->domsvc } );
224 my $domain = $svc_domain->domain;
225 $tag = "$domuser\@$domain";
226 } elsif ( $svcdb eq 'svc_forward' ) {
227 my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $svc_x->srcsvc } );
228 $tag = $svc_acct->email. '->';
229 if ( $svc_x->dstsvc ) {
230 $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $svc_x->dstsvc } );
231 $tag .= $svc_acct->email;
235 } elsif ( $svcdb eq 'svc_domain' ) {
236 $tag = $svc_x->getfield('domain');
237 } elsif ( $svcdb eq 'svc_www' ) {
238 my $domain = qsearchs( 'domain_record', { 'recnum' => $svc_x->recnum } );
239 $tag = $domain->reczone;
241 cluck "warning: asked for label of unsupported svcdb; using svcnum";
242 $tag = $svc_x->getfield('svcnum');
244 $self->part_svc->svc, $tag, $svcdb;
249 Returns the FS::svc_XXX object for this service (i.e. an FS::svc_acct object or
250 FS::svc_domain object, etc.)
256 my $svcdb = $self->part_svc->svcdb;
257 if ( $svcdb eq 'svc_acct' && $self->{'_svc_acct'} ) {
258 $self->{'_svc_acct'};
260 qsearchs( $svcdb, { 'svcnum' => $self->svcnum } );
264 =item seconds_since TIMESTAMP
266 See L<FS::svc_acct/seconds_since>. Equivalent to
267 $cust_svc->svc_x->seconds_since, but more efficient. Meaningless for records
268 where B<svcdb> is not "svc_acct".
272 #note: implementation here, POD in FS::svc_acct
274 my($self, $since) = @_;
276 my $sth = $dbh->prepare(' SELECT SUM(logout-login) FROM session
279 AND logout IS NOT NULL'
280 ) or die $dbh->errstr;
281 $sth->execute($self->svcnum, $since) or die $sth->errstr;
282 $sth->fetchrow_arrayref->[0];
289 $Id: cust_svc.pm,v 1.14 2002-04-20 02:06:38 ivan Exp $
293 Behaviour of changing the svcpart of cust_svc records is undefined and should
294 possibly be prohibited, and pkg_svc records are not checked.
296 pkg_svc records are not checked in general (here).
298 Deleting this record doesn't check or delete the svc_* record associated
303 L<FS::Record>, L<FS::cust_pkg>, L<FS::part_svc>, L<FS::pkg_svc>,
304 schema.html from the base documentation