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.
99 Checks all fields to make sure this is a valid service. If there is an error,
100 returns the error, otehrwise returns false. Called by the insert and
109 $self->ut_numbern('svcnum')
110 || $self->ut_numbern('pkgnum')
111 || $self->ut_number('svcpart')
113 return $error if $error;
115 my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
116 return "Unknown svcpart" unless $part_svc;
118 if ( $self->pkgnum ) {
119 my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
120 return "Unknown pkgnum" unless $cust_pkg;
121 my $pkg_svc = qsearchs( 'pkg_svc', {
122 'pkgpart' => $cust_pkg->pkgpart,
123 'svcpart' => $self->svcpart,
125 my @cust_svc = qsearch('cust_svc', {
126 'pkgnum' => $self->pkgnum,
127 'svcpart' => $self->svcpart,
129 return "Already ". scalar(@cust_svc). " ". $part_svc->svc.
130 " services for pkgnum ". $self->pkgnum
131 if scalar(@cust_svc) >= $pkg_svc->quantity;
139 Returns the definition for this service, as a FS::part_svc object (see
147 ? $self->{'_svcpart'}
148 : qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
153 Returns the definition for this service, as a FS::part_svc object (see
160 qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
165 Returns a list consisting of:
166 - The name of this service (from part_svc)
167 - A meaningful identifier (username, domain, or mail alias)
168 - The table name (i.e. svc_domain) for this service
174 my $svcdb = $self->part_svc->svcdb;
175 my $svc_x = $self->svc_x
176 or die "can't find $svcdb.svcnum ". $self->svcnum;
178 if ( $svcdb eq 'svc_acct' ) {
179 $tag = $svc_x->email;
180 } elsif ( $svcdb eq 'svc_acct_sm' ) {
181 my $domuser = $svc_x->domuser eq '*' ? '(anything)' : $svc_x->domuser;
182 my $svc_domain = qsearchs ( 'svc_domain', { 'svcnum' => $svc_x->domsvc } );
183 my $domain = $svc_domain->domain;
184 $tag = "$domuser\@$domain";
185 } elsif ( $svcdb eq 'svc_forward' ) {
186 my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $svc_x->srcsvc } );
187 $tag = $svc_acct->email. '->';
188 if ( $svc_x->dstsvc ) {
189 $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $svc_x->dstsvc } );
190 $tag .= $svc_acct->email;
194 } elsif ( $svcdb eq 'svc_domain' ) {
195 $tag = $svc_x->getfield('domain');
196 } elsif ( $svcdb eq 'svc_www' ) {
197 my $domain = qsearchs( 'domain_record', { 'recnum' => $svc_x->recnum } );
198 $tag = $domain->reczone;
200 cluck "warning: asked for label of unsupported svcdb; using svcnum";
201 $tag = $svc_x->getfield('svcnum');
203 $self->part_svc->svc, $tag, $svcdb;
208 Returns the FS::svc_XXX object for this service (i.e. an FS::svc_acct object or
209 FS::svc_domain object, etc.)
215 my $svcdb = $self->part_svc->svcdb;
216 if ( $svcdb eq 'svc_acct' && $self->{'_svc_acct'} ) {
217 $self->{'_svc_acct'};
219 qsearchs( $svcdb, { 'svcnum' => $self->svcnum } );
223 =item seconds_since TIMESTAMP
225 See L<FS::svc_acct/seconds_since>. Equivalent to
226 $cust_svc->svc_x->seconds_since, but more efficient. Meaningless for records
227 where B<svcdb> is not "svc_acct".
231 #note: implementation here, POD in FS::svc_acct
233 my($self, $since) = @_;
235 my $sth = $dbh->prepare(' SELECT SUM(logout-login) FROM session
238 AND logout IS NOT NULL'
239 ) or die $dbh->errstr;
240 $sth->execute($self->svcnum, $since) or die $sth->errstr;
241 $sth->fetchrow_arrayref->[0];
248 $Id: cust_svc.pm,v 1.12 2002-02-10 22:06:28 ivan Exp $
252 Behaviour of changing the svcpart of cust_svc records is undefined and should
253 possibly be prohibited, and pkg_svc records are not checked.
255 pkg_svc records are not checked in general (here).
257 Deleting this record doesn't check or delete the svc_* record associated
262 L<FS::Record>, L<FS::cust_pkg>, L<FS::part_svc>, L<FS::pkg_svc>,
263 schema.html from the base documentation