summaryrefslogtreecommitdiff
path: root/FS/FS/part_event/Action
diff options
context:
space:
mode:
Diffstat (limited to 'FS/FS/part_event/Action')
-rw-r--r--FS/FS/part_event/Action/addpost.pm24
-rw-r--r--FS/FS/part_event/Action/apply.pm28
-rw-r--r--FS/FS/part_event/Action/bill.pm30
-rw-r--r--FS/FS/part_event/Action/cancel.pm35
-rw-r--r--FS/FS/part_event/Action/collect.pm30
-rw-r--r--FS/FS/part_event/Action/cust_bill_batch.pm31
-rw-r--r--FS/FS/part_event/Action/cust_bill_comp.pm34
-rw-r--r--FS/FS/part_event/Action/cust_bill_fee_percent.pm40
-rw-r--r--FS/FS/part_event/Action/cust_bill_realtime_card.pm32
-rw-r--r--FS/FS/part_event/Action/cust_bill_realtime_check.pm32
-rw-r--r--FS/FS/part_event/Action/cust_bill_realtime_lec.pm32
-rw-r--r--FS/FS/part_event/Action/cust_bill_send.pm27
-rw-r--r--FS/FS/part_event/Action/cust_bill_send_agent.pm44
-rw-r--r--FS/FS/part_event/Action/cust_bill_send_alternate.pm35
-rw-r--r--FS/FS/part_event/Action/cust_bill_send_csv_ftp.pm56
-rw-r--r--FS/FS/part_event/Action/cust_bill_send_if_newest.pm40
-rw-r--r--FS/FS/part_event/Action/cust_bill_spool_csv.pm64
-rw-r--r--FS/FS/part_event/Action/cust_bill_suspend_if_balance.pm48
-rw-r--r--FS/FS/part_event/Action/fee.pm33
-rw-r--r--FS/FS/part_event/Action/suspend.pm36
-rw-r--r--FS/FS/part_event/Action/suspend_if_pkgpart.pm42
-rw-r--r--FS/FS/part_event/Action/suspend_unless_pkgpart.pm42
22 files changed, 815 insertions, 0 deletions
diff --git a/FS/FS/part_event/Action/addpost.pm b/FS/FS/part_event/Action/addpost.pm
new file mode 100644
index 000000000..e0e3fa878
--- /dev/null
+++ b/FS/FS/part_event/Action/addpost.pm
@@ -0,0 +1,24 @@
+package FS::part_event::Action::addpost;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Add postal invoicing';
+}
+
+sub default_weight {
+ 20;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ $cust_main->invoicing_list_addpost();
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/apply.pm b/FS/FS/part_event/Action/apply.pm
new file mode 100644
index 000000000..f91c6047e
--- /dev/null
+++ b/FS/FS/part_event/Action/apply.pm
@@ -0,0 +1,28 @@
+package FS::part_event::Action::apply;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Apply unapplied payments and credits';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub default_weight {
+ 70;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ $cust_main->apply_payments_and_credits;
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/bill.pm b/FS/FS/part_event/Action/bill.pm
new file mode 100644
index 000000000..fec025f62
--- /dev/null
+++ b/FS/FS/part_event/Action/bill.pm
@@ -0,0 +1,30 @@
+package FS::part_event::Action::bill;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ #'Generate invoices (normally only used with a <i>Late Fee</i> event)';
+ 'Generate invoices (normally only used with a Late Fee event)';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub default_weight {
+ 60;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ my $error = $cust_main->bill;
+ die $error if $error;
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cancel.pm b/FS/FS/part_event/Action/cancel.pm
new file mode 100644
index 000000000..94f314602
--- /dev/null
+++ b/FS/FS/part_event/Action/cancel.pm
@@ -0,0 +1,35 @@
+package FS::part_event::Action::cancel;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Cancel';
+}
+
+sub option_fields {
+ (
+ 'reasonnum' => { 'label' => 'Reason',
+ 'type' => 'select-reason',
+ 'reason_class' => 'C',
+ },
+ );
+
+};
+
+sub default_weight {
+ 20;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ my $error = $cust_main->cancel( 'reason' => $self->option('reasonnum') );
+ die $error if $error;
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/collect.pm b/FS/FS/part_event/Action/collect.pm
new file mode 100644
index 000000000..fa94b7def
--- /dev/null
+++ b/FS/FS/part_event/Action/collect.pm
@@ -0,0 +1,30 @@
+package FS::part_event::Action::collect;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ #'Collect on invoices (normally only used with a <i>Late Fee</i> and <i>Generate Invoice</i> events)';
+ 'Collect on invoices (normally only used with a Late Fee and Generate Invoice events)';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub default_weight {
+ 80;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ my $error = $cust_main->collect;
+ die $error if $error;
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_batch.pm b/FS/FS/part_event/Action/cust_bill_batch.pm
new file mode 100644
index 000000000..aec09250b
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_batch.pm
@@ -0,0 +1,31 @@
+package FS::part_event::Action::cust_bill_batch;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Add card or check to a pending batch';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub default_weight {
+ 40;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->batch_card; # ( %options ); #XXX options??
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_comp.pm b/FS/FS/part_event/Action/cust_bill_comp.pm
new file mode 100644
index 000000000..636a66df5
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_comp.pm
@@ -0,0 +1,34 @@
+package FS::part_event::Action::cust_bill_comp;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Pay invoice with a complimentary "payment"';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub default_weight {
+ 30;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ my $error = $cust_bill->comp;
+ die $error if $error;
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_fee_percent.pm b/FS/FS/part_event/Action/cust_bill_fee_percent.pm
new file mode 100644
index 000000000..100fc8bc3
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_fee_percent.pm
@@ -0,0 +1,40 @@
+package FS::part_event::Action::cust_bill_fee_percent;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Late fee (percentage of invoice)';
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub option_fields {
+ (
+ 'percent' => { label=>'Percent', size=>2, },
+ 'reason' => 'Reason',
+ );
+}
+
+sub default_weight {
+ 10;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ my $error = $cust_main->charge(
+ sprintf('%.2f', $cust_bill->owed * $self->option('percent') / 100 ),
+ $self->option('reason')
+ );
+ die $error if $error;
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_realtime_card.pm b/FS/FS/part_event/Action/cust_bill_realtime_card.pm
new file mode 100644
index 000000000..471c946dc
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_realtime_card.pm
@@ -0,0 +1,32 @@
+package FS::part_event::Action::cust_bill_realtime_card;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ #'Run card with a <a href="http://420.am/business-onlinepayment/">Business::OnlinePayment</a> realtime gateway';
+ 'Run card with a Business::OnlinePayment realtime gateway';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub default_weight {
+ 30;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->realtime_card;
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_realtime_check.pm b/FS/FS/part_event/Action/cust_bill_realtime_check.pm
new file mode 100644
index 000000000..9a52830ae
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_realtime_check.pm
@@ -0,0 +1,32 @@
+package FS::part_event::Action::cust_bill_realtime_check;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ #'Run check with a <a href="http://420.am/business-onlinepayment/">Business::OnlinePayment</a> realtime gateway';
+ 'Run check with a Business::OnlinePayment realtime gateway';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub default_weight {
+ 30;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->realtime_ach;
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_realtime_lec.pm b/FS/FS/part_event/Action/cust_bill_realtime_lec.pm
new file mode 100644
index 000000000..db091dadb
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_realtime_lec.pm
@@ -0,0 +1,32 @@
+package FS::part_event::Action::cust_bill_realtime_lec;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ #'Run phone bill ("LEC") billing with a <a href="http://420.am/business-onlinepayment/">Business::OnlinePayment</a> realtime gateway';
+ 'Run phone bill ("LEC") billing with a Business::OnlinePayment realtime gateway';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub default_weight {
+ 30;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->realtime_lec;
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_send.pm b/FS/FS/part_event/Action/cust_bill_send.pm
new file mode 100644
index 000000000..9330c6113
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_send.pm
@@ -0,0 +1,27 @@
+package FS::part_event::Action::cust_bill_send;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Send invoice (email/print/fax)';
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub default_weight {
+ 50;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->send;
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_send_agent.pm b/FS/FS/part_event/Action/cust_bill_send_agent.pm
new file mode 100644
index 000000000..fcf000736
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_send_agent.pm
@@ -0,0 +1,44 @@
+package FS::part_event::Action::cust_bill_send_agent;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Send invoice (email/print/fax) with alternate template, for specific agents';
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub option_fields {
+ (
+ 'agentnum' => { label => 'Only for agent(s)',
+ type => 'select-agent',
+ multiple => 1
+ },
+ 'agent_templatename' => { label => 'Template',
+ type => 'select-invoice_template',
+ },
+ 'agent_invoice_from' => 'Invoice email From: address',
+ );
+}
+
+sub default_weight {
+ 50;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->send(
+ $self->option('agent_templatename'),
+ [ split(/\s*,\s*/, $self->option('agentnum') ) ],
+ $self->option('agent_invoice_from'),
+ );
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_send_alternate.pm b/FS/FS/part_event/Action/cust_bill_send_alternate.pm
new file mode 100644
index 000000000..6afb89a99
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_send_alternate.pm
@@ -0,0 +1,35 @@
+package FS::part_event::Action::cust_bill_send_alternate;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Send invoice (email/print/fax) with alternate template';
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub option_fields {
+ (
+ 'templatename' => { label => 'Template',
+ type => 'select-invoice_template',
+ },
+ );
+}
+
+sub default_weight {
+ 50;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->send( $self->option('templatename') );
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_send_csv_ftp.pm b/FS/FS/part_event/Action/cust_bill_send_csv_ftp.pm
new file mode 100644
index 000000000..db3554e01
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_send_csv_ftp.pm
@@ -0,0 +1,56 @@
+package FS::part_event::Action::cust_bill_send_csv_ftp;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Upload CSV invoice data to an FTP server';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub option_fields {
+ (
+ 'ftpformat' => { label => 'Format',
+ type =>'select',
+ options => ['default', 'billco'],
+ option_labels => { 'default' => 'Default',
+ 'billco' => 'Billco',
+ },
+ },
+ 'ftpserver' => 'FTP server',
+ 'ftpusername' => 'FTP username',
+ 'ftppassword' => 'FTP password',
+ 'ftpdir' => 'FTP directory',
+ );
+}
+
+sub default_weight {
+ 50;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->send_csv(
+ 'protocol' => 'ftp',
+ 'server' => $self->option('ftpserver'),
+ 'username' => $self->option('ftpusername'),
+ 'password' => $self->option('ftppassword'),
+ 'dir' => $self->option('ftpdir'),
+ 'format' => $self->option('ftpformat'),
+ );
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_send_if_newest.pm b/FS/FS/part_event/Action/cust_bill_send_if_newest.pm
new file mode 100644
index 000000000..916983ebe
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_send_if_newest.pm
@@ -0,0 +1,40 @@
+package FS::part_event::Action::cust_bill_send_if_newest;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Send invoice (email/print/fax) with alternate template, if it is still the newest invoice (useful for late notices - set to 31 days or later)';
+}
+
+# XXX is this handled better by something against customers??
+#sub deprecated {
+# 1;
+#}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub option_fields {
+ (
+ 'if_newest_templatename' => { label => 'Template',
+ type => 'select-invoice_template',
+ },
+ );
+}
+
+sub default_weight {
+ 50;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->send( $self->option('templatename') );
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_spool_csv.pm b/FS/FS/part_event/Action/cust_bill_spool_csv.pm
new file mode 100644
index 000000000..4300b6120
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_spool_csv.pm
@@ -0,0 +1,64 @@
+package FS::part_event::Action::cust_bill_spool_csv;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Spool CSV invoice data';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub option_fields {
+ (
+ 'spoolformat' => { label => 'Format',
+ type => 'select',
+ options => ['default', 'billco'],
+ option_labels => { 'default' => 'Default',
+ 'billco' => 'Billco',
+ },
+ },
+ 'spooldest' => { label => 'For destination',
+ type => 'select',
+ options => [ '', qw( POST EMAIL FAX ) ],
+ option_labels => { '' => '(all)',
+ 'POST' => 'Postal Mail',
+ 'EMAIL' => 'Email',
+ 'FAX' => 'Fax',
+ },
+ },
+ 'spoolbalanceover' => { label =>
+ 'If balance (this invoice and previous) over',
+ type => 'money',
+ },
+ 'spoolagent_spools' => { label => 'Individual per-agent spools',
+ type => 'checkbox',
+ },
+ );
+}
+
+sub default_weight {
+ 50;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ $cust_bill->spool_csv(
+ 'format' => $self->option('spoolformat'),
+ 'dest' => $self->option('spooldest'),
+ 'balanceover' => $self->option('spoolbalanceover'),
+ 'agent_spools' => $self->option('spoolagent_spools'),
+ );
+}
+
+1;
diff --git a/FS/FS/part_event/Action/cust_bill_suspend_if_balance.pm b/FS/FS/part_event/Action/cust_bill_suspend_if_balance.pm
new file mode 100644
index 000000000..655994963
--- /dev/null
+++ b/FS/FS/part_event/Action/cust_bill_suspend_if_balance.pm
@@ -0,0 +1,48 @@
+package FS::part_event::Action::cust_bill_suspend_if_balance;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Suspend if balance (this invoice and previous) over';
+}
+
+sub deprecated {
+ 1;
+}
+
+sub eventtable_hashref {
+ { 'cust_bill' => 1 };
+}
+
+sub option_fields {
+ (
+ 'balanceover' => { label=>'Balance over', type=>'money', }, # size=>7 },
+ 'reasonnum' => { 'label' => 'Reason',
+ 'type' => 'select-reason',
+ 'reason_class' => 'S',
+ },
+ );
+};
+
+sub default_weight {
+ 10;
+}
+
+sub do_action {
+ my( $self, $cust_bill ) = @_;
+
+ #my $cust_main = $self->cust_main($cust_bill);
+ my $cust_main = $cust_bill->cust_main;
+
+ my @err = $cust_bill->cust_suspend_if_balance_over(
+ $self->option('balanceover'),
+ 'reason' => $self->option('reasonnum'),
+ );
+
+ die join(' / ', @err) if scalar(@err);
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/fee.pm b/FS/FS/part_event/Action/fee.pm
new file mode 100644
index 000000000..81a84498a
--- /dev/null
+++ b/FS/FS/part_event/Action/fee.pm
@@ -0,0 +1,33 @@
+package FS::part_event::Action::fee;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Late fee (flat)';
+}
+
+sub option_fields {
+ (
+ 'charge' => { label=>'Amount', type=>'money', }, # size=>7, },
+ 'reason' => 'Reason',
+ );
+};
+
+sub default_weight {
+ 10;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ my $error = $cust_main->charge( $self->option('charge'), $self->option('reason') );
+
+ die $error if $error;
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/suspend.pm b/FS/FS/part_event/Action/suspend.pm
new file mode 100644
index 000000000..ec440ffd2
--- /dev/null
+++ b/FS/FS/part_event/Action/suspend.pm
@@ -0,0 +1,36 @@
+package FS::part_event::Action::suspend;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Suspend';
+}
+
+sub option_fields {
+ (
+ 'reasonnum' => { 'label' => 'Reason',
+ 'type' => 'select-reason',
+ 'reason_class' => 'S',
+ },
+ );
+};
+
+sub default_weight {
+ 10;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ my @err = $cust_main->suspend( 'reason' => $self->option('reasonnum') );
+
+ die join(' / ', @err) if scalar(@err);
+
+ '';
+
+}
+
+1;
diff --git a/FS/FS/part_event/Action/suspend_if_pkgpart.pm b/FS/FS/part_event/Action/suspend_if_pkgpart.pm
new file mode 100644
index 000000000..9bdc9be53
--- /dev/null
+++ b/FS/FS/part_event/Action/suspend_if_pkgpart.pm
@@ -0,0 +1,42 @@
+package FS::part_event::Action::suspend_if_pkgpart;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Suspend packages';
+}
+
+sub option_fields {
+ (
+ 'if_pkgpart' => { 'label' => 'Suspend packages:',
+ 'type' => 'select-part_pkg',
+ 'multiple' => 1,
+ },
+ 'reasonnum' => { 'label' => 'Reason',
+ 'type' => 'select-reason',
+ 'reason_class' => 'S',
+ },
+ );
+};
+
+sub default_weight {
+ 10;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ my @err = $cust_main->suspend_if_pkgpart( {
+ 'pkgparts' => [ split(/\s*,\s*/, $self->option('if_pkgpart') ) ],
+ 'reason' => $self->option('reasonnum'),
+ } );
+
+ die join(' / ', @err) if scalar(@err);
+
+ '';
+}
+
+1;
diff --git a/FS/FS/part_event/Action/suspend_unless_pkgpart.pm b/FS/FS/part_event/Action/suspend_unless_pkgpart.pm
new file mode 100644
index 000000000..f9bf1e860
--- /dev/null
+++ b/FS/FS/part_event/Action/suspend_unless_pkgpart.pm
@@ -0,0 +1,42 @@
+package FS::part_event::Action::suspend_unless_pkgpart;
+
+use strict;
+use base qw( FS::part_event::Action );
+
+sub description {
+ 'Suspend packages except';
+}
+
+sub option_fields {
+ (
+ 'unless_pkgpart' => { 'label' => 'Suspend packages except:',
+ 'type' => 'select-part_pkg',
+ 'multiple' => 1,
+ },
+ 'reasonnum' => { 'label' => 'Reason',
+ 'type' => 'select-reason',
+ 'reason_class' => 'S',
+ },
+ );
+};
+
+sub default_weight {
+ 10;
+}
+
+sub do_action {
+ my( $self, $cust_object ) = @_;
+
+ my $cust_main = $self->cust_main($cust_object);
+
+ my @err = $cust_main->suspend_unless_pkgpart( {
+ 'pkgparts' => [ split(/\s*,\s*/, $self->option('unless_pkgpart') ) ],
+ 'reason' => $self->option('reasonnum'),
+ } );
+
+ die join(' / ', @err) if scalar(@err);
+
+ '';
+}
+
+1;