summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2018-09-13 10:51:01 -0700
committerIvan Kohler <ivan@freeside.biz>2018-09-13 10:51:01 -0700
commit6383208b0f004ddcb26c74788595dce6673863f8 (patch)
tree98a9d8902e707bb63f25154fdf84d1b146fd2004 /FS
parent24fcbda43464e5ee5a342a52f6c5780e12693402 (diff)
parentbc552f2fba7fd376a2f036a7dc02b58a48fa31b0 (diff)
Merge branch 'FREESIDE_4_BRANCH' of git.freeside.biz:/home/git/freeside into FREESIDE_4_BRANCH
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/ClientAPI/MyAccount.pm33
-rw-r--r--FS/FS/ClientAPI_XMLRPC.pm1
-rw-r--r--FS/FS/Record.pm54
-rw-r--r--FS/FS/Report/Table.pm2
-rw-r--r--FS/FS/contact.pm13
-rw-r--r--FS/FS/cust_payby.pm84
-rw-r--r--FS/FS/part_export/saisei.pm60
7 files changed, 239 insertions, 8 deletions
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index dbecb9b67..fe77243e5 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -184,6 +184,29 @@ sub skin_info {
}
+sub get_mac_address {
+ my $p = shift;
+
+## access radius exports acct tables to get mac
+ my @part_export = ();
+ @part_export = (
+ qsearch( 'part_export', { 'exporttype' => 'sqlradius' } ),
+ qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } ),
+ qsearch( 'part_export', { 'exporttype' => 'broadband_sqlradius' } ),
+ );
+
+ my @sessions;
+ foreach my $part_export (@part_export) {
+ push @sessions, ( @{ $part_export->usage_sessions( {
+ 'ip' => $p->{'ip'},
+ } ) } );
+ }
+
+ my $mac = $sessions[0]->{'callingstationid'};
+
+ return { 'mac_address' => $mac, };
+}
+
sub login_info {
my $p = shift;
@@ -237,6 +260,16 @@ sub login {
$svc_x = $svc_phone;
+ } elsif ( $p->{'domain'} eq 'ip_mac' ) {
+
+ my $mac_address = $p->{'username'};
+ $mac_address =~ s/\://g;
+
+ my $svc_broadband = qsearchs( 'svc_broadband', { 'mac_addr' => $mac_address } );
+ return { error => 'MAC address not found '.$p->{'username'} }
+ unless $svc_broadband;
+ $svc_x = $svc_broadband;
+
} elsif ( $p->{email}
&& (my $contact = FS::contact->by_selfservice_email($p->{email}))
)
diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm
index dcf34fdaa..db0537c02 100644
--- a/FS/FS/ClientAPI_XMLRPC.pm
+++ b/FS/FS/ClientAPI_XMLRPC.pm
@@ -227,6 +227,7 @@ sub ss2clientapi {
'quotation_add_pkg' => 'MyAccount/quotation/quotation_add_pkg',
'quotation_remove_pkg' => 'MyAccount/quotation/quotation_remove_pkg',
'quotation_order' => 'MyAccount/quotation/quotation_order',
+ 'get_mac_address' => 'MyAccount/get_mac_address',
'freesideinc_service' => 'Freeside/freesideinc_service',
};
diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm
index 6ea936892..08d681e47 100644
--- a/FS/FS/Record.pm
+++ b/FS/FS/Record.pm
@@ -3207,6 +3207,60 @@ sub ut_enumn {
: '';
}
+=item ut_date COLUMN
+
+Check/untaint a column containing a date string.
+
+Date will be normalized to YYYY-MM-DD format
+
+=cut
+
+sub ut_date {
+ my ( $self, $field ) = @_;
+ my $value = $self->getfield( $field );
+
+ my @date = split /[\-\/]/, $value;
+ if ( scalar(@date) == 3 ) {
+ @date = @date[2,0,1] if $date[2] >= 1900;
+
+ local $@;
+ my $ymd;
+ eval {
+ # DateTime will die given invalid date
+ $ymd = DateTime->new(
+ year => $date[0],
+ month => $date[1],
+ day => $date[2],
+ )->ymd('-');
+ };
+
+ unless( $@ ) {
+ $self->setfield( $field, $ymd ) unless $value eq $ymd;
+ return '';
+ }
+
+ }
+ return "Illegal (date) field $field: $value";
+}
+
+=item ut_daten COLUMN
+
+Check/untaint a column containing a date string.
+
+Column may be null.
+
+Date will be normalized to YYYY-MM-DD format
+
+=cut
+
+sub ut_daten {
+ my ( $self, $field ) = @_;
+
+ $self->getfield( $field ) =~ /^()$/
+ ? $self->setfield( $field, '' )
+ : $self->ut_date( $field );
+}
+
=item ut_flag COLUMN
Check/untaint a column if it contains either an empty string or 'Y'. This
diff --git a/FS/FS/Report/Table.pm b/FS/FS/Report/Table.pm
index cef7813af..7c4f97309 100644
--- a/FS/FS/Report/Table.pm
+++ b/FS/FS/Report/Table.pm
@@ -1115,7 +1115,7 @@ sub calculate_churn_cust {
as suspended,
SUM((s_active = 0 and s_suspended > 0 and e_active > 0)::int)
as resumed,
- SUM((s_active > 0 and e_active = 0 and e_suspended = 0)::int)
+ SUM((e_active = 0 and e_cancelled > s_cancelled)::int)
as cancelled
FROM ($cust_sql) AS x
";
diff --git a/FS/FS/contact.pm b/FS/FS/contact.pm
index 02c6d0659..fc06ca82b 100644
--- a/FS/FS/contact.pm
+++ b/FS/FS/contact.pm
@@ -199,8 +199,6 @@ sub insert {
}
- $error ||= $self->insert_password_history;
-
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
@@ -302,6 +300,15 @@ sub insert {
}
}
+ if ( $self->get('password') ) {
+ my $error = $self->is_password_allowed($self->get('password'))
+ || $self->change_password($self->get('password'));
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
'';
@@ -817,7 +824,7 @@ sub authenticate_password {
$hash eq $check_hash;
- } else {
+ } else {
return 0 if $self->_password eq '';
diff --git a/FS/FS/cust_payby.pm b/FS/FS/cust_payby.pm
index 704741f3d..c497059fa 100644
--- a/FS/FS/cust_payby.pm
+++ b/FS/FS/cust_payby.pm
@@ -315,7 +315,6 @@ sub check {
#encrypted #|| $self->ut_textn('payinfo')
#encrypted #|| $self->ut_textn('paycvv')
# || $self->ut_textn('paymask') #XXX something
- #later #|| $self->ut_textn('paydate')
|| $self->ut_numbern('paystart_month')
|| $self->ut_numbern('paystart_year')
|| $self->ut_numbern('payissue')
@@ -546,6 +545,9 @@ sub check {
return $error if $error;
}
+ $error = $self->ut_daten('paydate');
+ return $error if $error;
+
$self->SUPER::check;
}
@@ -921,7 +923,87 @@ sub _upgrade_data {
local $ignore_expired_card = 1;
local $ignore_invalid_card = 1;
$class->upgrade_set_cardtype;
+ $class->_upgrade_data_paydate_edgebug;
+
+}
+
+=item _upgrade_data_paydate_edgebug
+
+Correct bad data injected into payment expire date column by Edge browser bug
+
+The month and year values may have an extra character injected into form POST
+data by Edge browser. It was possible for some bad month values to slip
+past data validation.
+
+If the stored value was out of range, it was causing payments screen to crash.
+We can detect and fix this by dropping the second digit.
+
+If the stored value is is 11 or 12, it's possible the user inputted a 1. In
+this case, the payment method will fail to authorize, but the record will
+not cause crashdumps for being out of range.
+
+In short, check for any expiration month > 12, and drop the extra digit
+
+=cut
+
+sub _upgrade_data_paydate_edgebug {
+ my $journal_label = 'cust_payby_paydate_edgebug';
+ return if FS::upgrade_journal->is_done( $journal_label );
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+
+ for my $row (
+ FS::Record::qsearch(
+ cust_payby => { paydate => { op => '!=', value => '' }}
+ )
+ ) {
+ next unless $row->ut_daten('paydate');
+
+ # paydate column stored in database has failed date validation
+ my $bad_paydate = $row->paydate;
+
+ my @date = split /[\-\/]/, $bad_paydate;
+ @date = @date[2,0,1] if $date[2] > 1900;
+
+ # Only autocorrecting when month > 12 - notify operator
+ unless ( $date[1] > 12 ) {
+ die sprintf(
+ 'Unable to correct bad paydate stored in cust_payby row '.
+ 'custpaybynum(%s) custnum(%s) paydate(%s)',
+ $row->custpaybynum,
+ $row->custnum,
+ $bad_paydate,
+ );
+ }
+
+ $date[1] = substr( $date[1], 0, 1 );
+ $row->paydate( join('-', @date ));
+
+ if ( my $error = $row->replace ) {
+ die sprintf(
+ 'Failed to autocorrect bad paydate stored in cust_payby row '.
+ 'custpaybynum(%s) custnum(%s) paydate(%s) - error: %s',
+ $row->custpaybynum,
+ $row->custnum,
+ $bad_paydate,
+ $error
+ );
+ }
+
+ warn sprintf(
+ 'Autocorrected bad paydate stored in cust_payby row '.
+ "custpaybynum(%s) custnum(%s) old-paydate(%s) new-paydate(%s)\n",
+ $row->custpaybynum,
+ $row->custnum,
+ $bad_paydate,
+ $row->paydate,
+ );
+
+ }
+ FS::upgrade_journal->set_done( $journal_label );
+ dbh->commit unless $oldAutoCommit;
}
=head1 BUGS
diff --git a/FS/FS/part_export/saisei.pm b/FS/FS/part_export/saisei.pm
index c79f79dac..3af3c9d9e 100644
--- a/FS/FS/part_export/saisei.pm
+++ b/FS/FS/part_export/saisei.pm
@@ -200,12 +200,28 @@ sub _export_insert {
my $accesspoint = process_sector($self, $sector_opt);
return $self->api_error if $self->{'__saisei_error'};
+## get custnum and pkgpart from cust_pkg for virtual access point
+ my $cust_pkg = FS::Record::qsearchs({
+ 'table' => 'cust_pkg',
+ 'hashref' => { 'pkgnum' => $svc_broadband->{Hash}->{pkgnum}, },
+ });
+ my $virtual_ap_name = $cust_pkg->{Hash}->{custnum}.'_'.$cust_pkg->{Hash}->{pkgpart}.'_'.$svc_broadband->{Hash}->{speed_down}.'_'.$svc_broadband->{Hash}->{speed_up};
+
+ my $virtual_ap_opt = {
+ 'virtual_name' => $virtual_ap_name,
+ 'sector_name' => $sector_name,
+ 'virtual_uprate_limit' => $svc_broadband->{Hash}->{speed_up},
+ 'virtual_downrate_limit' => $svc_broadband->{Hash}->{speed_down},
+ };
+ my $virtual_ap = process_virtual_ap($self, $virtual_ap_opt);
+ return $self->api_error if $self->{'__saisei_error'};
+
## tie host to user add sector name as access point.
$self->api_add_host_to_user(
$user->{collection}->[0]->{name},
$rateplan->{collection}->[0]->{name},
$svc_broadband->{Hash}->{ip_addr},
- $accesspoint->{collection}->[0]->{name},
+ $virtual_ap->{collection}->[0]->{name},
) unless $self->{'__saisei_error'};
}
@@ -215,8 +231,8 @@ sub _export_insert {
sub _export_replace {
my ($self, $svc_broadband) = @_;
- $self->_export_insert($svc_broadband);
- return '';
+ my $error = $self->_export_insert($svc_broadband);
+ return $error;
}
sub _export_delete {
@@ -804,6 +820,44 @@ sub process_sector {
return $accesspoint;
}
+sub process_virtual_ap {
+ my ($self, $opt) = @_;
+
+ my $existing_virtual_ap;
+ my $virtual_name = $opt->{virtual_name};
+
+ #check if sector has been set up as an access point.
+ $existing_virtual_ap = $self->api_get_accesspoint($virtual_name);
+
+ # modify the existing virtual accesspoint if changing it. this should never happen
+ $self->api_modify_existing_accesspoint (
+ $virtual_name,
+ $opt->{sector_name},
+ $opt->{virtual_uprate_limit},
+ $opt->{virtual_downrate_limit},
+ ) if $existing_virtual_ap && $opt->{modify_existing};
+
+ #if virtual ap does not exist as an access point create it.
+ $self->api_create_accesspoint(
+ $virtual_name,
+ $opt->{virtual_uprate_limit},
+ $opt->{virtual_downrate_limit},
+ ) unless $existing_virtual_ap;
+
+my $update_sector;
+if ($existing_virtual_ap && ($existing_virtual_ap->{collection}->[0]->{uplink}->{link}->{name} ne $opt->{sector_name})) {
+ $update_sector = 1;
+}
+
+ # Attach newly created virtual ap to tower sector ap or if sector has changed.
+ $self->api_modify_accesspoint($virtual_name, $opt->{sector_name}) unless ($self->{'__saisei_error'} || ($existing_virtual_ap && !$update_sector));
+
+ # set access point to existing one or newly created one.
+ my $accesspoint = $existing_virtual_ap ? $existing_virtual_ap : $self->api_get_accesspoint($virtual_name);
+
+ return $accesspoint;
+}
+
sub export_provisioned_services {
my $job = shift;
my $param = shift;