[freeside-commits] freeside/FS/FS/part_event/Condition agent.pm, NONE, 1.1 agent_type.pm, NONE, 1.1 balance.pm, NONE, 1.1 balance_age.pm, NONE, 1.1 balance_under.pm, NONE, 1.1 cust_bill_age.pm, NONE, 1.1 cust_bill_owed.pm, NONE, 1.1 cust_bill_owed_under.pm, NONE, 1.1 cust_pay_batch_declined.pm, NONE, 1.1 cust_status.pm, NONE, 1.1 every.pm, NONE, 1.1 once.pm, NONE, 1.1 payby.pm, NONE, 1.1 pkg_class.pm, NONE, 1.1 pkg_status.pm, NONE, 1.1

Ivan,,, ivan at wavetail.420.am
Wed Aug 1 15:24:43 PDT 2007


Update of /home/cvs/cvsroot/freeside/FS/FS/part_event/Condition
In directory wavetail:/tmp/cvs-serv23435/FS/FS/part_event/Condition

Added Files:
	agent.pm agent_type.pm balance.pm balance_age.pm 
	balance_under.pm cust_bill_age.pm cust_bill_owed.pm 
	cust_bill_owed_under.pm cust_pay_batch_declined.pm 
	cust_status.pm every.pm once.pm payby.pm pkg_class.pm 
	pkg_status.pm 
Log Message:
event refactor, landing on HEAD!

--- NEW FILE: cust_bill_owed_under.pm ---
package FS::part_event::Condition::cust_bill_owed_under;

use strict;
use FS::cust_bill;

use base qw( FS::part_event::Condition );

sub description {
  'Amount owed on specific invoice (under)';
}

sub eventtable_hashref {
    { 'cust_main' => 0,
      'cust_bill' => 1,
      'cust_pkg'  => 0,
    };
}

sub option_fields {
  (
    'owed' => { 'label'      => 'Amount owed under (or equal to)',
                'type'       => 'money',
                'value'      => '0.00', #default
              },
  );
}

sub condition {
  #my($self, $cust_bill, %opt) = @_;
  my($self, $cust_bill) = @_;

  my $under = $self->option('owed');
  $under = 0 unless length($under);

  $cust_bill->owed <= $under;

}

sub condition_sql {
  my( $class, $table ) = @_;
  
  my $under = $class->condition_sql_option('owed');

  my $owed_sql = FS::cust_bill->owed_sql;

  "$owed_sql <= $under";
}

1;

--- NEW FILE: cust_bill_owed.pm ---
package FS::part_event::Condition::cust_bill_owed;

use strict;
use FS::cust_bill;

use base qw( FS::part_event::Condition );

sub description {
  'Amount owed on specific invoice';
}

sub eventtable_hashref {
    { 'cust_main' => 0,
      'cust_bill' => 1,
      'cust_pkg'  => 0,
    };
}

sub option_fields {
  (
    'owed' => { 'label'      => 'Amount owed over',
                'type'       => 'money',
                'value'      => '0.00', #default
              },
  );
}

sub condition {
  #my($self, $cust_bill, %opt) = @_;
  my($self, $cust_bill) = @_;

  my $over = $self->option('owed');
  $over = 0 unless length($over);

  $cust_bill->owed > $over;
}

sub condition_sql {
  my( $class, $table ) = @_;
  
  my $over = $class->condition_sql_option('owed');

  my $owed_sql = FS::cust_bill->owed_sql;

  "$owed_sql > $over";
}

1;

--- NEW FILE: payby.pm ---
package FS::part_event::Condition::payby;

use strict;
use Tie::IxHash;
use FS::payby;

use base qw( FS::part_event::Condition );

sub description {
  #'customer payment types: ';
  'Customer payment type';
}

