diff options
Diffstat (limited to 'FS')
| -rw-r--r-- | FS/FS/Schema.pm | 3 | ||||
| -rw-r--r-- | FS/FS/contact.pm | 7 | ||||
| -rw-r--r-- | FS/FS/cust_contact.pm | 7 | ||||
| -rw-r--r-- | FS/FS/cust_main.pm | 96 | ||||
| -rw-r--r-- | FS/FS/cust_main_Mixin.pm | 38 | ||||
| -rw-r--r-- | FS/FS/msg_template/email.pm | 29 | ||||
| -rw-r--r-- | FS/FS/pay_batch/paymentech.pm | 8 |
7 files changed, 142 insertions, 46 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 08eae6a32..873c67e22 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1764,7 +1764,8 @@ sub tables_hashref { 'classnum', 'int', 'NULL', '', '', '', 'comment', 'varchar', 'NULL', 255, '', '', 'selfservice_access', 'char', 'NULL', 1, '', '', - 'invoice_dest', 'char', 'NULL', 1, '', '', + 'invoice_dest', 'char', 'NULL', 1, '', '', # Y or NULL + 'message_dest', 'char', 'NULL', 1, '', '', # Y or NULL ], 'primary_key' => 'custcontactnum', 'unique' => [ [ 'custnum', 'contactnum' ], ], diff --git a/FS/FS/contact.pm b/FS/FS/contact.pm index fc06ca82b..9505dee35 100644 --- a/FS/FS/contact.pm +++ b/FS/FS/contact.pm @@ -155,7 +155,7 @@ sub insert { $self->custnum(''); my %link_hash = (); - for (qw( classnum comment selfservice_access invoice_dest )) { + for (qw( classnum comment selfservice_access invoice_dest message_dest)) { $link_hash{$_} = $self->get($_); $self->$_(''); } @@ -437,7 +437,7 @@ sub replace { $self->custnum(''); my %link_hash = (); - for (qw( classnum comment selfservice_access invoice_dest )) { + for (qw( classnum comment selfservice_access invoice_dest message_dest )) { $link_hash{$_} = $self->get($_); $self->$_(''); } @@ -968,7 +968,7 @@ sub cgi_contact_fields { my @contact_fields = qw( classnum first last title comment emailaddress selfservice_access - invoice_dest password + invoice_dest message_dest password ); push @contact_fields, 'phonetypenum'. $_->phonetypenum @@ -1041,4 +1041,3 @@ L<FS::Record>, schema.html from the base documentation. =cut 1; - diff --git a/FS/FS/cust_contact.pm b/FS/FS/cust_contact.pm index 118a9e000..adad46e9e 100644 --- a/FS/FS/cust_contact.pm +++ b/FS/FS/cust_contact.pm @@ -59,6 +59,11 @@ empty or Y 'Y' if the customer should get invoices sent to this address, null if not +=item message_dest + +'Y' if contact should get non-invoice email messages sent to this address, +NULL if not + =back =head1 METHODS @@ -119,6 +124,7 @@ sub check { || $self->ut_textn('comment') || $self->ut_enum('selfservice_access', [ '', 'Y' ]) || $self->ut_flag('invoice_dest') + || $self->ut_flag('message_dest') ; return $error if $error; @@ -148,4 +154,3 @@ L<FS::contact>, L<FS::cust_main>, L<FS::Record> =cut 1; - diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index aa8ae2a6a..d2c4a36ed 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3265,48 +3265,101 @@ sub invoicing_list_emailonly_scalar { join(', ', $self->invoicing_list_emailonly); } -=item contact_list [ CLASSNUM, ... ] +=item contact_list [ CLASSNUM, DEST_FLAG... ] -Returns a list of contacts (L<FS::contact> objects) for the customer. If -a list of contact classnums is given, returns only contacts in those -classes. If the pseudo-classnum 'invoice' is given, returns contacts that -are marked as invoice destinations. If '0' is given, also returns contacts -with no class. +Returns a list of contacts (L<FS::contact> objects) for the customer. If no arguments are given, returns all contacts for the customer. +Arguments may contain classnums. When classnums are specified, only +contacts with a matching cust_contact.classnum are returned. When a +classnum of 0 is given, contacts with a null classnum are also included. + +Arguments may also contain the dest flag names 'invoice' or 'message'. +If given, contacts who's invoice_dest and/or message_dest flags are +not set to 'Y' will be excluded. + =cut sub contact_list { my $self = shift; my $search = { table => 'contact', - select => 'contact.*, cust_contact.invoice_dest', + select => join(', ',( + 'contact.*', + 'cust_contact.invoice_dest', + 'cust_contact.message_dest', + )), addl_from => ' JOIN cust_contact USING (contactnum)', extra_sql => ' WHERE cust_contact.custnum = '.$self->custnum, }; - my @orwhere; + # Bugfix notes: + # Calling methods were relying on this method to use invoice_dest to + # block e-mail messages. Depending on parameters, this may or may not + # have actually happened. + # + # The bug could cause this SQL to be used to filter e-mail addresses: + # + # AND ( + # cust_contact.classnums IN (1,2,3) + # OR cust_contact.invoice_dest = 'Y' + # ) + # + # improperly including everybody with the opt-in flag AND everybody + # in the contact classes + # + # Possibility to introduce new bugs: + # If callers of this method called it incorrectly, and didn't notice + # because it seemed to send the e-mails they wanted. + + # WHERE ... + # AND ( + # ( cust_contact.classnum IN (1,2,3) ) + # OR + # ( cust_contact.classnum IS NULL ) + # + # AND ( + # ( cust_contact.invoice_dest = 'Y' ) + # OR + # ( cust_contact.message_dest = 'Y' ) + # ) + # ) + + my @and_dest; + my @or_classnum; my @classnums; - foreach (@_) { - if ( $_ eq 'invoice' ) { - push @orwhere, 'cust_contact.invoice_dest = \'Y\''; - } elsif ( $_ eq '0' ) { - push @orwhere, 'cust_contact.classnum is null'; + for (@_) { + if ($_ eq 'invoice' || $_ eq 'message') { + push @and_dest, " cust_contact.${_}_dest = 'Y' "; + } elsif ($_ eq '0') { + push @or_classnum, ' cust_contact.classnum IS NULL '; } elsif ( /^\d+$/ ) { push @classnums, $_; } else { - die "bad classnum argument '$_'"; + croak "bad classnum argument '$_'"; } } - if (@classnums) { - push @orwhere, 'cust_contact.classnum IN ('.join(',', @classnums).')'; - } - if (@orwhere) { - $search->{extra_sql} .= ' AND (' . - join(' OR ', map "( $_ )", @orwhere) . - ')'; + push @or_classnum, 'cust_contact.classnum IN ('.join(',',@classnums).')' + if @classnums; + + if (@or_classnum || @and_dest) { # catch, no arguments given + $search->{extra_sql} .= ' AND ( '; + + if (@or_classnum) { + $search->{extra_sql} .= join ' OR ', map {" ($_) "} @or_classnum; + $search->{extra_sql} .= ' AND ( ' if @and_dest; + } + + if (@and_dest) { + $search->{extra_sql} .= join ' OR ', map {" ($_) "} @and_dest; + $search->{extra_sql} .= ' ) ' if @or_classnum; + } + + $search->{extra_sql} .= ' ) '; + + warn "\$extra_sql: $search->{extra_sql} \n" if $DEBUG; } qsearch($search); @@ -6027,4 +6080,3 @@ L<FS::cust_main_invoice>, L<FS::UID>, schema.html from the base documentation. =cut 1; - diff --git a/FS/FS/cust_main_Mixin.pm b/FS/FS/cust_main_Mixin.pm index 8b6569a74..cceaa4bc7 100644 --- a/FS/FS/cust_main_Mixin.pm +++ b/FS/FS/cust_main_Mixin.pm @@ -348,10 +348,21 @@ sub cust_search_sql { =item email_search_result HASHREF -Emails a notice to the specified customers. Customers without -invoice email destinations will be skipped. +Emails a notice to the specified customer's contact_email addresses. -Parameters: + +If the user has specified "Invoice recipients" on the send e-mail screen, +contact_email rows containing the invoice_dest flag will be included. +This option is default, if neither 'invoice' nor 'message' are present. + +If the user has specified "Message recipients" on the send e-mail screen, +contact_email rows containing the message_dest flag will be included. + +The selection is indicated by the presence of the text 'message' or +'invoice' within the to_contact_classnum argument. + + +Parameters: =over 4 @@ -386,9 +397,19 @@ Text body =item to_contact_classnum -The customer contact class (or classes, as a comma-separated list) to send -the message to. If unspecified, will be sent to any contacts that are marked -as invoice destinations (the equivalent of specifying 'invoice'). +This field contains a comma-separated list. This list may contain: + +- the text "invoice" indicating contacts with invoice_dest flag should + be included +- the text "message" indicating contacts with message_dest flag should + be included +- numbers representing classnum id values for email contact classes. + If any classnum are present, emails should only be sent to contact_email + addresses where contact_email.classnum contains one of these classes. + The classnum 0 also includes where contact_email.classnum IS NULL + +If neither 'invoice' nor 'message' has been specified, this method will +behave as if 'invoice' had been selected =back @@ -483,8 +504,8 @@ sub email_search_result { next; # unlinked object; nothing else we can do } -my %to = {}; -if ($to) { $to{'to'} = $to; } + my %to = (); + if ($to) { $to{'to'} = $to; } my $cust_msg = $msg_template->prepare( 'cust_main' => $cust_main, @@ -736,4 +757,3 @@ L<FS::cust_main>, L<FS::Record> =cut 1; - diff --git a/FS/FS/msg_template/email.pm b/FS/FS/msg_template/email.pm index 3850edeb9..12f2b2939 100644 --- a/FS/FS/msg_template/email.pm +++ b/FS/FS/msg_template/email.pm @@ -210,6 +210,22 @@ go away in the future. A L<MIME::Entity> (or arrayref of them) to attach to the message. +=item to_contact_classnum + +Set a string containing a comma-separated list. This list may contain: + +- the text "invoice" indicating contacts with invoice_dest flag should + be included +- the text "message" indicating contacts with message_dest flag should + be included +- numbers representing classnum id values for email contact classes. + If any classnum are present, emails should only be sent to contact_email + addresses where contact_email.classnum contains one of these classes. + The classnum 0 also includes where contact_email.classnum IS NULL + +If neither 'invoice' nor 'message' has been specified, this method will +behave as if 'invoice' had been selected + =cut =back @@ -296,8 +312,16 @@ sub prepare { my $classnum = $opt{'to_contact_classnum'} || ''; my @classes = ref($classnum) ? @$classnum : split(',', $classnum); - # traditional behavior: send to all invoice recipients - @classes = ('invoice') unless @classes; + + # There are two e-mail opt-in flags per contact_email address. + # If neither 'invoice' nor 'message' has been specified, default + # to 'invoice'. + # + # This default supports the legacy behavior of + # send to all invoice recipients + push @classes,'invoice' + unless grep {$_ eq 'invoice' || $_ eq 'message'} @classes; + @to = $cust_main->contact_list_email(@classes); # not guaranteed to produce contacts, but then customers aren't # guaranteed to have email addresses on file. in that case, env_to @@ -630,4 +654,3 @@ L<FS::Record>, schema.html from the base documentation. =cut 1; - diff --git a/FS/FS/pay_batch/paymentech.pm b/FS/FS/pay_batch/paymentech.pm index bb2c2588d..094d50114 100644 --- a/FS/FS/pay_batch/paymentech.pm +++ b/FS/FS/pay_batch/paymentech.pm @@ -67,12 +67,8 @@ my $gateway; $hash->{'error_message'} = $hash->{'procStatusMessage'}; } }, - 'approved' => sub { my $hash = shift; - $hash->{'approvalStatus'} - }, - 'declined' => sub { my $hash = shift; - ! $hash->{'approvalStatus'} - }, + 'approved' => sub { shift->{'approvalStatus'} == 1 }, + 'declined' => sub { shift->{'approvalStatus'} != 1 }, ); my %paytype = ( |
