summaryrefslogtreecommitdiff
path: root/FS/FS/part_event.pm
diff options
context:
space:
mode:
Diffstat (limited to 'FS/FS/part_event.pm')
-rw-r--r--FS/FS/part_event.pm444
1 files changed, 444 insertions, 0 deletions
diff --git a/FS/FS/part_event.pm b/FS/FS/part_event.pm
new file mode 100644
index 0000000..c98c3f8
--- /dev/null
+++ b/FS/FS/part_event.pm
@@ -0,0 +1,444 @@
+package FS::part_event;
+
+use strict;
+use vars qw( @ISA $DEBUG );
+use Carp qw(confess);
+use FS::Record qw( dbh qsearch qsearchs );
+use FS::option_Common;
+use FS::m2name_Common;
+use FS::Conf;
+use FS::part_event_option;
+use FS::part_event_condition;
+use FS::cust_event;
+use FS::agent;
+
+@ISA = qw( FS::m2name_Common FS::option_Common ); # FS::Record );
+$DEBUG = 0;
+
+=head1 NAME
+
+FS::part_event - Object methods for part_event records
+
+=head1 SYNOPSIS
+
+ use FS::part_event;
+
+ $record = new FS::part_event \%hash;
+ $record = new FS::part_event { 'column' => 'value' };
+
+ $error = $record->insert( { 'option' => 'value' } );
+ $error = $record->insert( \%options );
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->do_event( $direct_object );
+
+=head1 DESCRIPTION
+
+An FS::part_event object represents an event definition - a billing, collection
+or other callback which is triggered when certain customer, invoice, package or
+other conditions are met. FS::part_event inherits from FS::Record. The
+following fields are currently supported:
+
+=over 4
+
+=item eventpart - primary key
+
+=item agentnum - Optional agentnum (see L<FS::agent>)
+
+=item event - event name
+
+=item eventtable - table name against which this event is triggered; currently "cust_bill" (the traditional invoice events), "cust_main" (customer events) or "cust_pkg (package events) (or "cust_statement")
+
+=item check_freq - how often events of this type are checked; currently "1d" (daily) and "1m" (monthly) are recognized. Note that the apprioriate freeside-daily and/or freeside-monthly cron job needs to be in place.
+
+=item weight - ordering for events
+
+=item action - event action (like part_bill_event.plan - eventcode plan)
+
+=item disabled - Disabled flag, empty or `Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new invoice event definition. To add the invoice event definition to
+the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'part_event'; }
+
+=item insert [ HASHREF ]
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+If a list or hash reference of options is supplied, part_export_option records
+are created (see L<FS::part_event_option>).
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD [ HASHREF | OPTION => VALUE ... ]
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+If a list or hash reference of options is supplied, part_event_option
+records are created or modified (see L<FS::part_event_option>).
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid invoice event definition. If
+there is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ $self->weight(0) unless $self->weight;
+
+ my $error =
+ $self->ut_numbern('eventpart')
+ || $self->ut_text('event')
+ || $self->ut_enum('eventtable', [ $self->eventtables ] )
+ || $self->ut_enum('check_freq', [ '1d', '1m' ])
+ || $self->ut_number('weight')
+ || $self->ut_alpha('action')
+ || $self->ut_enum('disabled', [ '', 'Y' ] )
+ || $self->ut_agentnum_acl('agentnum', 'Edit global billing events')
+ ;
+ return $error if $error;
+
+ #XXX check action to make sure a module exists?
+ # well it'll die in _rebless...
+
+ $self->SUPER::check;
+}
+
+=item _rebless
+
+Reblesses the object into the FS::part_event::Action::ACTION class, where
+ACTION is the object's I<action> field.
+
+=cut
+
+sub _rebless {
+ my $self = shift;
+ my $action = $self->action or return $self;
+ #my $class = ref($self). "::$action";
+ my $class = "FS::part_event::Action::$action";
+ eval "use $class";
+ die $@ if $@;
+ bless($self, $class); # unless $@;
+ $self;
+}
+
+=item part_event_condition
+
+Returns the conditions associated with this event, as FS::part_event_condition
+objects (see L<FS::part_event_condition>)
+
+=cut
+
+sub part_event_condition {
+ my $self = shift;
+ qsearch( 'part_event_condition', { 'eventpart' => $self->eventpart } );
+}
+
+=item new_cust_event OBJECT
+
+Creates a new customer event (see L<FS::cust_event>) for the provided object.
+
+=cut
+
+sub new_cust_event {
+ my( $self, $object ) = @_;
+
+ confess "**** $object is not a ". $self->eventtable
+ if ref($object) ne "FS::". $self->eventtable;
+
+ my $pkey = $object->primary_key;
+
+ new FS::cust_event {
+ 'eventpart' => $self->eventpart,
+ 'tablenum' => $object->$pkey(),
+ '_date' => time, #i think we always want the real "now" here.
+ 'status' => 'new',
+ };
+}
+
+#surely this doesn't work
+sub reasontext { confess "part_event->reasontext deprecated"; }
+#=item reasontext
+#
+#Returns the text of any reason associated with this event.
+#
+#=cut
+#
+#sub reasontext {
+# my $self = shift;
+# my $r = qsearchs('reason', { 'reasonnum' => $self->reason });
+# if ($r){
+# $r->reason;
+# }else{
+# '';
+# }
+#}
+
+=item agent
+
+Returns the associated agent for this event, if any, as an FS::agent object.
+
+=cut
+
+sub agent {
+ my $self = shift;
+ qsearchs('agent', { 'agentnum' => $self->agentnum } );
+}
+
+=item templatename
+
+Returns the alternate invoice template name, if any, or false if there is
+no alternate template for this event.
+
+=cut
+
+sub templatename {
+
+ my $self = shift;
+ if ( $self->action =~ /^cust_bill_send_(alternate|agent)$/
+ && ( $self->option('agent_templatename')
+ || $self->option('templatename') )
+ )
+ {
+ $self->option('agent_templatename')
+ || $self->option('templatename');
+
+ } else {
+ '';
+ }
+}
+
+=back
+
+=head1 CLASS METHODS
+
+=over 4
+
+=item eventtable_labels
+
+Returns a hash reference of labels for eventtable values,
+i.e. 'cust_main'=>'Customer'
+
+=cut
+
+sub eventtable_labels {
+ #my $class = shift;
+
+ tie my %hash, 'Tie::IxHash',
+ 'cust_pkg' => 'Package',
+ 'cust_bill' => 'Invoice',
+ 'cust_main' => 'Customer',
+ 'cust_pay_batch' => 'Batch payment',
+ 'cust_statement' => 'Statement', #too general a name here? "Invoice group"?
+ ;
+
+ \%hash
+}
+
+=item eventtable_pkey_sql
+
+Returns a hash reference of full SQL primary key names for eventtable values,
+i.e. 'cust_main'=>'cust_main.custnum'
+
+=cut
+
+sub eventtable_pkey_sql {
+ my $class = shift;
+
+ my $hashref = $class->eventtable_pkey;
+
+ my %hash = map { $_ => "$_.". $hashref->{$_} } keys %$hashref;
+
+ \%hash;
+}
+
+=item eventtable_pkey
+
+Returns a hash reference of full SQL primary key names for eventtable values,
+i.e. 'cust_main'=>'custnum'
+
+=cut
+
+sub eventtable_pkey {
+ #my $class = shift;
+
+ {
+ 'cust_main' => 'custnum',
+ 'cust_bill' => 'invnum',
+ 'cust_pkg' => 'pkgnum',
+ 'cust_pay_batch' => 'paybatchnum',
+ 'cust_statement' => 'statementnum',
+ };
+}
+
+=item eventtables
+
+Returns a list of eventtable values (default ordering; suited for display).
+
+=cut
+
+sub eventtables {
+ my $class = shift;
+ my $eventtables = $class->eventtable_labels;
+ keys %$eventtables;
+}
+
+=item eventtables_runorder
+
+Returns a list of eventtable values (run order).
+
+=cut
+
+sub eventtables_runorder {
+ shift->eventtables; #same for now
+}
+
+=item check_freq_labels
+
+Returns a hash reference of labels for check_freq values,
+i.e. '1d'=>'daily'
+
+=cut
+
+sub check_freq_labels {
+ #my $class = shift;
+
+ #Tie::IxHash??
+ {
+ '1d' => 'daily',
+ '1m' => 'monthly',
+ };
+}
+
+=item actions [ EVENTTABLE ]
+
+Return information about the available actions. If an eventtable is specified,
+only return information about actions available for that eventtable.
+
+Information is returned as key-value pairs. Keys are event names. Values are
+hashrefs with the following keys:
+
+=over 4
+
+=item description
+
+=item eventtable_hashref
+
+=item option_fields
+
+=item default_weight
+
+=item deprecated
+
+=back
+
+See L<FS::part_event::Action> for more information.
+
+=cut
+
+#false laziness w/part_event_condition.pm
+#some false laziness w/part_export & part_pkg
+my %actions;
+foreach my $INC ( @INC ) {
+ foreach my $file ( glob("$INC/FS/part_event/Action/*.pm") ) {
+ warn "attempting to load Action from $file\n" if $DEBUG;
+ $file =~ /\/(\w+)\.pm$/ or do {
+ warn "unrecognized file in $INC/FS/part_event/Action/: $file\n";
+ next;
+ };
+ my $mod = $1;
+ eval "use FS::part_event::Action::$mod;";
+ if ( $@ ) {
+ die "error using FS::part_event::Action::$mod (skipping): $@\n" if $@;
+ #warn "error using FS::part_event::Action::$mod (skipping): $@\n" if $@;
+ #next;
+ }
+ $actions{$mod} = {
+ ( map { $_ => "FS::part_event::Action::$mod"->$_() }
+ qw( description eventtable_hashref default_weight deprecated )
+ #option_fields_hashref
+ ),
+ 'option_fields' => [ "FS::part_event::Action::$mod"->option_fields() ],
+ };
+ }
+}
+
+sub actions {
+ my( $class, $eventtable ) = @_;
+ (
+ map { $_ => $actions{$_} }
+ sort { $actions{$a}->{'default_weight'}<=>$actions{$b}->{'default_weight'} }
+ $class->all_actions( $eventtable )
+ );
+
+}
+
+=item all_actions [ EVENTTABLE ]
+
+Returns a list of just the action names
+
+=cut
+
+sub all_actions {
+ my ( $class, $eventtable ) = @_;
+
+ grep { !$eventtable || $actions{$_}->{'eventtable_hashref'}{$eventtable} }
+ keys %actions
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::part_event_option>, L<FS::part_event_condition>, L<FS::cust_main>,
+L<FS::cust_pkg>, L<FS::cust_bill>, L<FS::cust_bill_event>, L<FS::Record>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+