#something like this
tie my %payby, 'Tie::IxHash', FS::payby->cust_payby2longname;
sub option_fields {
  (
    'payby' => { 
                 label         => 'Customer payment type',
                 #type          => 'select-multiple',
                 type          => 'checkbox-multiple',
                 options       => [ keys %payby ],
                 option_labels => \%payby,
               },
  );
}

sub condition {
  my( $self, $object ) = @_;

  my $cust_main = $self->cust_main($object);

  #uuh.. all right?  test this.
  my $hashref = $self->option('payby') || {};
  $hashref->{ $cust_main->payby };

}

#sub condition_sql {
#  my( $self, $table ) = @_;
#
#  #uuh... yeah... something like this.  test it for sure.
#
#  my @payby = keys %{ $self->option('payby') };
#
#  ' ( '. join(' OR ', map { "cust_main.payby = '$_'" } @payby ). ' ) ';
#
#}

1;

--- NEW FILE: pkg_status.pm ---
package FS::part_event::Condition::pkg_status;

use strict;

use base qw( FS::part_event::Condition );
use FS::Record qw( qsearch );

sub description {
  'Package Status';
}

sub eventtable_hashref {
    { 'cust_main' => 0,
      'cust_bill' => 0,
      'cust_pkg'  => 1,
    };
}

#something like this
sub option_fields {
  (
    'status'  => { 'label'    => 'Package Status',
                   'type'     => 'select-cust_pkg-status',
                   'multiple' => 1,
                 },
  );
}

sub condition {
  my( $self, $cust_pkg ) = @_;

  #XXX test
  my $hashref = $self->option('status') || {};
  $hashref->{ $cust_pkg->status };
}

1;

--- NEW FILE: balance_under.pm ---
package FS::part_event::Condition::balance_under;

use strict;
use FS::cust_main;

use base qw( FS::part_event::Condition );

sub description { 'Customer balance (under)'; }

sub option_fields {
  (
    'balance' => { 'label'      => 'Balance under (or equal to)',
                   'type'       => 'money',
                   'value'      => '0.00', #default
                 },
  );
}

sub condition {
  my($self, $object) = @_;

  my $cust_main = $self->cust_main($object);

  my $under = $self->option('balance');
  $under = 0 unless length($under);

  $cust_main->balance <= $under;
}

sub condition_sql {
  my( $class, $table ) = @_;

  my $under = $class->condition_sql_option('balance');

  my $balance_sql = FS::cust_main->balance_sql;

  "$balance_sql <= $under";

}

1;


--- NEW FILE: once.pm ---
package FS::part_event::Condition::once;

use strict;
use FS::Record qw( qsearch );
use FS::part_event;
use FS::cust_event;

use base qw( FS::part_event::Condition );

sub description { "Don't run this event again after it has completed sucessfully"; }

sub implicit_flag { 10; }

sub remove_warning {
  'Are you sure you want to remove this condition?  Doing so will allow this event to run every time the other conditions are satisfied, even if it has already run sucessfully.'; #better error msg?
}

sub condition {
  my($self, $object) = @_;

  my $obj_pkey = $object->primary_key;
  my $tablenum = $object->$obj_pkey();
  
  my @existing = qsearch( 'cust_event', {
    'eventpart' => $self->eventpart,
    'tablenum'  => $tablenum,
    'status'    => { op=>'!=', value=>'failed' },
  } );

  ! scalar(@existing);

}

sub condition_sql {
  my( $self, $table ) = @_;

  my %tablenum = %{ FS::part_event->eventtable_pkey_sql };

  "0 = ( SELECT COUNT(*) FROM cust_event
           WHERE cust_event.eventpart = part_event.eventpart
             AND cust_event.tablenum = $tablenum{$table}
             AND status != 'failed'
       )
  ";

}

1;

--- NEW FILE: balance_age.pm ---
package FS::part_event::Condition::balance_age;

require 5.006;
use strict;
use Time::Local qw(timelocal_nocheck);

use base qw( FS::part_event::Condition );

sub description { 'Customer balance age'; }

