use FS::contact;
use FS::reason;
use FS::Misc::Savepoint;
+use FS::DBI;
# 1 is mostly method/subroutine entry and options
# 2 traces progress of some operations
=item dundate
-A suggestion to events (see L<FS::part_bill_event">) to delay until this unix timestamp
+A suggestion to events (see L<FS::part_bill_event>) to delay until this unix timestamp
=item squelch_cdr
$ticket_dbh = $dbh;
} elsif ($conf->config('ticket_system') eq 'RT_External') {
my ($datasrc, $user, $pass) = $conf->config('ticket_system-rt_external_datasrc');
- $ticket_dbh = DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 });
+ $ticket_dbh = FS::DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 });
#or die "RT_External DBI->connect error: $DBI::errstr\n";
}
=cut
sub suspend {
- my $self = shift;
- grep { $_->suspend(@_) } $self->unsuspended_pkgs;
+ my($self, %opt) = @_;
+
+ my @pkgs = $self->unsuspended_pkgs;
+
+ @pkgs = grep { ! $_->get('start_date') } @pkgs
+ if $opt{skip_future_startdate};
+
+ grep { $_->suspend(%opt) } @pkgs;
}
=item suspend_if_pkgpart HASHREF | PKGPART [ , PKGPART ... ]
=item quiet - can be set true to supress email cancellation notices.
-=item reason - can be set to a cancellation reason (see L<FS:reason>), either a
+=item reason - can be set to a cancellation reason (see L<FS::reason>), either a
reasonnum of an existing reason, or passing a hashref will create a new reason.
The hashref should have the following keys:
typenum - Reason type (see L<FS::reason_type>)
L<Date::Parse> for conversion functions. The empty string can be passed
to disable that time constraint completely.
-Accepts the same options as L<balance_date_sql>:
+Accepts the same options as L</balance_date_sql>:
=over 4
@emails;
}
+=item contact_list_email_destinations
+
+Returns a list of emails and whether they receive invoices or messages destinations.
+{ emailaddress => 'email.com', invoice => 'Y', message => '', }
+
+=cut
+
+sub contact_list_email_destinations {
+ my $self = shift;
+ warn "$me contact_list_email_destinations"
+ if $DEBUG;
+ return () if !$self->custnum; # not yet inserted
+ return map { $_ }
+ qsearch({
+ table => 'cust_contact',
+ select => 'emailaddress, cust_contact.invoice_dest as invoice, cust_contact.message_dest as message',
+ addl_from => ' JOIN contact USING (contactnum) '.
+ ' JOIN contact_email USING (contactnum)',
+ hashref => { 'custnum' => $self->custnum, },
+ order_by => 'ORDER BY custcontactnum DESC',
+ extra_sql => '',
+ });
+}
+
+=item contact_list_name_phones
+
+Returns a list of contact phone numbers.
+{ phonetypenum => '1', phonenum => 'xxxxxxxxxx', first => 'firstname', last => 'lastname', countrycode => '1' }
+
+=cut
+
+sub contact_list_name_phones {
+ my $self = shift;
+ my $phone_type = shift;
+
+ warn "$me contact_list_phones" if $DEBUG;
+
+ return () if !$self->custnum; # not yet inserted
+ return map { $_ }
+ qsearch({
+ table => 'cust_contact',
+ select => 'phonetypenum, phonenum, first, last, countrycode',
+ addl_from => ' JOIN contact USING (contactnum) '.
+ ' JOIN contact_phone USING (contactnum)',
+ hashref => { 'custnum' => $self->custnum, 'phonetypenum' => $phone_type, },
+ order_by => 'ORDER BY custcontactnum DESC',
+ extra_sql => '',
+ });
+}
+
+=item contact_list_emailonly
+
+Returns an array of hashes containing the emails. Used for displaying contact email field in advanced customer reports.
+[ { data => 'email.com', }, ]
+
+=cut
+
+sub contact_list_emailonly {
+ my $self = shift;
+ warn "$me contact_list_emailonly called"
+ if $DEBUG;
+ my @emails;
+ foreach ($self->contact_list_email_destinations) {
+ my $data = [
+ {
+ 'data' => $_->emailaddress,
+ },
+ ];
+ push @emails, $data;
+ }
+ return \@emails;
+}
+
+=item contact_list_cust_invoice_only
+
+Returns an array of hashes containing cust_contact.invoice_dest. Does this email receive invoices. Used for displaying email Invoice field in advanced customer reports.
+[ { data => 'Yes', }, ]
+
+=cut
+
+sub contact_list_cust_invoice_only {
+ my $self = shift;
+ warn "$me contact_list_cust_invoice_only called"
+ if $DEBUG;
+ my @emails;
+ foreach ($self->contact_list_email_destinations) {
+ my $invoice = $_->invoice ? 'Yes' : 'No';
+ my $data = [
+ {
+ 'data' => $invoice,
+ },
+ ];
+ push @emails, $data;
+ }
+ return \@emails;
+}
+
+=item contact_list_cust_message_only
+
+Returns an array of hashes containing cust_contact.message_dest. Does this email receive message notifications. Used for displaying email Message field in advanced customer reports.
+[ { data => 'Yes', }, ]
+
+=cut
+
+sub contact_list_cust_message_only {
+ my $self = shift;
+ warn "$me contact_list_cust_message_only called"
+ if $DEBUG;
+ my @emails;
+ foreach ($self->contact_list_email_destinations) {
+ my $message = $_->message ? 'Yes' : 'No';
+ my $data = [
+ {
+ 'data' => $message,
+ },
+ ];
+ push @emails, $data;
+ }
+ return \@emails;
+}
+
=item referral_custnum_cust_main
Returns the customer who referred this customer (or the empty string, if
FS::cust_bill->count( 'custnum = '.shift->custnum."AND pending = 'Y'" );
}
+=item cust_locations_missing_district
+
+Always returns empty list, unless tax_district_method eq 'wa_sales'
+
+Return cust_location rows for this customer, associated with active
+customer packages, where tax district column is empty. Presense of
+these rows should block billing, because invoice would be generated
+with incorrect taxes
+
+=cut
+
+sub cust_locations_missing_district {
+ my ( $self ) = @_;
+
+ my $tax_district_method = FS::Conf->new->config('tax_district_method');
+
+ return ()
+ unless $tax_district_method
+ && $tax_district_method eq 'wa_sales';
+
+ qsearch({
+ table => 'cust_location',
+ select => 'cust_location.*',
+ addl_from => '
+ LEFT JOIN cust_main USING (custnum)
+ LEFT JOIN cust_pkg ON cust_location.locationnum = cust_pkg.locationnum
+ ',
+ extra_sql => sprintf(q{
+ WHERE cust_location.state = 'WA'
+ AND cust_location.custnum = %s
+ AND (
+ cust_location.district IS NULL
+ or cust_location.district = ''
+ )
+ AND cust_pkg.pkgnum IS NOT NULL
+ AND (
+ cust_pkg.cancel > %s
+ OR cust_pkg.cancel IS NULL
+ )
+ },
+ $self->custnum, time()
+ ),
+ });
+}
+
#starting to take quite a while for big dbs
# (JRNL: journaled so it only happens once per database)
# - seq scan of h_cust_main (yuck), but not going to index paycvv, so