summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
Diffstat (limited to 'FS')
-rw-r--r--FS/FS.pm2
-rw-r--r--FS/FS/ClientAPI/MyAccount.pm3
-rw-r--r--FS/FS/Conf.pm8
-rw-r--r--FS/FS/Schema.pm1
-rw-r--r--FS/FS/Template_Mixin.pm27
-rw-r--r--FS/FS/Upgrade.pm4
-rw-r--r--FS/FS/contact.pm1
-rw-r--r--FS/FS/contact/Import.pm5
-rw-r--r--FS/FS/contact_import.pm164
-rw-r--r--FS/FS/cust_bill.pm8
-rw-r--r--FS/FS/cust_main.pm3
-rw-r--r--FS/FS/cust_main/Billing_Realtime.pm2
-rw-r--r--FS/FS/cust_main_Mixin.pm15
-rw-r--r--FS/FS/cust_pkg.pm6
-rw-r--r--FS/FS/part_event/Action/notice_to_emailtovoice.pm84
-rw-r--r--FS/FS/part_event/Condition/agent.pm9
-rw-r--r--FS/FS/part_event/Condition/cust_bill_hasnt_noauto.pm38
-rw-r--r--FS/FS/part_event_condition_option.pm33
-rw-r--r--FS/FS/pay_batch/RBC.pm12
-rw-r--r--FS/MANIFEST1
20 files changed, 212 insertions, 214 deletions
diff --git a/FS/FS.pm b/FS/FS.pm
index 9ee5fc944..e1d65f9e7 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -67,6 +67,8 @@ L<FS::cust_main::Search> - Customer searching
L<FS::cust_main::Import> - Batch customer importing
+L<FS::contact::Import> - Batch contact importing
+
=head2 Database record classes
L<FS::Record> - Database record base class
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index 476ef0789..f32523e35 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -600,6 +600,8 @@ sub customer_info_short {
for (@cust_main_editable_fields) {
$return{$_} = $cust_main->get($_);
}
+ $return{$_} = $cust_main->masked($_) for qw/ss stateid/;
+
#maybe a little more expensive, but it should be cached by now
for (@location_editable_fields) {
$return{$_} = $cust_main->bill_location->get($_);
@@ -3880,4 +3882,3 @@ sub _custoragent_session_custnum {
}
1;
-
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index c21d69244..d2351c005 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -1012,6 +1012,14 @@ my $validate_email = sub { $_[0] =~
},
{
+ 'key' => 'email-to-voice_domain',
+ 'section' => 'email_to_voice_services',
+ 'description' => 'The domain name that phone numbers will be attached to for sending email to voice emails via a 3rd party email to voice service. You will get this domain from your email to voice service provider. This is utilized on the email customer page or when using the email to voice billing event action. There you will be able to select the phone number for the email to voice service.',
+ 'type' => 'text',
+ 'per_agent' => 1,
+ },
+
+ {
'key' => 'next-bill-ignore-time',
'section' => 'billing',
'description' => 'Ignore the time portion of next bill dates when billing, matching anything from 00:00:00 to 23:59:59 on the billing day.',
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 1567b0030..699143239 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1909,6 +1909,7 @@ sub tables_hashref {
'amount', @money_type, '', '',
'status', 'varchar', 'NULL', $char_d, '', '',
'error_message', 'varchar', 'NULL', $char_d, '', '',
+ 'paycode', 'varchar', 'NULL', $char_d, '', '',
],
'primary_key' => 'paybatchnum',
'unique' => [],
diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm
index cefb4bcc3..f197d005a 100644
--- a/FS/FS/Template_Mixin.pm
+++ b/FS/FS/Template_Mixin.pm
@@ -2026,6 +2026,23 @@ sub due_date2str {
$self->due_date ? $self->time2str_local(shift, $self->due_date) : '';
}
+=item invoice_pay_by_msg
+
+ displays the invoice_pay_by_msg or default Please pay by [_1] if empty.
+
+=cut
+
+sub invoice_pay_by_msg {
+ my $self = shift;
+ my $msg = '';
+ my $please_pay_by =
+ $self->conf->config('invoice_pay_by_msg', $self->agentnum)
+ || 'Please pay by [_1]';
+ $msg .= ' - ' . $self->mt($please_pay_by, $self->due_date2str('short')) . ' ';
+
+ $msg;
+}
+
=item balance_due_msg
=cut
@@ -2040,11 +2057,7 @@ sub balance_due_msg {
# _items_total) and not here
# (yes, or if invoice_sections is enabled; this is just for compatibility)
if ( $self->due_date ) {
- my $please_pay_by =
- $self->conf->config('invoice_pay_by_msg', $self->agentnum)
- || 'Please pay by [_1]';
- $msg .= ' - ' . $self->mt($please_pay_by, $self->due_date2str('short')).
- ' '
+ $msg .= $self->invoice_pay_by_msg
unless $self->conf->config_bool('invoice_omit_due_date',$self->agentnum);
} elsif ( $self->terms ) {
$msg .= ' - '. $self->mt($self->terms);
@@ -3099,7 +3112,9 @@ sub _items_fee {
my @cust_bill_pkg = grep { $_->feepart } $self->cust_bill_pkg;
my $escape_function = $options{escape_function};
- my $locale = $self->cust_main->locale;
+ my $locale = $self->cust_main
+ ? $self->cust_main->locale
+ : $self->prospect_main->locale;
my @items;
foreach my $cust_bill_pkg (@cust_bill_pkg) {
diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm
index e729896b3..f26c6a338 100644
--- a/FS/FS/Upgrade.pm
+++ b/FS/FS/Upgrade.pm
@@ -454,6 +454,10 @@ sub upgrade_data {
#mark certain taxes as system-maintained,
# and fix whitespace
'cust_main_county' => [],
+
+ #upgrade part_event_condition_option agentnum to a multiple hash value
+ 'part_event_condition_option' =>[],
+
;
\%hash;
diff --git a/FS/FS/contact.pm b/FS/FS/contact.pm
index 8a381a509..4db3cdfd1 100644
--- a/FS/FS/contact.pm
+++ b/FS/FS/contact.pm
@@ -12,6 +12,7 @@ use FS::contact_class;
use FS::cust_location;
use FS::contact_phone;
use FS::contact_email;
+use FS::contact::Import;
use FS::queue;
use FS::cust_pkg;
use FS::phone_type; #for cgi_contact_fields
diff --git a/FS/FS/contact/Import.pm b/FS/FS/contact/Import.pm
index 26bdcfa6e..7a71349bc 100644
--- a/FS/FS/contact/Import.pm
+++ b/FS/FS/contact/Import.pm
@@ -2,6 +2,8 @@ package FS::contact::Import;
use strict;
use vars qw( $DEBUG ); #$conf );
+use Storable qw(thaw);
+use MIME::Base64;
use Data::Dumper;
use FS::Misc::DateTime qw( parse_datetime );
use FS::Record qw( qsearchs );
@@ -49,7 +51,8 @@ Load a batch import as a queued JSRPC job
sub process_batch_import {
my $job = shift;
- my $param = shift;
+ #my $param = shift;
+ my $param = thaw(decode_base64(shift));
warn Dumper($param) if $DEBUG;
my $files = $param->{'uploaded_files'}
diff --git a/FS/FS/contact_import.pm b/FS/FS/contact_import.pm
deleted file mode 100644
index 599132bc7..000000000
--- a/FS/FS/contact_import.pm
+++ /dev/null
@@ -1,164 +0,0 @@
-package FS::contact_import;
-
-use strict;
-use vars qw( $DEBUG ); #$conf );
-use Storable qw(thaw);
-use Data::Dumper;
-use MIME::Base64;
-use FS::Misc::DateTime qw( parse_datetime );
-use FS::Record qw( qsearchs );
-use FS::contact;
-use FS::cust_main;
-
-$DEBUG = 0;
-
-=head1 NAME
-
-FS::contact_import - Batch contact importing
-
-=head1 SYNOPSIS
-
- use FS::contact_import;
-
- #import
- FS::contact_import::batch_import( {
- file => $file, #filename
- type => $type, #csv or xls
- format => $format, #default
- agentnum => $agentnum,
- job => $job, #optional job queue job, for progressbar updates
- pkgbatch => $pkgbatch, #optional batch unique identifier
- } );
- die $error if $error;
-
- #ajax helper
- use FS::UI::Web::JSRPC;
- my $server =
- new FS::UI::Web::JSRPC 'FS::contact_import::process_batch_import', $cgi;
- print $server->process;
-
-=head1 DESCRIPTION
-
-Batch contact importing.
-
-=head1 SUBROUTINES
-
-=item process_batch_import
-
-Load a batch import as a queued JSRPC job
-
-=cut
-
-sub process_batch_import {
- my $job = shift;
- #my $param = shift;
- my $param = thaw(decode_base64(shift));
- warn Dumper($param) if $DEBUG;
-
- my $files = $param->{'uploaded_files'}
- or die "No files provided.\n";
-
- my (%files) = map { /^(\w+):([\.\w]+)$/ ? ($1,$2):() } split /,/, $files;
-
- my $dir = '%%%FREESIDE_CACHE%%%/cache.'. $FS::UID::datasrc. '/';
-
- my $file = $dir. $files{'file'};
-
- my $type;
- if ( $file =~ /\.(\w+)$/i ) {
- $type = lc($1);
- } else {
- #or error out???
- warn "can't parse file type from filename $file; defaulting to CSV";
- $type = 'csv';
- }
-
- my $error =
- FS::contact_import::batch_import( {
- job => $job,
- file => $file,
- type => $type,
- agentnum => $param->{'agentnum'},
- 'format' => $param->{'format'},
- } );
-
- unlink $file;
-
- die "$error\n" if $error;
-
-}
-
-=item batch_import
-
-=cut
-
-my %formatfields = (
- 'default' => [ qw( custnum last first title comment selfservice_access emailaddress phonetypenum1 phonetypenum3 phonetypenum2 ) ],
-);
-
-sub _formatfields {
- \%formatfields;
-}
-
-## not tested but maybe allow 2nd format to attach location in the future
-my %import_options = (
- 'table' => 'contact',
-
- 'preinsert_callback' => sub {
- my($record, $param) = @_;
- my @location_params = grep /^location\./, keys %$param;
- if (@location_params) {
- my $cust_location = FS::cust_location->new({
- 'custnum' => $record->custnum,
- });
- foreach my $p (@location_params) {
- $p =~ /^location.(\w+)$/;
- $cust_location->set($1, $param->{$p});
- }
-
- my $error = $cust_location->find_or_insert; # this avoids duplicates
- return "error creating location: $error" if $error;
- $record->set('locationnum', $cust_location->locationnum);
- }
- '';
- },
-
-);
-
-sub _import_options {
- \%import_options;
-}
-
-sub batch_import {
- my $opt = shift;
-
- my $iopt = _import_options;
- $opt->{$_} = $iopt->{$_} foreach keys %$iopt;
-
- my $format = delete $opt->{'format'};
-
- my $formatfields = _formatfields();
- die "unknown format $format" unless $formatfields->{$format};
-
- my @fields;
- foreach my $field ( @{ $formatfields->{$format} } ) {
- push @fields, $field;
- }
-
- $opt->{'fields'} = \@fields;
-
- FS::Record::batch_import( $opt );
-
-}
-
-=head1 BUGS
-
-Not enough documentation.
-
-=head1 SEE ALSO
-
-L<FS::contact>
-
-=cut
-
-1; \ No newline at end of file
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index 6bfe3339a..2d937a827 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -2925,15 +2925,11 @@ sub _items_total {
}
}
-
- if ( $conf->exists('invoice_show_prior_due_date') ) {
+ if ( $conf->exists('invoice_show_prior_due_date') && !$conf->exists('invoice_omit_due_date') ) {
# then the due date should be shown with Total New Charges,
# and should NOT be shown with the Balance Due message.
if ( $self->due_date ) {
- # localize the "Please pay by" message and the date itself
- # (grammar issues with this, yeah)
- $new_charges_desc .= ' - ' . $self->mt('Please pay by') . ' ' .
- $self->due_date2str('short');
+ $new_charges_desc .= $self->invoice_pay_by_msg;
} elsif ( $self->terms ) {
# phrases like "due on receipt" should be localized
$new_charges_desc .= ' - ' . $self->mt($self->terms);
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 8058357a5..621f3d144 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -2790,7 +2790,7 @@ sub batch_card {
} );
foreach (qw( address1 address2 city state zip country latitude longitude
- payby payinfo paydate payname ))
+ payby payinfo paydate payname paycode paytype ))
{
$options{$_} = '' unless exists($options{$_});
}
@@ -2822,6 +2822,7 @@ sub batch_card {
'exp' => $options{paydate} || $self->paydate,
'payname' => $options{payname} || $self->payname,
'amount' => $amount, # consolidating
+ 'paycode' => $options{paycode} || '',
} );
$cust_pay_batch->paybatchnum($old_cust_pay_batch->paybatchnum)
diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm
index ae41c70c4..c503b45e6 100644
--- a/FS/FS/cust_main/Billing_Realtime.pm
+++ b/FS/FS/cust_main/Billing_Realtime.pm
@@ -1479,7 +1479,7 @@ sub realtime_refund_bop {
$self->agent->payment_gateway( 'method' => $options{method},
#'payinfo' => $payinfo,
);
- my( $processor, $login, $password, $namespace ) =
+ ( $processor, $login, $password, $namespace ) =
map { my $method = "gateway_$_"; $payment_gateway->$method }
qw( module username password namespace );
diff --git a/FS/FS/cust_main_Mixin.pm b/FS/FS/cust_main_Mixin.pm
index 28d894b1b..ccd1b84c9 100644
--- a/FS/FS/cust_main_Mixin.pm
+++ b/FS/FS/cust_main_Mixin.pm
@@ -405,14 +405,21 @@ use Digest::SHA qw(sha1); # for duplicate checking
sub email_search_result {
my($class, $param) = @_;
+ my $conf = FS::Conf->new;
+ my $send_to_domain = $conf->config('email-to-voice_domain');
+
my $msgnum = $param->{msgnum};
my $from = delete $param->{from};
my $subject = delete $param->{subject};
my $html_body = delete $param->{html_body};
my $text_body = delete $param->{text_body};
my $to_contact_classnum = delete $param->{to_contact_classnum};
+ my $emailtovoice_name = delete $param->{emailtovoice_contact};
+
my $error = '';
+ my $to = $emailtovoice_name . '@' . $send_to_domain unless !$emailtovoice_name;
+
my $job = delete $param->{'job'}
or die "email_search_result must run from the job queue.\n";
@@ -458,12 +465,16 @@ sub email_search_result {
next; # unlinked object; nothing else we can do
}
+ my %to = {};
+ if ($to) { $to{'to'} = $to; }
+
if ( $msg_template ) {
# Now supports other context objects.
%message = $msg_template->prepare(
'cust_main' => $cust_main,
'object' => $obj,
'to_contact_classnum' => $to_contact_classnum,
+ %to
);
} else {
@@ -476,7 +487,7 @@ sub email_search_result {
if (!@classes) {
@classes = ( 'invoice' );
}
- my @to = $cust_main->contact_list_email(@classes);
+ my @to = $to ? split(',', $to) : $cust_main->contact_list_email(@classes);
next if !@to;
%message = (
@@ -490,7 +501,7 @@ sub email_search_result {
} #if $msg_template
# For non-cust_main searches, we avoid duplicates based on message
- # body text.
+ # body text.
my $unique = $cust_main->custnum;
$unique .= sha1($message{'text_body'}) if $class ne 'FS::cust_main';
if( $sent_to{$unique} ) {
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index fa60afb45..3b746fc2d 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -5893,6 +5893,8 @@ sub search {
push @where, $FS::CurrentUser::CurrentUser->agentnums_sql('table'=>'cust_main');
}
+ push @where, "cust_pkg_reason.reasonnum = '".$params->{reasonnum}."'" if $params->{reasonnum};
+
my $extra_sql = scalar(@where) ? ' WHERE '. join(' AND ', @where) : '';
my $addl_from = 'LEFT JOIN part_pkg USING ( pkgpart ) '.
@@ -5900,6 +5902,10 @@ sub search {
'LEFT JOIN cust_location USING ( locationnum ) '.
FS::UI::Web::join_cust_main('cust_pkg', 'cust_pkg');
+ if ($params->{reasonnum}) {
+ $addl_from .= 'LEFT JOIN cust_pkg_reason ON (cust_pkg_reason.pkgnum = cust_pkg.pkgnum) ';
+ }
+
my $select;
my $count_query;
if ( $params->{'select_zip5'} ) {
diff --git a/FS/FS/part_event/Action/notice_to_emailtovoice.pm b/FS/FS/part_event/Action/notice_to_emailtovoice.pm
new file mode 100644
index 000000000..3eaa73850
--- /dev/null
+++ b/FS/FS/part_event/Action/notice_to_emailtovoice.pm
@@ -0,0 +1,84 @@
+package FS::part_event::Action::notice_to_emailtovoice;
+
+use strict;
+use base qw( FS::part_event::Action );
+use FS::Record qw( qsearchs );
+use FS::msg_template;
+use FS::Conf;
+
+sub description { 'Email a email to voice notice'; }
+
+sub eventtable_hashref {
+ {
+ 'cust_main' => 1,
+ 'cust_bill' => 1,
+ 'cust_pkg' => 1,
+ 'cust_pay' => 1,
+ 'cust_pay_batch' => 1,
+ 'cust_statement' => 1,
+ 'svc_acct' => 1,
+ };
+}
+
+sub option_fields {
+
+ #my $conf = new FS::Conf;
+ #my $to_domain = $conf->config('email-to-voice_domain');
+
+(
+ 'to_name' => { 'label' => 'Address To',
+ 'type' => 'select',
+ 'options' => [ 'mobile', 'fax', 'daytime' ],
+ 'option_labels' => { 'mobile' => 'Mobile Phone #',
+ 'fax' => 'Fax #',
+ 'daytime' => 'Day Time #',
+ },
+ 'post_field_label' => ' <font color="red">Make sure you have setup your email-to-voice_domain config option in your Configuration settings.</font>',
+ },
+
+ 'msgnum' => { 'label' => 'Template',
+ 'type' => 'select-table',
+ 'table' => 'msg_template',
+ 'name_col' => 'msgname',
+ 'hashref' => { disabled => '' },
+ 'disable_empty' => 1,
+ },
+ );
+
+}
+
+sub default_weight { 56; } #?
+
+sub do_action {
+ my( $self, $object ) = @_;
+
+ my $conf = new FS::Conf;
+ my $to_domain = $conf->config('email-to-voice_domain')
+ or die "Can't send notice with out send-to-domain, being set in global config \n";
+
+ my $cust_main = $self->cust_main($object);
+
+ my $msgnum = $self->option('msgnum');
+ my $name = $self->option('to_name');
+
+ my $msg_template = qsearchs('msg_template', { 'msgnum' => $msgnum } )
+ or die "Template $msgnum not found";
+
+ my $to_name = $cust_main->$name
+ or die "Can't send notice with out " . $cust_main->$name . " number set";
+
+ ## remove - from phone number
+ $to_name =~ s/-//g;
+
+ #my $to = $to_name . '@' . $self->option('to_domain');
+ my $to = $to_name . '@' . $to_domain;
+
+ $msg_template->send(
+ 'to' => $to,
+ 'cust_main' => $cust_main,
+ 'object' => $object,
+ );
+
+}
+
+1;
diff --git a/FS/FS/part_event/Condition/agent.pm b/FS/FS/part_event/Condition/agent.pm
index bdd4e12de..917cf468b 100644
--- a/FS/FS/part_event/Condition/agent.pm
+++ b/FS/FS/part_event/Condition/agent.pm
@@ -13,7 +13,7 @@ sub description {
sub option_fields {
(
- 'agentnum' => { label=>'Agent', type=>'select-agent', },
+ 'agentnum' => { label=>'Agent', type=>'select-agent', multiple => '1' },
);
}
@@ -22,16 +22,15 @@ sub condition {
my $cust_main = $self->cust_main($object);
- my $agentnum = $self->option('agentnum');
-
- $cust_main->agentnum == $agentnum;
+ my $hashref = $self->option('agentnum') || {};
+ grep $hashref->{ $_->agentnum }, $cust_main->agent;
}
sub condition_sql {
my( $class, $table, %opt ) = @_;
- "cust_main.agentnum = " . $class->condition_sql_option_integer('agentnum', $opt{'driver_name'});
+ "cust_main.agentnum IN " . $class->condition_sql_option_option_integer('agentnum', $opt{'driver_name'});
}
1;
diff --git a/FS/FS/part_event/Condition/cust_bill_hasnt_noauto.pm b/FS/FS/part_event/Condition/cust_bill_hasnt_noauto.pm
index 027625569..d782c12c1 100644
--- a/FS/FS/part_event/Condition/cust_bill_hasnt_noauto.pm
+++ b/FS/FS/part_event/Condition/cust_bill_hasnt_noauto.pm
@@ -26,32 +26,18 @@ sub condition {
sub condition_sql {
my( $class, $table, %opt ) = @_;
- # XXX: can be made faster with optimizations?
- # -remove some/all sub-selects?
- # -remove the two main separate selects?
-
- "0 = (select count(1) from cust_pkg
- where cust_pkg.no_auto = 'Y' and cust_pkg.pkgnum in
- (select distinct cust_bill_pkg.pkgnum
- from cust_bill_pkg, cust_pkg
- where cust_bill_pkg.pkgnum = cust_pkg.pkgnum
- and cust_bill_pkg.invnum = cust_bill.invnum
- and cust_bill_pkg.pkgnum > 0
- )
- )
- AND
- 0 = (select count(1) from part_pkg
- where part_pkg.no_auto = 'Y' and part_pkg.pkgpart in
- (select cust_pkg.pkgpart from cust_pkg
- where pkgnum in
- (select distinct cust_bill_pkg.pkgnum
- from cust_bill_pkg, cust_pkg
- where cust_bill_pkg.pkgnum = cust_pkg.pkgnum
- and cust_bill_pkg.invnum = cust_bill.invnum
- and cust_bill_pkg.pkgnum > 0
- )
- )
- )
+ # can be made still faster with optimizations?
+
+ "NOT EXISTS ( SELECT 1 FROM cust_pkg
+ LEFT JOIN part_pkg USING (pkgpart)
+ WHERE ( cust_pkg.no_auto = 'Y' OR part_pkg.no_auto = 'Y' )
+ AND cust_pkg.pkgnum IN
+ ( SELECT DISTINCT cust_bill_pkg.pkgnum
+ FROM cust_bill_pkg
+ WHERE cust_bill_pkg.invnum = cust_bill.invnum
+ AND cust_bill_pkg.pkgnum > 0
+ )
+ )
";
}
diff --git a/FS/FS/part_event_condition_option.pm b/FS/FS/part_event_condition_option.pm
index 3256dc0bd..f1d1b6a15 100644
--- a/FS/FS/part_event_condition_option.pm
+++ b/FS/FS/part_event_condition_option.pm
@@ -138,6 +138,39 @@ sub optionvalue {
}
}
+use FS::upgrade_journal;
+sub _upgrade_data { #class method
+ my ($class, %opts) = @_;
+
+ # migrate part_event_condition_option agentnum to part_event_condition_option_option agentnum
+ unless ( FS::upgrade_journal->is_done('agentnum_to_hash') ) {
+
+ foreach my $condition_option (qsearch('part_event_condition_option', { optionname => 'agentnum', })) {
+ my %options;
+ my $optionvalue = $condition_option->get("optionvalue");
+ if ($optionvalue eq 'HASH' ) { next; }
+ elsif ($optionvalue eq '') {
+ foreach my $agent (qsearch('agent', {})) {
+ $options{$agent->agentnum} = '1';
+ }
+
+ }
+ else {
+ $options{$optionvalue} = '1';
+ }
+
+ $condition_option->optionvalue(ref(\%options));
+ my $error = $condition_option->replace(\%options);
+ die $error if $error;
+
+ }
+
+ FS::upgrade_journal->set_done('agentnum_to_hash');
+
+ }
+
+}
+
=back
=head1 SEE ALSO
diff --git a/FS/FS/pay_batch/RBC.pm b/FS/FS/pay_batch/RBC.pm
index 142c50b79..c4388d156 100644
--- a/FS/FS/pay_batch/RBC.pm
+++ b/FS/FS/pay_batch/RBC.pm
@@ -180,8 +180,13 @@ $name = 'RBC';
if (($cust_pay_batch->cust_main->paytype eq "Business checking" || $cust_pay_batch->cust_main->paytype eq "Business savings") && $cust_pay_batch->cust_main->company);
$i++;
+
+ ## set to D for debit by default, then override to what cust_pay_batch has as payments may not have paycode.
+ my $debitorcredit = 'D';
+ $debitorcredit = $cust_pay_batch->paycode unless !$cust_pay_batch->paycode;
+
sprintf("%06u", $i).
- 'D'.
+ $debitorcredit.
sprintf("%3s",$trans_code).
sprintf("%10s",$client_num).
' '.
@@ -225,5 +230,10 @@ $name = 'RBC';
},
);
+## this format can handle credit transactions
+sub can_handle_credits {
+ 1;
+}
+
1;
diff --git a/FS/MANIFEST b/FS/MANIFEST
index 93835936a..d16282ffd 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -513,6 +513,7 @@ t/class_Common.t
FS/category_Common.pm
t/category_Common.t
FS/contact.pm
+FS/contact/Import.pm
t/contact.t
FS/contact_phone.pm
t/contact_phone.t