sub option_fields {
  (
    'balance' => { 'label'      => 'Balance over',
                   'type'       => 'money',
                   'value'      => '0.00', #default
                 },
    'age'     => { 'label'      => 'Age',
                   'type'       => 'freq',
                 },
  );
}

sub condition {
  my($self, $object, %opt) = @_;

  my $cust_main = $self->cust_main($object);

  my $over = $self->option('balance');
  $over = 0 unless length($over);

  #false laziness w/cust_bill_age
  my $time = $opt{'time'};
  my $age = $self->option('age');
  $age = '0m' unless length($age);

  my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($time) )[0,1,2,3,4,5];
  if ( $age =~ /^(\d+)m$/i ) {
    $mon -= $1;
    until ( $mon >= 0 ) { $mon += 12; $year--; }
  } elsif ( $age =~ /^(\d+)y$/i ) {
    $year -= $1;
  } elsif ( $age =~ /^(\d+)w$/i ) {
    $mday -= $1 * 7;
  } elsif ( $age =~ /^(\d+)d$/i ) {
    $mday -= $1;
  } elsif ( $age =~ /^(\d+)h$/i ) {
    $hour -= $hour;
  } else {
    die "unparsable age: $age";
  }
  my $age_date = timelocal_nocheck($sec,$min,$hour,$mday,$mon,$year);

  $cust_main->balance_date($age_date) > $over;
}

sub condition_sql {
  my( $class, $table, %opt ) = @_;

  my $time = $opt{'time'};

  my $over = $class->condition_sql_option('balance');
  my $age = $class->condition_sql_option('age');
  my $age_sql =
    "$time - EXTRACT( EPOCH FROM REPLACE( $age, 'm', 'mon')::interval )";

  my $balance_sql = FS::cust_main->balance_date_sql( $age_sql );

  "$balance_sql > $over";

}

sub order_sql {
  my( $class ) = @_;

  my $age = $class->condition_sql_option('age');
  "EXTRACT( EPOCH FROM REPLACE( $age, 'm', 'mon')::interval )";
}

sub order_sql_weight {
  10;
}

1;

--- NEW FILE: every.pm ---
package FS::part_event::Condition::every;

use strict;
use FS::UID qw( dbh );
use FS::Record qw( qsearch );
use FS::cust_event;

use base qw( FS::part_event::Condition );

sub description { "Don't retry failures more often than specified interval"; }

sub option_fields {
  (
    'retry_delay' => { label=>'Retry after', type=>'freq', value=>'1d', },
    'max_tries'   => { label=>'Maximum # of attempts', type=>'text', size=>3, },
  );
}

my %after = (
  'h' =>     3600,
  'd' =>    86400,
  'w' =>   604800,
  'm' =>  2592000, #well, 30 days... presumably people would mostly use d or w
  ''  =>  2592000,
  'y' => 31536000, #well, 365 days...
);

my $sql =
  "SELECT COUNT(*) FROM cust_event WHERE eventpart = ? AND tablenum = ?";

sub condition {
  my($self, $object, %opt) = @_;

  my $obj_pkey = $object->primary_key;
  my $tablenum = $object->$obj_pkey();

  if ( $self->option('max_tries') =~ /^\s*(\d+)\s*$/ ) {
    my $max_tries = $1;
    my $sth = dbh->prepare($sql)
      or die dbh->errstr. " preparing: $sql";
    $sth->execute($self->eventpart, $tablenum)
      or die $sth->errstr. " executing: $sql";
    my $tries = $sth->fetchrow_arrayref->[0];
    return 0 if $tries >= $max_tries;
  }

  my $time = $opt{'time'};
  my $retry_delay = $self->option('retry_delay');
  $retry_delay =~ /^(\d+)([hdwmy]?)$/
    or die "unparsable retry_delay: $retry_delay";
  my $date_after = $time - $1 * $after{$2};

  my $sth = dbh->prepare("$sql AND date > ?") # AND status = 'failed' "
    or die  dbh->errstr. " preparing: $sql";
  $sth->execute($self->eventpart, $tablenum, $date_after)
    or die $sth->errstr. " executing: $sql";
  ! $sth->fetchrow_arrayref->[0];

}

