Initial revision
authorivan <ivan>
Wed, 23 Sep 1998 07:27:04 +0000 (07:27 +0000)
committerivan <ivan>
Wed, 23 Sep 1998 07:27:04 +0000 (07:27 +0000)
site_perl/agent_type.pm [new file with mode: 0644]
site_perl/cust_credit.pm [new file with mode: 0644]
site_perl/cust_main_county.pm [new file with mode: 0644]
site_perl/cust_pay.pm [new file with mode: 0644]
site_perl/cust_svc.pm [new file with mode: 0644]
site_perl/part_pkg.pm [new file with mode: 0644]
site_perl/part_referral.pm [new file with mode: 0644]
site_perl/pkg_svc.pm [new file with mode: 0644]

diff --git a/site_perl/agent_type.pm b/site_perl/agent_type.pm
new file mode 100644 (file)
index 0000000..002c36f
--- /dev/null
@@ -0,0 +1,161 @@
+package FS::agent_type;
+
+use strict;
+use vars qw(@ISA @EXPORT_OK);
+use Exporter;
+use FS::Record qw(qsearch fields);
+
+@ISA = qw(FS::Record Exporter);
+@EXPORT_OK = qw(fields);
+
+=head1 NAME
+
+FS::agent_type - Object methods for agent_type records
+
+=head1 SYNOPSIS
+
+  use FS::agent_type;
+
+  $record = create FS::agent_type \%hash;
+  $record = create FS::agent_type { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::agent_type object represents an agent type.  Every agent (see
+L<FS::agent>) has an agent type.  Agent types define which packages (see
+L<FS::part_pkg>) may be purchased by customers (see L<FS::cust_main>), via 
+FS::type_pkgs records (see L<FS::type_pkgs>).  FS::agent_type inherits from
+FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item typenum - primary key (assigned automatically for new agent types)
+
+=item atype - Text name of this agent type
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item create HASHREF
+
+Creates a new agent type.  To add the agent type to the database, see
+L<"insert">.
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_;
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('agent_type')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('agent_type',$hashref);
+
+}
+
+=item insert
+
+Adds this agent type to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  $self->check or
+  $self->add;
+}
+
+=item delete
+
+Deletes this agent type from the database.  Only agent types with no agents
+can be deleted.  If there is an error, returns the error, otherwise returns
+false.
+
+=cut
+
+sub delete {
+  my($self)=@_;
+  return "Can't delete an agent_type with agents!"
+    if qsearch('agent',{'typenum' => $self->typenum});
+  $self->del;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+  my($new,$old)=@_;
+  return "(Old) Not a agent_type record!" unless $old->table eq "agent_type";
+  return "Can't change typenum!"   
+    unless $old->getfield('typenum') eq $new->getfield('typenum');
+  $new->check or
+  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid agent type.  If there is an
+error, returns the error, otherwise returns false.  Called by the insert and
+replace methods.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a agent_type record!" unless $self->table eq "agent_type";
+
+  $self->ut_numbern('typenum')
+  or $self->ut_text('atype');
+
+}
+
+=back
+
+=head1 BUGS
+
+It doesn't properly override FS::Record yet.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::agent>, L<FS::type_pkgs>, L<FS::cust_main>,
+L<FS::part_pkg>, schema.html from the base documentation.
+
+=head1 HISTORY
+
+Class for the different sets of allowable packages you can assign to an
+agent.
+
+ivan@sisd.com 97-nov-13
+
+ut_ FS::Record methods
+ivan@sisd.com 97-dec-10
+
+Changed 'type' to 'atype' because Pg6.3 reserves the type word
+       bmccane@maxbaud.net     98-apr-3
+
+pod, added check in delete ivan@sisd.com 98-sep-21
+
+=cut
+
+1;
+
diff --git a/site_perl/cust_credit.pm b/site_perl/cust_credit.pm
new file mode 100644 (file)
index 0000000..b1a5e16
--- /dev/null
@@ -0,0 +1,199 @@
+package FS::cust_credit;
+
+use strict;
+use vars qw(@ISA @EXPORT_OK);
+use Exporter;
+use FS::UID qw(getotaker);
+use FS::Record qw(fields qsearchs);
+
+@ISA = qw(FS::Record Exporter);
+@EXPORT_OK = qw(fields);
+
+=head1 NAME
+
+FS::cust_credit - Object methods for cust_credit records
+
+=head1 SYNOPSIS
+
+  use FS::cust_credit;
+
+  $record = create FS::cust_credit \%hash;
+  $record = create FS::cust_credit { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_credit object represents a credit.  FS::cust_credit inherits from
+FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item crednum - primary key (assigned automatically for new credits)
+
+=item custnum - customer (see L<FS::cust_main>)
+
+=item amount - amount of the credit
+
+=item credited - how much of this credit that is still outstanding, which is
+amount minus all refunds (see L<FS::cust_refund>).
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=item otaker - order taker (assigned automatically, see L<FS::UID>)
+
+=item reason - text
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item create HASHREF
+
+Creates a new credit.  To add the credit to the database, see L<"insert">.
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_;
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('cust_credit')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('cust_credit',$hashref);
+}
+
+=item insert
+
+Adds this credit to the database ("Posts" the credit).  If there is an error,
+returns the error, otherwise returns false.
+
+When adding new invoices, credited must be amount (or null, in which case it is
+automatically set to amount).
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  $self->setfield('credited',$self->amount) if $self->credited eq '';
+  return "credited != amount!"
+    unless $self->credited == $self->amount;
+
+  $self->check or
+  $self->add;
+}
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+  return "Can't remove credit!"
+  #my($self)=@_;
+  #$self->del;
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+Only credited may be changed.  Credited is normally updated by creating and
+inserting a refund (see L<FS::cust_refund>).
+
+=cut
+
+sub replace {
+  my($new,$old)=@_;
+  return "(Old) Not a cust_credit record!" unless $old->table eq "cust_credit";
+  return "Can't change crednum!"
+    unless $old->getfield('crednum') eq $new->getfield('crednum');
+  return "Can't change custnum!"
+    unless $old->getfield('custnum') eq $new->getfield('custnum');
+  return "Can't change date!"
+    unless $old->getfield('_date') eq $new->getfield('_date');
+  return "Can't change amount!"
+    unless $old->getfield('amount') eq $new->getfield('amount');
+  return "(New) credited can't be > (new) amount!"
+    if $new->getfield('credited') > $new->getfield('amount');
+
+  $new->check or
+  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid credit.  If there is an error,
+returns the error, otherwise returns false.  Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a cust_credit record!" unless $self->table eq "cust_credit";
+  my($recref) = $self->hashref;
+
+  $recref->{crednum} =~ /^(\d*)$/ or return "Illegal crednum";
+  $recref->{crednum} = $1;
+
+  $recref->{custnum} =~ /^(\d+)$/ or return "Illegal custnum";
+  $recref->{custnum} = $1;
+  return "Unknown customer"
+    unless qsearchs('cust_main',{'custnum'=>$recref->{custnum}});
+
+  $recref->{_date} =~ /^(\d*)$/ or return "Illegal date";
+  $recref->{_date} = $recref->{_date} ? $1 : time;
+
+  $recref->{amount} =~ /^(\d+(\.\d\d)?)$/ or return "Illegal amount";
+  $recref->{amount} = $1;
+
+  $recref->{credited} =~ /^(\-?\d+(\.\d\d)?)$/ or return "Illegal credited";
+  $recref->{credited} = $1;
+
+  #$recref->{otaker} =~ /^(\w+)$/ or return "Illegal otaker";
+  #$recref->{otaker} = $1;
+  $self->otaker(getotaker);
+
+  $self->ut_textn('reason');
+
+}
+
+=back
+
+=head1 BUGS
+
+The delete method.
+
+It doesn't properly override FS::Record yet.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_refund>, L<FS::cust_bill>, schema.html from the base
+documentation.
+
+=head1 HISTORY
+
+ivan@sisd.com 98-mar-17
+
+pod, otaker from FS::UID ivan@sisd.com 98-sep-21
+
+=cut
+
+1;
+
diff --git a/site_perl/cust_main_county.pm b/site_perl/cust_main_county.pm
new file mode 100644 (file)
index 0000000..f4b4595
--- /dev/null
@@ -0,0 +1,161 @@
+package FS::cust_main_county;
+
+use strict;
+use vars qw(@ISA @EXPORT_OK);
+use Exporter;
+use FS::Record qw(fields hfields qsearch qsearchs);
+
+@ISA = qw(FS::Record Exporter);
+@EXPORT_OK = qw(hfields);
+
+=head1 NAME
+
+FS::cust_main_county - Object methods for cust_main_county objects
+
+=head1 SYNOPSIS
+
+  use FS::cust_main_county;
+
+  $record = create FS::cust_main_county \%hash;
+  $record = create FS::cust_main_county { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_main_county object represents a tax rate, defined by locale.
+FS::cust_main_county inherits from FS::Record.  The following fields are
+currently supported:
+
+=over 4
+
+=item taxnum - primary key (assigned automatically for new tax rates)
+
+=item state
+
+=item county
+
+=item tax - percentage
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item create HASHREF
+
+Creates a new tax rate.  To add the tax rate to the database, see L<"insert">.
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_;
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('cust_main_county')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('cust_main_county',$hashref);
+}
+
+=item insert
+
+Adds this tax rate to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  $self->check or
+  $self->add;
+}
+
+=item delete
+
+Deletes this tax rate from the database.  If there is an error, returns the
+error, otherwise returns false.
+
+=cut
+
+sub delete {
+  my($self)=@_;
+
+  $self->del;
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+  my($new,$old)=@_;
+  return "(Old) Not a cust_main_county record!"
+    unless $old->table eq "cust_main_county";
+  return "Can't change taxnum!"
+    unless $old->getfield('taxnum') eq $new->getfield('taxnum');
+  $new->check or
+  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid tax rate.  If there is an error,
+returns the error, otherwise returns false.  Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a cust_main_county record!"
+    unless $self->table eq "cust_main_county";
+  my($recref) = $self->hashref;
+
+  $self->ut_numbern('taxnum')
+    or $self->ut_text('state')
+    or $self->ut_textn('county')
+    or $self->ut_float('tax')
+  ;
+
+}
+
+=back
+
+=head1 BUGS
+
+It doesn't properly override FS::Record yet.
+
+A country field (and possibly a currency field) should be added.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>, L<FS::cust_bill>, schema.html from the base
+documentation.
+
+=head1 HISTORY
+
+ivan@voicenet.com 97-dec-16
+
+Changed check for 'tax' to use the new ut_float subroutine
+       bmccane@maxbaud.net     98-apr-3
+
+pod ivan@sisd.com 98-sep-21
+
+=cut
+
+1;
+
diff --git a/site_perl/cust_pay.pm b/site_perl/cust_pay.pm
new file mode 100644 (file)
index 0000000..6e30c59
--- /dev/null
@@ -0,0 +1,235 @@
+package FS::cust_pay;
+
+use strict;
+use vars qw(@ISA @EXPORT_OK);
+use Exporter;
+use Business::CreditCard;
+use FS::Record qw(fields qsearchs);
+use FS::cust_bill;
+
+@ISA = qw(FS::Record Exporter);
+@EXPORT_OK = qw(fields);
+
+=head1 NAME
+
+FS::cust_pay - Object methods for cust_pay objects
+
+=head1 SYNOPSIS
+
+  use FS::cust_pay;
+
+  $record = create FS::cust_pay \%hash;
+  $record = create FS::cust_pay { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_pay object represents a payment.  FS::cust_pay inherits from
+FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item paynum - primary key (assigned automatically for new payments)
+
+=item invnum - Invoice (see L<FS::cust_bill>)
+
+=item paid - Amount of this payment
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=item payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)
+
+=item payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)
+
+=item paybatch - text field for tracking card processing
+
+=back
+
+=head1 METHODS
+
+=over 4 
+
+=item create HASHREF
+
+Creates a new payment.  To add the payment to the databse, see L<"insert">.
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_;
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('cust_pay')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('cust_pay',$hashref);
+
+}
+
+=item insert
+
+Adds this payment to the databse, and updates the invoice (see
+L<FS::cust_bill>).
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  my($error);
+
+  $error=$self->check;
+  return $error if $error;
+
+  my($old_cust_bill) = qsearchs('cust_bill', {
+                                'invnum' => $self->getfield('invnum')
+                               } );
+  return "Unknown invnum" unless $old_cust_bill;
+  my(%hash)=$old_cust_bill->hash;
+  $hash{owed} = sprintf("%.2f",$hash{owed} - $self->getfield('paid') );
+  my($new_cust_bill) = create FS::cust_bill ( \%hash );
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+
+  $error=$new_cust_bill -> replace($old_cust_bill);
+  return "Error modifying cust_bill: $error" if $error;
+
+  $self->add;
+}
+
+=item delete
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub delete {
+  return "Can't (yet?) delete cust_pay records!";
+#template code below
+#  my($self)=@_;
+#
+#  $self->del;
+}
+
+=item replace OLD_RECORD
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub replace {
+   return "Can't (yet?) modify cust_pay records!";
+#template code below
+#  my($new,$old)=@_;
+#  return "(Old) Not a cust_pay record!" unless $old->table eq "cust_pay";
+#
+#  $new->check or
+#  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid payment.  If there is an error,
+returns the error, otherwise returns false.  Called by the insert method.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a cust_pay record!" unless $self->table eq "cust_pay";
+  my($recref) = $self->hashref;
+
+  $recref->{paynum} =~ /^(\d*)$/ or return "Illegal paynum";
+  $recref->{paynum} = $1;
+
+  $recref->{invnum} =~ /^(\d+)$/ or return "Illegal invnum";
+  $recref->{invnum} = $1;
+
+  $recref->{paid} =~ /^(\d+(\.\d\d)?)$/ or return "Illegal paid";
+  $recref->{paid} = $1;
+
+  $recref->{_date} =~ /^(\d*)$/ or return "Illegal date";
+  $recref->{_date} = $recref->{_date} ? $1 : time;
+
+  $recref->{payby} =~ /^(CARD|BILL|COMP)$/ or return "Illegal payby";
+  $recref->{payby} = $1;
+
+  if ( $recref->{payby} eq 'CARD' ) {
+
+    $recref->{payinfo} =~ s/\D//g;
+    if ( $recref->{payinfo} ) {
+      $recref->{payinfo} =~ /^(\d{13,16})$/
+        or return "Illegal (mistyped?) credit card number (payinfo)";
+      $recref->{payinfo} = $1;
+      #validate($recref->{payinfo})
+      #  or return "Illegal credit card number";
+      my($type)=cardtype($recref->{payinfo});
+      return "Unknown credit card type"
+        unless ( $type =~ /^VISA/ ||
+                 $type =~ /^MasterCard/ ||
+                 $type =~ /^American Express/ ||
+                 $type =~ /^Discover/ );
+    } else {
+      $recref->{payinfo}='N/A';
+    }
+
+  } elsif ( $recref->{payby} eq 'BILL' ) {
+
+    $recref->{payinfo} =~ /^([\w \-]*)$/
+      or return "Illegal P.O. number (payinfo)";
+    $recref->{payinfo} = $1;
+
+  } elsif ( $recref->{payby} eq 'COMP' ) {
+
+    $recref->{payinfo} =~ /^([\w]{2,8})$/
+      or return "Illegal comp account issuer (payinfo)";
+    $recref->{payinfo} = $1;
+
+  }
+
+  $recref->{paybatch} =~ /^([\w\-\:]*)$/
+    or return "Illegal paybatch";
+  $recref->{paybatch} = $1;
+
+  ''; #no error
+
+}
+
+=back
+
+=head1 BUGS
+
+It doesn't properly override FS::Record yet.
+
+Delete and replace methods.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_bill>, schema.html from the base documentation.
+
+=head1 HISTORY
+
+ivan@voicenet.com 97-jul-1 - 25 - 29
+
+new api ivan@sisd.com 98-mar-13
+
+pod ivan@sisd.com 98-sep-21
+
+=cut
+
+1;
+
diff --git a/site_perl/cust_svc.pm b/site_perl/cust_svc.pm
new file mode 100644 (file)
index 0000000..1d5051b
--- /dev/null
@@ -0,0 +1,168 @@
+package FS::cust_svc;
+
+use strict;
+use vars qw(@ISA);
+use Exporter;
+use FS::Record qw(fields qsearchs);
+
+@ISA = qw(FS::Record Exporter);
+
+=head1 NAME
+
+FS::cust_svc - Object method for cust_svc objects
+
+=head1 SYNOPSIS
+
+  use FS::cust_svc;
+
+  $record = create FS::cust_svc \%hash
+  $record = create FS::cust_svc { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_svc represents a service.  FS::cust_svc inherits from FS::Record.
+The following fields are currently supported:
+
+=over 4
+
+=item svcnum - primary key (assigned automatically for new services)
+
+=item pkgnum - Package (see L<FS::cust_pkg>)
+
+=item svcpart - Service definition (see L<FS::part_svc>)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item create HASHREF
+
+Creates a new service.  To add the refund to the database, see L<"insert">.
+Services are normally created by creating FS::svc_ objects (see
+L<FS::svc_acct>, L<FS::svc_domain>, and L<FS::svc_acct_sm>, among others).
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_; 
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('cust_svc')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('cust_svc',$hashref);
+}
+
+=item insert
+
+Adds this service to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  $self->check or
+  $self->add;
+}
+
+=item delete
+
+Deletes this service from the database.  If there is an error, returns the
+error, otherwise returns false.
+
+Called by the cancel method of the package (see L<FS::cust_pkg>).
+
+=cut
+
+sub delete {
+  my($self)=@_;
+  # anything else here?
+  $self->del;
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+  my($new,$old)=@_;
+  return "(Old) Not a cust_svc record!" unless $old->table eq "cust_svc";
+  return "Can't change svcnum!"
+    unless $old->getfield('svcnum') eq $new->getfield('svcnum');
+  $new->check or
+  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid service.  If there is an error,
+returns the error, otehrwise returns false.  Called by the insert and
+replace methods.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a cust_svc record!" unless $self->table eq "cust_svc";
+  my($recref) = $self->hashref;
+
+  $recref->{svcnum} =~ /^(\d*)$/ or return "Illegal svcnum";
+  $recref->{svcnum}=$1;
+
+  $recref->{pkgnum} =~ /^(\d*)$/ or return "Illegal pkgnum";
+  $recref->{pkgnum}=$1;
+  return "Unknown pkgnum" unless
+    ! $recref->{pkgnum} ||
+    qsearchs('cust_pkg',{'pkgnum'=>$recref->{pkgnum}});
+
+  $recref->{svcpart} =~ /^(\d+)$/ or return "Illegal svcpart";
+  $recref->{svcpart}=$1;
+  return "Unknown svcpart" unless
+    qsearchs('part_svc',{'svcpart'=>$recref->{svcpart}});
+
+  ''; #no error
+}
+
+=back
+
+=head1 BUGS
+
+Behaviour of changing the svcpart of cust_svc records is undefined and should
+possibly be prohibited, and pkg_svc records are not checked.
+
+pkg_svc records are not checket in general (here).
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_pkg>, L<FS::part_svc>, L<FS::pkg_svc>, 
+schema.html from the base documentation
+
+=head1 HISTORY
+
+ivan@voicenet.com 97-jul-10,14
+
+no TableUtil, no FS::Lock ivan@sisd.com 98-mar-7
+
+pod ivan@sisd.com 98-sep-21
+
+=cut
+
+1;
+
diff --git a/site_perl/part_pkg.pm b/site_perl/part_pkg.pm
new file mode 100644 (file)
index 0000000..d1c12e4
--- /dev/null
@@ -0,0 +1,168 @@
+package FS::part_pkg;
+
+use strict;
+use vars qw(@ISA @EXPORT_OK);
+use Exporter;
+use FS::Record qw(fields hfields);
+
+@ISA = qw(FS::Record Exporter);
+@EXPORT_OK = qw(hfields fields);
+
+=head1 NAME
+
+FS::part_pkg - Object methods for part_pkg objects
+
+=head1 SYNOPSIS
+
+  use FS::part_pkg;
+
+  $record = create FS::part_pkg \%hash
+  $record = create FS::part_pkg { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_pkg represents a billing item definition.  FS::part_pkg inherits
+from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item pkgpart - primary key (assigned automatically for new billing item definitions)
+
+=item pkg - Text name of this billing item definition (customer-viewable)
+
+=item comment - Text name of this billing item definition (non-customer-viewable)
+
+=item setup - Setup fee
+
+=item freq - Frequency of recurring fee
+
+=item recur - Recurring fee
+
+=back
+
+setup and recur are evaluated as Safe perl expressions.  You can use numbers
+just as you would normally.  More advanced semantics are not yet defined.
+
+=head1 METHODS
+
+=over 4 
+
+=item create HASHREF
+
+Creates a new billing item definition.  To add the billing item definition to
+the database, see L<"insert">.
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_;
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('part_pkg')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('part_pkg',$hashref);
+}
+
+=item insert
+
+Adds this billing item definition to the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  $self->check or
+  $self->add;
+}
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+  return "Can't (yet?) delete package definitions.";
+# maybe check & make sure the pkgpart isn't in cust_pkg or type_pkgs?
+#  my($self)=@_;
+#
+#  $self->del;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+  my($new,$old)=@_;
+  return "(Old) Not a part_pkg record!" unless $old->table eq "part_pkg";
+  return "Can't change pkgpart!"
+    unless $old->getfield('pkgpart') eq $new->getfield('pkgpart');
+  $new->check or
+  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid billing item definition.  If
+there is an error, returns the error, otherwise returns false.  Called by the
+insert and replace methods.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a part_pkg record!" unless $self->table eq "part_pkg";
+
+  $self->ut_numbern('pkgpart')
+    or $self->ut_text('pkg')
+    or $self->ut_text('comment')
+    or $self->ut_anything('setup')
+    or $self->ut_number('freq')
+    or $self->ut_anything('recur')
+  ;
+
+}
+
+=back
+
+=head1 BUGS
+
+It doesn't properly override FS::Record yet.
+
+The delete method is unimplemented.
+
+setup and recur semantics are not yet defined (and are implemented in
+FS::cust_bill.  hmm.).
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_pkg>, L<FS::type_pkgs>, L<FS::pkg_svc>, L<Safe>.
+schema.html from the base documentation.
+
+=head1 HISTORY
+
+ivan@sisd.com 97-dec-5
+
+pod ivan@sisd.com 98-sep-21
+
+=cut
+
+1;
+
diff --git a/site_perl/part_referral.pm b/site_perl/part_referral.pm
new file mode 100644 (file)
index 0000000..1b4a1b6
--- /dev/null
@@ -0,0 +1,155 @@
+package FS::part_referral;
+
+use strict;
+use vars qw(@ISA @EXPORT_OK);
+use Exporter;
+use FS::Record qw(fields qsearchs);
+
+@ISA = qw(FS::Record Exporter);
+@EXPORT_OK = qw(fields);
+
+=head1 NAME
+
+FS::part_referral - Object methods for part_referral objects
+
+=head1 SYNOPSIS
+
+  use FS::part_referral;
+
+  $record = create FS::part_referral \%hash
+  $record = create FS::part_referral { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_referral represents a referral - where a customer heard of your
+services.  This can be used to track the effectiveness of a particular piece of
+advertising, for example.  FS::part_referral inherits from FS::Record.  The
+following fields are currently supported:
+
+=over 4
+
+=item refnum - primary key (assigned automatically for new referrals)
+
+=item referral - Text name of this referral
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item create HASHREF
+
+Creates a new referral.  To add the referral to the database, see L<"insert">.
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_;
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('part_referral')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('part_referral',$hashref);
+}
+
+=item insert
+
+Adds this referral to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  $self->check or
+  $self->add;
+}
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+  my($self)=@_;
+  return "Can't (yet?) delete part_referral records";
+  #$self->del;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+  my($new,$old)=@_;
+  return "(Old) Not an part_referral record!" 
+    unless $old->table eq "part_referral";
+  return "Can't change refnum!"
+    unless $old->getfield('refnum') eq $new->getfield('refnum');
+  $new->check or
+  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid referral.  If there is an error,
+returns the error, otherwise returns false.  Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a part_referral record!" unless $self->table eq "part_referral";
+
+  my($error)=
+    $self->ut_numbern('refnum')
+      or $self->ut_text('referral')
+  ;
+  return $error if $error;
+
+  '';
+
+}
+
+=back
+
+=head1 BUGS
+
+It doesn't properly override FS::Record yet.
+
+The delete method is unimplemented.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>, schema.html from the base documentation.
+
+=head1 HISTORY
+
+Class dealing with referrals
+
+ivan@sisd.com 98-feb-23
+
+pod ivan@sisd.com 98-sep-21
+
+=cut
+
+1;
+
diff --git a/site_perl/pkg_svc.pm b/site_perl/pkg_svc.pm
new file mode 100644 (file)
index 0000000..517125c
--- /dev/null
@@ -0,0 +1,168 @@
+package FS::pkg_svc;
+
+use strict;
+use vars qw(@ISA @EXPORT_OK);
+use Exporter;
+use FS::Record qw(fields hfields qsearchs);
+
+@ISA = qw(FS::Record Exporter);
+@EXPORT_OK = qw(hfields);
+
+=head1 NAME
+
+FS::pkg_svc - Object methods for pkg_svc records
+
+=head1 SYNOPSIS
+
+  use FS::pkg_svc;
+
+  $record = create FS::pkg_svc \%hash;
+  $record = create FS::pkg_svc { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::pkg_svc record links a billing item definition (see L<FS::part_pkg>) to
+a service definition (see L<FS::part_svc>).  FS::pkg_svc inherits from
+FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item pkgpart - Billing item definition (see L<FS::part_pkg>)
+
+=item svcpart - Service definition (see L<FS::part_svc>)
+
+=item quantity - Quantity of this service definition that this billing item
+definition includes
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item create HASHREF
+
+Create a new record.  To add the record to the database, see L<"insert">.
+
+=cut
+
+sub create {
+  my($proto,$hashref)=@_;
+
+  #now in FS::Record::new
+  #my($field);
+  #foreach $field (fields('pkg_svc')) {
+  #  $hashref->{$field}='' unless defined $hashref->{$field};
+  #}
+
+  $proto->new('pkg_svc',$hashref);
+
+}
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+  my($self)=@_;
+
+  $self->check or
+  $self->add;
+}
+
+=item delete
+
+Deletes this record from the database.  If there is an error, returns the
+error, otherwise returns false.
+
+=cut
+
+sub delete {
+  my($self)=@_;
+
+  $self->del;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+  my($new,$old)=@_;
+  return "(Old) Not a pkg_svc record!" unless $old->table eq "pkg_svc";
+  return "Can't change pkgpart!"
+    if $old->getfield('pkgpart') ne $new->getfield('pkgpart');
+  return "Can't change svcpart!"
+    if $old->getfield('svcpart') ne $new->getfield('svcpart');
+
+  $new->check or
+  $new->rep($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is an error,
+returns the error, otherwise returns false.  Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+  my($self)=@_;
+  return "Not a pkg_svc record!" unless $self->table eq "pkg_svc";
+  my($recref) = $self->hashref;
+
+  my($error);
+  return $error if $error =
+    $self->ut_number('pkgpart')
+    || $self->ut_number('svcpart')
+    || $self->ut_number('quantity')
+  ;
+
+  return "Unknown pkgpart!"
+    unless qsearchs('part_pkg',{'pkgpart'=> $self->getfield('pkgpart')});
+
+  return "Unknown svcpart!"
+    unless qsearchs('part_svc',{'svcpart'=> $self->getfield('svcpart')});
+
+  ''; #no error
+}
+
+=back
+
+=head1 BUGS
+
+It doesn't properly override FS::Record yet.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::part_pkg>, L<FS::part_svc>, schema.html from the base
+documentation.
+
+=head1 HISTORY
+
+ivan@voicenet.com 97-jul-1
+added hfields
+ivan@sisd.com 97-nov-13
+
+pod ivan@sisd.com 98-sep-22
+
+=cut
+
+1;
+