summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rwxr-xr-xbin/23diff2
-rwxr-xr-xbin/cdr-netsapiens.import1
-rwxr-xr-xbin/cust_main-bulk_change54
-rwxr-xr-xbin/fs-migrate-supplemental151
-rwxr-xr-xbin/megapop.pl114
5 files changed, 310 insertions, 12 deletions
diff --git a/bin/23diff b/bin/23diff
index d38c84834..1dc1659d2 100755
--- a/bin/23diff
+++ b/bin/23diff
@@ -7,7 +7,7 @@ $dir =~ s/freeside(\/?)/freeside2.3$1/;
warn $dir;
#$cmd = "diff -u $file $dir/$file";
-$cmd = "diff -u $dir/$file $file";
+$cmd = "diff -ubBw $dir/$file $file";
print "$cmd\n";
system($cmd);
diff --git a/bin/cdr-netsapiens.import b/bin/cdr-netsapiens.import
index 8aa4ac0b7..1cce461e2 100755
--- a/bin/cdr-netsapiens.import
+++ b/bin/cdr-netsapiens.import
@@ -37,6 +37,7 @@ do {
my $ns = $part_export->ns_command( 'GET', '/cdr/',
'time_release' => "$time_release,",
'_sort' => '+time_release',
+ '_limit' => '500',
);
#loop over them, double check duplicates, insert the rest
diff --git a/bin/cust_main-bulk_change b/bin/cust_main-bulk_change
index fdf53d999..32a6d7bd6 100755
--- a/bin/cust_main-bulk_change
+++ b/bin/cust_main-bulk_change
@@ -1,13 +1,15 @@
#!/usr/bin/perl
use strict;
-use vars qw( $opt_p );
+use vars qw( $opt_a $opt_p $opt_t $opt_k );
use Getopt::Std;
use FS::UID qw(adminsuidsetup);
-use FS::Record qw(qsearchs);
+use FS::Record qw(qsearch qsearchs);
use FS::cust_main;
+use FS::cust_tag;
+use FS::cust_pkg;
-getopts('p:');
+getopts('a:p:t:k:');
my $user = shift or &usage;
adminsuidsetup $user;
@@ -31,17 +33,41 @@ while (<STDIN>) {
next;
}
- if ( $opt_p ) {
- $cust_main->payby($opt_p);
+ my %cust_tag = ( custnum=>$custnum, tagnum=>$opt_t );
+ if ( $opt_t && ! qsearchs('cust_tag', \%cust_tag) ) {
+ my $cust_tag = new FS::cust_tag \%cust_tag;
+ my $error = $cust_tag->insert;
+ die "$error\n" if $error;
}
- my $error = $cust_main->replace;
- die "$error\n" if $error;
+ if ( $opt_p || $opt_a ) {
+ $cust_main->agentnum($opt_a) if $opt_a;
+ $cust_main->payby($opt_p) if $opt_p;
+
+ my $error = $cust_main->replace;
+ die "$error\n" if $error;
+ }
+
+ if ( $opt_k ) {
+ foreach my $k (split(/\s*,\s*/, $opt_k)) {
+ my($old, $new) = split(/\s*:\s*/, $k);
+ foreach my $cust_pkg ( qsearch('cust_pkg', {
+ 'custnum' => $cust_main->custnum,
+ 'pkgpart' => $old,
+ })
+ )
+ {
+ $cust_pkg->pkgpart($new);
+ my $error = $cust_pkg->replace;
+ die "$error\n" if $error;
+ }
+ }
+ }
}
sub usage {
- die "usage: cust_main-bulk_change -p NEW_PAYBY employee_username <custnums.txt\n";
+ die "usage: cust_main-bulk_change [ -a agentnum ] [ -p NEW_PAYBY ] [ -t tagnum ] [ -k old_pkgpart:new_pkgpart,... ] employee_username <custnums.txt\n";
}
=head1 NAME
@@ -50,13 +76,19 @@ cust_main-bulk_change
=head1 SYNOPSIS
- cust_main-bulk_change -p NEW_PAYBY username <custnums.txt
+ cust_main-bulk_change [ -a agentnum ] [ -p NEW_PAYBY ] [ -t tagnum ] [ -k old_pkgpart:new_pkgpart,... ] username <custnums.txt
=head1 DESCRIPTION
-Command-line tool to change the payby field for a group of customers.
+Command-line tool to make bulk changes to a group of customers.
+
+-a: new agentnum
+
+-p: new payby, for example, I<CARD> or I<DCRD>
+
+-t: tagnum to add if not present
--p: new payby, for example, I<CARD> or I<DCRD>.
+-k: old_pkgpart:new_pkgpart, for example, I<5:4>. Multiple entries can be comma-separated.
user: Employee username
diff --git a/bin/fs-migrate-supplemental b/bin/fs-migrate-supplemental
new file mode 100755
index 000000000..dbef95fc1
--- /dev/null
+++ b/bin/fs-migrate-supplemental
@@ -0,0 +1,151 @@
+#!/usr/bin/perl
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch qsearchs);
+use FS::cust_pkg;
+use FS::part_pkg;
+
+my $user = shift or die &usage;
+my @pkgparts = @ARGV or die &usage;
+my $dbh = adminsuidsetup $user;
+
+$FS::UID::AutoCommit = 0;
+
+my %stats = (
+ mainpkgs => 0,
+ created => 0,
+ linked => 0,
+ errors => 0,
+);
+
+my %pkg_freq; # cache
+foreach my $pkgpart (@pkgparts) {
+ my $part_pkg = FS::part_pkg->by_key($pkgpart)
+ or die "pkgpart $pkgpart not found.\n";
+ $pkg_freq{$pkgpart} = $part_pkg->freq;
+ my @links = $part_pkg->supp_part_pkg_link
+ or die "pkgpart $pkgpart has no supplemental packages.\n";
+ CUST_PKG: foreach my $cust_pkg (
+ qsearch('cust_pkg', {
+ 'pkgpart' => $pkgpart,
+ 'cancel' => '',
+ })
+ ) {
+ my $cust_main = $cust_pkg->cust_main;
+ my @existing = $cust_pkg->supplemental_pkgs;
+ my @active = grep { !$_->main_pkgnum } $cust_main->ncancelled_pkgs;
+ LINK: foreach my $link (@links) {
+ # yeah, it's expensive
+ # see if there's an existing package with this link identity
+ foreach (@existing) {
+ if ($_->pkglinknum == $link->pkglinknum) {
+ next LINK;
+ }
+ }
+ # no? then is there one with this pkgpart?
+ my $i = 0;
+ foreach (@active) {
+ if ( $_->pkgpart == $link->dst_pkgpart ) {
+ set_link($cust_pkg, $link, $_);
+ splice(@active, $i, 1); # delete it so we don't reuse it
+ next LINK;
+ }
+ }
+ # no? then create one
+ create_linked($cust_pkg, $link);
+ } #foreach $link
+ $stats{mainpkgs}++;
+ } #foreach $cust_pkg
+} #foreach $pkgpart
+
+print "
+Main packages: $stats{mainpkgs}
+Supplemental packages linked: $stats{linked}
+Supplemental packages ordered: $stats{created}
+Errors: $stats{errors}
+";
+
+$dbh->commit or die $dbh->errstr;
+
+sub set_link {
+ my ($main_pkg, $part_pkg_link, $supp_pkg) = @_;
+ my $task = "linking package ".$supp_pkg->pkgnum.
+ " to package ".$main_pkg->pkgnum;
+ $supp_pkg->set('main_pkgnum', $main_pkg->pkgnum);
+ $supp_pkg->set('pkglinknum', $part_pkg_link->pkglinknum);
+ # Set the next bill date of the supplemental package to the nearest one in
+ # the future that lines up with the main package. If the main package
+ # hasn't started billing yet, use its future start date.
+ my $new_bill = $main_pkg->get('bill') || $main_pkg->get('start_date');
+ if ( $new_bill ) {
+ my $old_bill = $supp_pkg->get('bill');
+ my $diff = $new_bill - $old_bill;
+ my $main_freq = $pkg_freq{$main_pkg->pkgpart};
+ my $prev_bill = 0;
+ while ($diff < 0) {
+ # this will exit once $new_bill has overtaken the existing bill date.
+ # if there is no existing bill date, then this will exit right away
+ # and set bill to the bill date of the main package, which is correct.
+ $prev_bill = $new_bill;
+ $new_bill = FS::part_pkg->add_freq($new_bill, $main_freq);
+ $diff = $new_bill - $old_bill;
+ }
+ # then, of $new_bill and $prev_bill, pick the one that's closer to $old_bill
+ if ( $prev_bill > 0 and
+ $new_bill - $old_bill > $old_bill - $prev_bill ) {
+ $supp_pkg->set('bill', $prev_bill);
+ } else {
+ $supp_pkg->set('bill', $new_bill);
+ }
+ } else {
+ # otherwise the main package hasn't been billed yet and has no
+ # start date, so we can't sync the supplemental to it yet.
+ # but we can still link them.
+ warn "$task: main package has no next bill date.\n";
+ }
+ my $error = $supp_pkg->replace;
+ if ( $error ) {
+ warn "$task:\n $error\n";
+ $stats{errors}++;
+ } else {
+ $stats{linked}++;
+ }
+ return;
+}
+
+sub create_linked {
+ my ($main_pkg, $part_pkg_link) = @_;
+ my $task = "creating pkgpart ".$part_pkg_link->dst_pkgpart.
+ " supplemental to package ".$main_pkg->pkgnum;
+ my $supp_pkg = FS::cust_pkg->new({
+ 'pkgpart' => $part_pkg_link->dst_pkgpart,
+ 'pkglinknum' => $part_pkg_link->pkglinknum,
+ 'custnum' => $main_pkg->custnum,
+ 'main_pkgnum' => $main_pkg->pkgnum,
+ 'locationnum' => $main_pkg->locationnum,
+ 'start_date' => $main_pkg->start_date,
+ 'order_date' => $main_pkg->order_date,
+ 'expire' => $main_pkg->expire,
+ 'adjourn' => $main_pkg->adjourn,
+ 'contract_end' => $main_pkg->contract_end,
+ 'susp' => $main_pkg->susp,
+ 'bill' => $main_pkg->bill,
+ 'refnum' => $main_pkg->refnum,
+ 'discountnum' => $main_pkg->discountnum,
+ 'waive_setup' => $main_pkg->waive_setup,
+ });
+ my $error = $supp_pkg->insert;
+ if ( $error ) {
+ warn "$task:\n $error\n";
+ $stats{errors}++;
+ } else {
+ $stats{created}++;
+ }
+ return;
+}
+
+sub usage {
+ die "Usage:\n fs-migrate-supplemental user main_pkgpart\n";
+}
+
diff --git a/bin/megapop.pl b/bin/megapop.pl
new file mode 100755
index 000000000..e2930fb55
--- /dev/null
+++ b/bin/megapop.pl
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -Tw
+#
+# this will break when megapop changes the URL or format of their listing page.
+# that's stupid. perhaps they can provide a machine-readable listing?
+
+use strict;
+use LWP::UserAgent;
+use FS::UID qw(adminsuidsetup);
+use FS::svc_acct_pop;
+
+my $url = "http://www.megapop.com/location.htm";
+
+my $user = shift or die &usage;
+adminsuidsetup($user);
+
+my %state2usps = &state2usps;
+$state2usps{'WASHINGTON STATE'} = 'WA'; #megapop's on crack
+$state2usps{'CANADA'} = 'CANADA'; #freeside's on crack
+
+my $ua = new LWP::UserAgent;
+my $request = new HTTP::Request('GET', $url);
+my $response = $ua->request($request);
+die $response->error_as_HTML unless $response->is_success;
+my $line;
+my $usps = '';
+foreach $line ( split("\n", $response->content) ) {
+ if ( $line =~ /\W(\w[\w\s]*\w)\s+LOCATIONS/i ) {
+ $usps = $state2usps{uc($1)}
+ or warn "warning: unknown state $1\n";
+ } elsif ( $line =~ /(\d{3})\-(\d{3})\-(\d{4})\s+(\w[\w\s]*\w)/ ) {
+ print "$1 $2 $3 $4 $usps\n";
+ my $svc_acct_pop = new FS::svc_acct_pop ( {
+ 'city' => $4,
+ 'state' => $usps,
+ 'ac' => $1,
+ 'exch' => $2,
+ } );
+ my $error = $svc_acct_pop->insert;
+ die $error if $error;
+ }
+}
+
+sub usage {
+ die "Usage:\n $0 user\n";
+}
+
+sub state2usps{ (
+ 'ALABAMA' => 'AL',
+ 'ALASKA' => 'AK',
+ 'AMERICAN SAMOA' => 'AS',
+ 'ARIZONA' => 'AZ',
+ 'ARKANSAS' => 'AR',
+ 'CALIFORNIA' => 'CA',
+ 'COLORADO' => 'CO',
+ 'CONNECTICUT' => 'CT',
+ 'DELAWARE' => 'DE',
+ 'DISTRICT OF COLUMBIA' => 'DC',
+ 'FEDERATED STATES OF MICRONESIA' => 'FM',
+ 'FLORIDA' => 'FL',
+ 'GEORGIA' => 'GA',
+ 'GUAM' => 'GU',
+ 'HAWAII' => 'HI',
+ 'IDAHO' => 'ID',
+ 'ILLINOIS' => 'IL',
+ 'INDIANA' => 'IN',
+ 'IOWA' => 'IA',
+ 'KANSAS' => 'KS',
+ 'KENTUCKY' => 'KY',
+ 'LOUISIANA' => 'LA',
+ 'MAINE' => 'ME',
+ 'MARSHALL ISLANDS' => 'MH',
+ 'MARYLAND' => 'MD',
+ 'MASSACHUSETTS' => 'MA',
+ 'MICHIGAN' => 'MI',
+ 'MINNESOTA' => 'MN',
+ 'MISSISSIPPI' => 'MS',
+ 'MISSOURI' => 'MO',
+ 'MONTANA' => 'MT',
+ 'NEBRASKA' => 'NE',
+ 'NEVADA' => 'NV',
+ 'NEW HAMPSHIRE' => 'NH',
+ 'NEW JERSEY' => 'NJ',
+ 'NEW MEXICO' => 'NM',
+ 'NEW YORK' => 'NY',
+ 'NORTH CAROLINA' => 'NC',
+ 'NORTH DAKOTA' => 'ND',
+ 'NORTHERN MARIANA ISLANDS' => 'MP',
+ 'OHIO' => 'OH',
+ 'OKLAHOMA' => 'OK',
+ 'OREGON' => 'OR',
+ 'PALAU' => 'PW',
+ 'PENNSYLVANIA' => 'PA',
+ 'PUERTO RICO' => 'PR',
+ 'RHODE ISLAND' => 'RI',
+ 'SOUTH CAROLINA' => 'SC',
+ 'SOUTH DAKOTA' => 'SD',
+ 'TENNESSEE' => 'TN',
+ 'TEXAS' => 'TX',
+ 'UTAH' => 'UT',
+ 'VERMONT' => 'VT',
+ 'VIRGIN ISLANDS' => 'VI',
+ 'VIRGINIA' => 'VA',
+ 'WASHINGTON' => 'WA',
+ 'WEST VIRGINIA' => 'WV',
+ 'WISCONSIN' => 'WI',
+ 'WYOMING' => 'WY',
+ 'ARMED FORCES AFRICA' => 'AE',
+ 'ARMED FORCES AMERICAS' => 'AA',
+ 'ARMED FORCES CANADA' => 'AE',
+ 'ARMED FORCES EUROPE' => 'AE',
+ 'ARMED FORCES MIDDLE EAST' => 'AE',
+ 'ARMED FORCES PACIFIC' => 'AP',
+) }
+