#sub condition_sql {
#  my( $self, $table ) = @_;
#
#  'true';
#}

1;

--- NEW FILE: agent.pm ---
package FS::part_event::Condition::agent;

use strict;

use base qw( FS::part_event::Condition );

# see the FS::part_event::Condition manpage for full documentation on each
# of the required and optional methods.

sub description {
  'Agent';
}

sub option_fields {
  (
    'agentnum'   => { label=>'Agent', type=>'select-agent', },
  );
}

sub condition {
  my($self, $object, %opt) = @_;

  my $cust_main = $self->cust_main($object);

  my $agentnum = $self->option('agentnum');

  $cust_main->agentnum == $agentnum;

}

#sub condition_sql {
#  my( $self, $table ) = @_;
#
#  'true';
#}

1;

--- NEW FILE: cust_status.pm ---
package FS::part_event::Condition::cust_status;

use strict;

use base qw( FS::part_event::Condition );
use FS::Record qw( qsearch );

sub description {
  'Customer Status';
}

#something like this
sub option_fields {
  (
    'status'  => { 'label'    => 'Customer Status',
                   'type'     => 'select-cust_main-status',
                   'multiple' => 1,
                 },
  );
}

sub condition {
  my( $self, $object) = @_;

  my $cust_main = $self->cust_main($object);

  #XXX test
  my $hashref = $self->option('status') || {};
  $hashref->{ $cust_main->status };
}

1;

--- NEW FILE: cust_bill_age.pm ---
package FS::part_event::Condition::cust_bill_age;

require 5.006;
use strict;
use Time::Local qw(timelocal_nocheck);

use base qw( FS::part_event::Condition );

sub description {
  'Invoice age';
}

sub eventtable_hashref {
    { 'cust_main' => 0,
      'cust_bill' => 1,
      'cust_pkg'  => 0,
    };
}

#something like this
sub option_fields {
  (
    #'days' => { label=>'Days', size=>3, },
    'age' => { label=>'Age', type=>'freq', },
  );
}

sub condition {
  my( $self, $cust_bill, %opt ) = @_;

  #false laziness w/balance_age
  my $time = $opt{'time'};
  my $age = $self->option('age');
  $age = '0m' unless length($age);

  my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($time) )[0,1,2,3,4,5];
  if ( $age =~ /^(\d+)m$/i ) {
    $mon -= $1;
    until ( $mon >= 0 ) { $mon += 12; $year--; }
  } elsif ( $age =~ /^(\d+)y$/i ) {
    $year -= $1;
  } elsif ( $age =~ /^(\d+)w$/i ) {
    $mday -= $1 * 7;
  } elsif ( $age =~ /^(\d+)d$/i ) {
    $mday -= $1;
  } elsif ( $age =~ /^(\d+)h$/i ) {
    $hour -= $hour;
  } else {
    die "unparsable age: $age";
  }
  my $age_date = timelocal_nocheck($sec,$min,$hour,$mday,$mon,$year);

  $cust_bill->_date <= $age_date;

}

#                            and seconds <= $time - cust_bill._date

sub condition_sql {
  my( $class, $table, %opt ) = @_;

  my $time = $opt{'time'};

  my $age = $class->condition_sql_option('age');
  my $age_sql = 
    "$time - EXTRACT( EPOCH FROM REPLACE( $age, 'm', 'mon')::interval )";

  "cust_bill._date <= $age_sql";

}

sub order_sql {
  my( $class ) = @_;

  my $age = $class->condition_sql_option('age');
  "EXTRACT( EPOCH FROM REPLACE( $age, 'm', 'mon')::interval )";
}

sub order_sql_weight {
  0;
}

1;

--- NEW FILE: agent_type.pm ---
package FS::part_event::Condition::agent_type;

use strict;

use base qw( FS::part_event::Condition );

# see the FS::part_event::Condition manpage for full documentation on each
# of the required and optional methods.

sub description {
  'Agent Type';
}

sub option_fields {
  (
    'typenum'   => { label         => 'Agent Type',
                     type          => 'select-agent_type',
                     disable_empty => 1,
                   },
  );
}

sub condition {
  my($self, $object, %opt) = @_;

  my $cust_main = $self->cust_main($object);

  my $typenum = $self->option('typenum');

  $cust_main->agent->typenum == $typenum;

}

#sub condition_sql {
#  my( $self, $table ) = @_;
#
#  'true';
#}

1;

--- NEW FILE: balance.pm ---
package FS::part_event::Condition::balance;

use strict;
use FS::cust_main;

use base qw( FS::part_event::Condition );

sub description { 'Customer balance'; }

sub implicit_flag { 20; }

sub remove_warning {
  'Are you sure you want to remove this condition?  Doing so will allow this event to run even if the customer has no outstanding balance.  Perhaps you want to reset "Balance over" to 0 instead of removing the condition entirely?'; #better error msg?
}

sub option_fields {
  (
    'balance' => { 'label'      => 'Balance over',
                   'type'       => 'money',
                   'value'      => '0.00', #default
                 },
  );
}

sub condition {
  my($self, $object) = @_;

  my $cust_main = $self->cust_main($object);

  my $over = $self->option('balance');
  $over = 0 unless length($over);

  $cust_main->balance > $over;
}

sub condition_sql {
  my( $class, $table ) = @_;

  my $over = $class->condition_sql_option('balance');

  my $balance_sql = FS::cust_main->balance_sql;

  "$balance_sql > $over";

}

1;


--- NEW FILE: cust_pay_batch_declined.pm ---
package FS::part_event::Condition::cust_pay_batch_declined;

use strict;

use base qw( FS::part_event::Condition );

sub description {
  'Batch payment declined';
}

sub eventtable_hashref {
    { 'cust_main'      => 0,
      'cust_bill'      => 0,
      'cust_pkg'       => 0,
      'cust_pay_batch' => 1,
    };
}

#sub option_fields {
#  (
#    'field'         => 'description',
#
#    'another_field' => { 'label'=>'Amount', 'type'=>'money', },
#
#    'third_field'   => { 'label'         => 'Types',
#                         'type'          => 'checkbox-multiple',
#                         'options'       => [ 'h', 's' ],
#                         'option_labels' => { 'h' => 'Happy',
#                                              's' => 'Sad',
#                                            },
#  );
#}

sub condition {
  my($self, $cust_pay_batch, %opt) = @_;

  #my $cust_main = $self->cust_main($object);
  #my $value_of_field = $self->option('field');
  #my $time = $opt{'time'}; #use this instead of time or $^T

  $cust_pay_batch->status =~ /Declined/i;

}

#sub condition_sql {
#  my( $class, $table ) = @_;
#  #...
#  'true';
#}

1;

--- NEW FILE: pkg_class.pm ---
package FS::part_event::Condition::pkg_class;

use strict;

use base qw( FS::part_event::Condition );
use FS::Record qw( qsearch );
use FS::pkg_class;

sub description {
  'Package Class';
}

sub eventtable_hashref {
    { 'cust_main' => 0,
      'cust_bill' => 0,
      'cust_pkg'  => 1,
    };
}

#something like this
sub option_fields {
  (
    'pkgclass'  => { 'label'    => 'Package Class',
                     'type'     => 'select-pkg_class',
                     'multiple' => 1,
                   },
  );
}

sub condition {
  my( $self, $cust_pkg ) = @_;

  #XXX test
  my $hashref = $self->option('pkgclass') || {};
  $hashref->{ $cust_pkg->part_pkg->classnum };
}

1;



More information about the freeside-commits mailing list